github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/integration_test/integration_test.go (about)

     1  // Copyright 2016 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package integration_test
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"os/exec"
    22  	"path"
    23  	"regexp"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/nmiyake/pkg/dirs"
    28  	"github.com/nmiyake/pkg/gofiles"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"github.com/palantir/godel/apps/distgo/pkg/git"
    33  	"github.com/palantir/godel/apps/distgo/pkg/git/gittest"
    34  	"github.com/palantir/godel/pkg/products"
    35  )
    36  
    37  var (
    38  	gödelTGZ    string
    39  	testRootDir string
    40  	version     string
    41  )
    42  
    43  func TestMain(m *testing.M) {
    44  	os.Exit(runTestMain(m))
    45  }
    46  
    47  func runTestMain(m *testing.M) int {
    48  	wd, err := os.Getwd()
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  	gödelProjectDir := path.Join(wd, "..")
    53  	version, err = git.ProjectVersion(gödelProjectDir)
    54  	if err != nil {
    55  		panic(fmt.Sprintf("Failed to get version from directory %s: %v", gödelProjectDir, err))
    56  	}
    57  
    58  	gödelTGZ, err = products.Dist("godel")
    59  	if err != nil {
    60  		panic(fmt.Sprintf("Failed create distribution: %v", err))
    61  	}
    62  
    63  	var cleanup func()
    64  	testRootDir, cleanup, err = dirs.TempDir(wd, "")
    65  	defer cleanup()
    66  	if err != nil {
    67  		panic(fmt.Sprintf("Failed to create temporary directory in %s: %v", wd, err))
    68  	}
    69  
    70  	return m.Run()
    71  }
    72  
    73  func TestVersion(t *testing.T) {
    74  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
    75  
    76  	output := execCommand(t, testProjectDir, "./godelw", "--version")
    77  	assert.Equal(t, fmt.Sprintf("godel version %v\n", version), string(output))
    78  }
    79  
    80  func TestProjectVersion(t *testing.T) {
    81  	tmpDir, cleanup, err := dirs.TempDir("", "")
    82  	defer cleanup()
    83  	require.NoError(t, err)
    84  
    85  	gittest.InitGitDir(t, tmpDir)
    86  	gittest.CreateGitTag(t, tmpDir, "testTag")
    87  	err = ioutil.WriteFile(path.Join(tmpDir, "random.txt"), []byte(""), 0644)
    88  	require.NoError(t, err)
    89  
    90  	testProjectDir := setUpGödelTestAndDownload(t, tmpDir, gödelTGZ, version)
    91  	output := execCommand(t, testProjectDir, "./godelw", "project-version")
    92  	assert.Equal(t, "testTag.dirty\n", string(output))
    93  }
    94  
    95  func TestGitHooksSuccess(t *testing.T) {
    96  	// create project directory in temporary location so primary project's repository is not modified by test
    97  	tmp, cleanup, err := dirs.TempDir("", "")
    98  	defer cleanup()
    99  	require.NoError(t, err)
   100  
   101  	testProjectDir := setUpGödelTestAndDownload(t, tmp, gödelTGZ, version)
   102  
   103  	// initialize git repository
   104  	gittest.InitGitDir(t, testProjectDir)
   105  
   106  	// install commit hooks
   107  	execCommand(t, testProjectDir, "./godelw", "git-hooks")
   108  
   109  	// committing Go file that is properly formatted works
   110  	formatted := `package main
   111  
   112  func main() {
   113  }
   114  `
   115  	err = ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(formatted), 0644)
   116  	require.NoError(t, err)
   117  	execCommand(t, testProjectDir, "git", "add", ".")
   118  	execCommand(t, testProjectDir, "git", "commit", "--author=testAuthor <test@author.com>", "-m", "Second commit")
   119  }
   120  
   121  func TestGitHooksFail(t *testing.T) {
   122  	// create project directory in temporary location so primary project's repository is not modified by test
   123  	tmp, cleanup, err := dirs.TempDir("", "")
   124  	defer cleanup()
   125  	require.NoError(t, err)
   126  
   127  	testProjectDir := setUpGödelTestAndDownload(t, tmp, gödelTGZ, version)
   128  
   129  	// initialize git repository
   130  	gittest.InitGitDir(t, testProjectDir)
   131  
   132  	// install commit hooks
   133  	execCommand(t, testProjectDir, "./godelw", "git-hooks")
   134  
   135  	// committing Go file that is not properly formatted causes error
   136  	notFormatted := `package main
   137  import "fmt"
   138  
   139  func Foo() {
   140  fmt.Println("foo")
   141  }`
   142  	err = ioutil.WriteFile(path.Join(testProjectDir, "helper.go"), []byte(notFormatted), 0644)
   143  	require.NoError(t, err)
   144  	execCommand(t, testProjectDir, "git", "add", ".")
   145  
   146  	cmd := exec.Command("git", "commit", "--author=testAuthor <test@author.com>", "-m", "Second commit")
   147  	cmd.Dir = testProjectDir
   148  	output, err := cmd.CombinedOutput()
   149  	assert.Error(t, err, "exit status 1")
   150  	assert.Regexp(t, `(?s)^Unformatted files exist -- run ./godelw format to format these files:\n  .+/helper.go\n$`, string(output))
   151  }
   152  
   153  func TestFormat(t *testing.T) {
   154  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   155  
   156  	src := `package main
   157  		import "fmt"
   158  
   159  	func main() {
   160  	fmt.Println("hello, world!")
   161  	}`
   162  
   163  	formattedSrc := `package main
   164  
   165  import (
   166  	"fmt"
   167  )
   168  
   169  func main() {
   170  	fmt.Println("hello, world!")
   171  }
   172  `
   173  	err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644)
   174  	require.NoError(t, err)
   175  
   176  	execCommand(t, testProjectDir, "./godelw", "format")
   177  
   178  	content, err := ioutil.ReadFile(path.Join(testProjectDir, "main.go"))
   179  	require.NoError(t, err)
   180  	assert.Equal(t, formattedSrc, string(content))
   181  }
   182  
   183  func TestGenerate(t *testing.T) {
   184  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   185  
   186  	const generateYML = `
   187  generators:
   188    foo:
   189      go-generate-dir: gen
   190      gen-paths:
   191        paths:
   192          - "gen/output.txt"
   193  `
   194  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "generate.yml"), []byte(generateYML), 0644)
   195  	require.NoError(t, err)
   196  
   197  	specs := []gofiles.GoFileSpec{
   198  		{
   199  			RelPath: "gen/testbar.go",
   200  			Src: `package testbar
   201  
   202  //go:generate go run generator_main.go
   203  `,
   204  		},
   205  		{
   206  			RelPath: "gen/generator_main.go",
   207  			Src: `// +build ignore
   208  
   209  package main
   210  
   211  import (
   212  	"io/ioutil"
   213  )
   214  
   215  func main() {
   216  	if err := ioutil.WriteFile("output.txt", []byte("foo-output"), 0644); err != nil {
   217  		panic(err)
   218  	}
   219  }
   220  `,
   221  		},
   222  	}
   223  
   224  	_, err = gofiles.Write(testProjectDir, specs)
   225  	require.NoError(t, err)
   226  
   227  	execCommand(t, testProjectDir, "./godelw", "generate")
   228  
   229  	content, err := ioutil.ReadFile(path.Join(testProjectDir, "gen", "output.txt"))
   230  	require.NoError(t, err)
   231  	assert.Equal(t, "foo-output", string(content))
   232  }
   233  
   234  func TestGenerateVerify(t *testing.T) {
   235  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   236  
   237  	const generateYML = `
   238  generators:
   239    foo:
   240      go-generate-dir: gen
   241      gen-paths:
   242        paths:
   243          - "gen/output.txt"
   244  `
   245  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "generate.yml"), []byte(generateYML), 0644)
   246  	require.NoError(t, err)
   247  
   248  	specs := []gofiles.GoFileSpec{
   249  		{
   250  			RelPath: "gen/testbar.go",
   251  			Src: `package testbar
   252  
   253  //go:generate go run generator_main.go
   254  `,
   255  		},
   256  		{
   257  			RelPath: "gen/generator_main.go",
   258  			Src: `// +build ignore
   259  
   260  package main
   261  
   262  import (
   263  	"io/ioutil"
   264  )
   265  
   266  func main() {
   267  	if err := ioutil.WriteFile("output.txt", []byte("foo-output"), 0644); err != nil {
   268  		panic(err)
   269  	}
   270  }
   271  `,
   272  		},
   273  	}
   274  
   275  	_, err = gofiles.Write(testProjectDir, specs)
   276  	require.NoError(t, err)
   277  
   278  	err = ioutil.WriteFile(path.Join(testProjectDir, "gen", "output.txt"), []byte("original"), 0644)
   279  	require.NoError(t, err)
   280  
   281  	cmd := exec.Command("./godelw", "generate", "--verify")
   282  	cmd.Dir = testProjectDir
   283  	output, err := cmd.CombinedOutput()
   284  	require.Error(t, err)
   285  
   286  	want := "Generators produced output that differed from what already exists: [foo]\n  foo:\n    gen/output.txt: previously had checksum 0682c5f2076f099c34cfdd15a9e063849ed437a49677e6fcc5b4198c76575be5, now has checksum 380a300b764683667309818ff127a401c6ea6ab1959f386fe0f05505d660ba37\n"
   287  	assert.Equal(t, want, string(output))
   288  }
   289  
   290  func TestImports(t *testing.T) {
   291  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   292  
   293  	const importsYML = `root-dirs:
   294    - pkg`
   295  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "imports.yml"), []byte(importsYML), 0644)
   296  	require.NoError(t, err)
   297  
   298  	specs := []gofiles.GoFileSpec{
   299  		{
   300  			RelPath: "pkg/foo/foo.go",
   301  			Src:     `package foo; import _ "{{index . "bar.go"}}";`,
   302  		},
   303  		{
   304  			RelPath: "bar.go",
   305  			Src:     "package bar",
   306  		},
   307  	}
   308  
   309  	files, err := gofiles.Write(testProjectDir, specs)
   310  	require.NoError(t, err)
   311  
   312  	want := fmt.Sprintf(`{
   313      "imports": [
   314          {
   315              "path": "%s",
   316              "numGoFiles": 1,
   317              "numImportedGoFiles": 0,
   318              "importedFrom": [
   319                  "%s"
   320              ]
   321          }
   322      ],
   323      "mainOnlyImports": [],
   324      "testOnlyImports": []
   325  }`, files["bar.go"].ImportPath, files["pkg/foo/foo.go"].ImportPath)
   326  
   327  	execCommand(t, testProjectDir, "./godelw", "imports")
   328  
   329  	content, err := ioutil.ReadFile(path.Join(testProjectDir, "pkg", "gocd_imports.json"))
   330  	require.NoError(t, err)
   331  	assert.Equal(t, want, string(content))
   332  }
   333  
   334  func TestImportsVerify(t *testing.T) {
   335  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   336  
   337  	const importsYML = `root-dirs:
   338    - pkg`
   339  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "imports.yml"), []byte(importsYML), 0644)
   340  	require.NoError(t, err)
   341  
   342  	specs := []gofiles.GoFileSpec{
   343  		{
   344  			RelPath: "pkg/foo/foo.go",
   345  			Src:     `package foo; import _ "{{index . "bar.go"}}";`,
   346  		},
   347  		{
   348  			RelPath: "bar.go",
   349  			Src:     "package bar",
   350  		},
   351  	}
   352  
   353  	_, err = gofiles.Write(testProjectDir, specs)
   354  	require.NoError(t, err)
   355  
   356  	cmd := exec.Command("./godelw", "imports", "--verify")
   357  	cmd.Dir = testProjectDir
   358  	output, err := cmd.CombinedOutput()
   359  	require.Error(t, err)
   360  	assert.Equal(t, "gocd_imports.json out of date for 1 directory:\n\tpkg: gocd_imports.json does not exist\n", string(output))
   361  }
   362  
   363  func TestLicense(t *testing.T) {
   364  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   365  
   366  	const licenseYML = `header: |
   367    /*
   368    Copyright 2016 Palantir Technologies, Inc.
   369  
   370    Licensed under the Apache License, Version 2.0 (the "License");
   371    you may not use this file except in compliance with the License.
   372    You may obtain a copy of the License at
   373  
   374    http://www.apache.org/licenses/LICENSE-2.0
   375  
   376    Unless required by applicable law or agreed to in writing, software
   377    distributed under the License is distributed on an "AS IS" BASIS,
   378    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   379    See the License for the specific language governing permissions and
   380    limitations under the License.
   381    */
   382  `
   383  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "license.yml"), []byte(licenseYML), 0644)
   384  	require.NoError(t, err)
   385  
   386  	specs := []gofiles.GoFileSpec{
   387  		{
   388  			RelPath: "foo.go",
   389  			Src:     "package foo",
   390  		},
   391  		{
   392  			RelPath: "vendor/github.com/bar.go",
   393  			Src:     "package bar",
   394  		},
   395  	}
   396  
   397  	files, err := gofiles.Write(testProjectDir, specs)
   398  	require.NoError(t, err)
   399  
   400  	want := `/*
   401  Copyright 2016 Palantir Technologies, Inc.
   402  
   403  Licensed under the Apache License, Version 2.0 (the "License");
   404  you may not use this file except in compliance with the License.
   405  You may obtain a copy of the License at
   406  
   407  http://www.apache.org/licenses/LICENSE-2.0
   408  
   409  Unless required by applicable law or agreed to in writing, software
   410  distributed under the License is distributed on an "AS IS" BASIS,
   411  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   412  See the License for the specific language governing permissions and
   413  limitations under the License.
   414  */
   415  
   416  package foo`
   417  
   418  	execCommand(t, testProjectDir, "./godelw", "license")
   419  
   420  	content, err := ioutil.ReadFile(files["foo.go"].Path)
   421  	require.NoError(t, err)
   422  	assert.Equal(t, want, string(content))
   423  
   424  	want = `package bar`
   425  	content, err = ioutil.ReadFile(files["vendor/github.com/bar.go"].Path)
   426  	require.NoError(t, err)
   427  	assert.Equal(t, want, string(content))
   428  }
   429  
   430  func TestLicenseVerify(t *testing.T) {
   431  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   432  
   433  	const licenseYML = `header: |
   434    /*
   435    Copyright 2016 Palantir Technologies, Inc.
   436  
   437    Licensed under the Apache License, Version 2.0 (the "License");
   438    you may not use this file except in compliance with the License.
   439    You may obtain a copy of the License at
   440  
   441    http://www.apache.org/licenses/LICENSE-2.0
   442  
   443    Unless required by applicable law or agreed to in writing, software
   444    distributed under the License is distributed on an "AS IS" BASIS,
   445    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   446    See the License for the specific language governing permissions and
   447    limitations under the License.
   448    */
   449  `
   450  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "license.yml"), []byte(licenseYML), 0644)
   451  	require.NoError(t, err)
   452  
   453  	specs := []gofiles.GoFileSpec{
   454  		{
   455  			RelPath: "foo.go",
   456  			Src:     "package foo",
   457  		},
   458  		{
   459  			RelPath: "bar/bar.go",
   460  			Src: `/*
   461  Copyright 2016 Palantir Technologies, Inc.
   462  
   463  Licensed under the Apache License, Version 2.0 (the "License");
   464  you may not use this file except in compliance with the License.
   465  You may obtain a copy of the License at
   466  
   467  http://www.apache.org/licenses/LICENSE-2.0
   468  
   469  Unless required by applicable law or agreed to in writing, software
   470  distributed under the License is distributed on an "AS IS" BASIS,
   471  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   472  See the License for the specific language governing permissions and
   473  limitations under the License.
   474  */
   475  
   476  package bar`,
   477  		},
   478  		{
   479  			RelPath: "vendor/github.com/baz.go",
   480  			Src:     "package baz",
   481  		},
   482  	}
   483  
   484  	_, err = gofiles.Write(testProjectDir, specs)
   485  	require.NoError(t, err)
   486  
   487  	cmd := exec.Command("./godelw", "license", "--verify")
   488  	cmd.Dir = testProjectDir
   489  	output, err := cmd.CombinedOutput()
   490  	require.Error(t, err)
   491  	assert.Equal(t, "1 file does not have the correct license header:\n\tfoo.go\n", string(output))
   492  }
   493  
   494  func TestCheck(t *testing.T) {
   495  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   496  	src := `package main
   497  	import "fmt"
   498  
   499  	func main() {
   500  		fmt.Println("hello, world!")
   501  	}`
   502  	err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644)
   503  	require.NoError(t, err)
   504  
   505  	execCommand(t, testProjectDir, "./godelw", "check")
   506  }
   507  
   508  func TestProducts(t *testing.T) {
   509  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   510  
   511  	distYml := `
   512  products:
   513    foo:
   514      build:
   515        main-pkg: ./foo
   516    bar:
   517      build:
   518        main-pkg: ./bar
   519  `
   520  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "dist.yml"), []byte(distYml), 0644)
   521  	require.NoError(t, err)
   522  
   523  	src := `package main
   524  	import "fmt"
   525  
   526  	func main() {
   527  		fmt.Println("hello, world!")
   528  	}`
   529  	err = os.MkdirAll(path.Join(testProjectDir, "foo"), 0755)
   530  	require.NoError(t, err)
   531  	err = ioutil.WriteFile(path.Join(testProjectDir, "foo", "foo.go"), []byte(src), 0644)
   532  	require.NoError(t, err)
   533  
   534  	err = os.MkdirAll(path.Join(testProjectDir, "bar"), 0755)
   535  	require.NoError(t, err)
   536  	err = ioutil.WriteFile(path.Join(testProjectDir, "bar", "bar.go"), []byte(src), 0644)
   537  	require.NoError(t, err)
   538  
   539  	execCommand(t, testProjectDir, "./godelw", "products")
   540  }
   541  
   542  func TestArtifactsBuild(t *testing.T) {
   543  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   544  	gittest.InitGitDir(t, testProjectDir)
   545  
   546  	distYml := `
   547  products:
   548    foo:
   549      build:
   550        main-pkg: ./foo
   551        os-archs:
   552          - os: darwin
   553            arch: amd64
   554          - os: linux
   555            arch: amd64
   556    bar:
   557      build:
   558        main-pkg: ./bar
   559        os-archs:
   560          - os: windows
   561            arch: amd64
   562  `
   563  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "dist.yml"), []byte(distYml), 0644)
   564  	require.NoError(t, err)
   565  
   566  	src := `package main
   567  	import "fmt"
   568  
   569  	func main() {
   570  		fmt.Println("hello, world!")
   571  	}`
   572  	err = os.MkdirAll(path.Join(testProjectDir, "foo"), 0755)
   573  	require.NoError(t, err)
   574  	err = ioutil.WriteFile(path.Join(testProjectDir, "foo", "foo.go"), []byte(src), 0644)
   575  	require.NoError(t, err)
   576  
   577  	err = os.MkdirAll(path.Join(testProjectDir, "bar"), 0755)
   578  	require.NoError(t, err)
   579  	err = ioutil.WriteFile(path.Join(testProjectDir, "bar", "bar.go"), []byte(src), 0644)
   580  	require.NoError(t, err)
   581  
   582  	gittest.CommitAllFiles(t, testProjectDir, "Commit files")
   583  	gittest.CreateGitTag(t, testProjectDir, "0.1.0")
   584  
   585  	output := execCommand(t, testProjectDir, "./godelw", "artifacts", "build")
   586  
   587  	want := `build/0.1.0/windows-amd64/bar.exe
   588  build/0.1.0/darwin-amd64/foo
   589  build/0.1.0/linux-amd64/foo
   590  `
   591  	assert.Equal(t, want, output)
   592  }
   593  
   594  func TestArtifactsDist(t *testing.T) {
   595  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   596  	gittest.InitGitDir(t, testProjectDir)
   597  
   598  	distYml := `
   599  products:
   600    foo:
   601      build:
   602        main-pkg: ./foo
   603      dist:
   604        dist-type:
   605          type: sls
   606    bar:
   607      build:
   608        main-pkg: ./bar
   609      dist:
   610        dist-type:
   611          type: sls
   612  `
   613  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "dist.yml"), []byte(distYml), 0644)
   614  	require.NoError(t, err)
   615  
   616  	src := `package main
   617  	import "fmt"
   618  
   619  	func main() {
   620  		fmt.Println("hello, world!")
   621  	}`
   622  	err = os.MkdirAll(path.Join(testProjectDir, "foo"), 0755)
   623  	require.NoError(t, err)
   624  	err = ioutil.WriteFile(path.Join(testProjectDir, "foo", "foo.go"), []byte(src), 0644)
   625  	require.NoError(t, err)
   626  
   627  	err = os.MkdirAll(path.Join(testProjectDir, "bar"), 0755)
   628  	require.NoError(t, err)
   629  	err = ioutil.WriteFile(path.Join(testProjectDir, "bar", "bar.go"), []byte(src), 0644)
   630  	require.NoError(t, err)
   631  
   632  	gittest.CommitAllFiles(t, testProjectDir, "Commit files")
   633  	gittest.CreateGitTag(t, testProjectDir, "0.1.0")
   634  
   635  	output := execCommand(t, testProjectDir, "./godelw", "artifacts", "dist")
   636  	assert.Equal(t, "dist/bar-0.1.0.sls.tgz\ndist/foo-0.1.0.sls.tgz\n", output)
   637  }
   638  
   639  func TestRun(t *testing.T) {
   640  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   641  	gittest.InitGitDir(t, testProjectDir)
   642  
   643  	distYml := `
   644  products:
   645    foo:
   646      build:
   647        main-pkg: ./foo
   648    bar:
   649      build:
   650        main-pkg: ./bar
   651  `
   652  	err := ioutil.WriteFile(path.Join(testProjectDir, "godel", "config", "dist.yml"), []byte(distYml), 0644)
   653  	require.NoError(t, err)
   654  
   655  	fooSrc := `package main
   656  	import (
   657  		"fmt"
   658  		"os"
   659  	)
   660  
   661  	func main() {
   662  		fmt.Println("foo:", os.Args[1:])
   663  	}`
   664  	err = os.MkdirAll(path.Join(testProjectDir, "foo"), 0755)
   665  	require.NoError(t, err)
   666  	err = ioutil.WriteFile(path.Join(testProjectDir, "foo", "foo.go"), []byte(fooSrc), 0644)
   667  	require.NoError(t, err)
   668  
   669  	barSrc := `package main
   670  	import (
   671  		"fmt"
   672  	)
   673  
   674  	func main() {
   675  		fmt.Println("bar")
   676  	}`
   677  	err = os.MkdirAll(path.Join(testProjectDir, "bar"), 0755)
   678  	require.NoError(t, err)
   679  	err = ioutil.WriteFile(path.Join(testProjectDir, "bar", "bar.go"), []byte(barSrc), 0644)
   680  	require.NoError(t, err)
   681  
   682  	gittest.CommitAllFiles(t, testProjectDir, "Commit files")
   683  	gittest.CreateGitTag(t, testProjectDir, "0.1.0")
   684  
   685  	output := execCommand(t, testProjectDir, "./godelw", "run", "--product", "foo", "arg1", "arg2")
   686  	output = output[strings.Index(output, "\n")+1:]
   687  	assert.Equal(t, "foo: [arg1 arg2]\n", output)
   688  }
   689  
   690  func TestTest(t *testing.T) {
   691  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   692  	src := `package foo_test
   693  	import "testing"
   694  
   695  	func TestFoo(t *testing.T) {}`
   696  	err := ioutil.WriteFile(path.Join(testProjectDir, "foo_test.go"), []byte(src), 0644)
   697  	require.NoError(t, err)
   698  
   699  	execCommand(t, testProjectDir, "./godelw", "test")
   700  }
   701  
   702  // Run "../godelw check" and ensure that it works (command supports being invoked from subdirectory). The action should
   703  // execute with the subdirectory as the working directory.
   704  func TestCheckFromNestedDirectory(t *testing.T) {
   705  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   706  
   707  	// write invalid Go file to root directory of project
   708  	badSrc := `badContentForGoFile`
   709  	err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(badSrc), 0644)
   710  	require.NoError(t, err)
   711  
   712  	// write valid Go file to child directory
   713  	childDir := path.Join(testProjectDir, "childDir")
   714  	err = os.MkdirAll(childDir, 0755)
   715  	require.NoError(t, err)
   716  	src := `package main
   717  	import "fmt"
   718  
   719  	func main() {
   720  		fmt.Println("hello, world!")
   721  	}`
   722  	err = ioutil.WriteFile(path.Join(childDir, "main.go"), []byte(src), 0644)
   723  	require.NoError(t, err)
   724  
   725  	execCommand(t, childDir, "../godelw", "check")
   726  }
   727  
   728  // Run "../godelw build" and ensure that it works (command supports being invoked from sub-directory). The build action
   729  // should execute with the root project directory as the working directory. Verifies #235.
   730  func TestBuildFromNestedDirectory(t *testing.T) {
   731  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   732  	src := `package main
   733  	import "fmt"
   734  
   735  	func main() {
   736  		fmt.Println("hello, world!")
   737  	}`
   738  	err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644)
   739  	require.NoError(t, err)
   740  
   741  	childDir := path.Join(testProjectDir, "childDir")
   742  	err = os.MkdirAll(childDir, 0755)
   743  	require.NoError(t, err)
   744  
   745  	execCommand(t, childDir, "../godelw", "build")
   746  
   747  	info, err := os.Stat(path.Join(testProjectDir, "build"))
   748  	require.NoError(t, err)
   749  	assert.True(t, info.IsDir())
   750  }
   751  
   752  // Run "./godelw publish" and verify that it prints a help message and exits with a non-0 exit code. Verifies #243.
   753  func TestPublishWithNoAction(t *testing.T) {
   754  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   755  	src := `package main
   756  	import "fmt"
   757  
   758  	func main() {
   759  		fmt.Println("hello, world!")
   760  	}`
   761  	err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644)
   762  	require.NoError(t, err)
   763  
   764  	cmd := exec.Command("./godelw", "publish")
   765  	cmd.Dir = testProjectDir
   766  	output, err := cmd.CombinedOutput()
   767  	require.Error(t, err)
   768  	assert.Regexp(t, regexp.MustCompile(`(?s)NAME:.+publish - Publish product distributions.+USAGE:.+godel publish.+SUBCOMMANDS:.+FLAGS:.+`), string(output))
   769  }
   770  
   771  func TestDebugFlagPrintsStackTrace(t *testing.T) {
   772  	testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version)
   773  
   774  	cmd := exec.Command("./godelw", "install", "foo")
   775  	cmd.Dir = testProjectDir
   776  	output, err := cmd.CombinedOutput()
   777  	require.Error(t, err)
   778  	assert.Regexp(t, `^Failed to install from foo into .+: foo does not exist\n$`, string(output))
   779  
   780  	cmd = exec.Command("./godelw", "--debug", "install", "foo")
   781  	cmd.Dir = testProjectDir
   782  	output, err = cmd.CombinedOutput()
   783  	require.Error(t, err)
   784  	assert.Regexp(t, `(?s)^foo does not exist.+cmd/godel.localPkg.getPkg.+Failed to install from foo into .+`, string(output))
   785  }
   786  
   787  func execCommand(t *testing.T, dir, cmdName string, args ...string) string {
   788  	cmd := exec.Command(cmdName, args...)
   789  	cmd.Dir = dir
   790  	output, err := cmd.CombinedOutput()
   791  	require.NoError(t, err, "Command %v failed. Output:\n%v", cmd.Args, string(output))
   792  	return string(output)
   793  }