github.com/jonathanlloyd/goreleaser@v0.91.1/internal/builders/golang/build_test.go (about)

     1  package golang
     2  
     3  import (
     4  	"io/ioutil"
     5  	"path/filepath"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/goreleaser/goreleaser/internal/artifact"
    11  	"github.com/goreleaser/goreleaser/internal/testlib"
    12  	"github.com/goreleaser/goreleaser/internal/tmpl"
    13  	api "github.com/goreleaser/goreleaser/pkg/build"
    14  	"github.com/goreleaser/goreleaser/pkg/config"
    15  	"github.com/goreleaser/goreleaser/pkg/context"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  var runtimeTarget = runtime.GOOS + "_" + runtime.GOARCH
    20  
    21  func TestWithDefaults(t *testing.T) {
    22  	for name, testcase := range map[string]struct {
    23  		build   config.Build
    24  		targets []string
    25  	}{
    26  		"full": {
    27  			build: config.Build{
    28  				Binary: "foo",
    29  				Goos: []string{
    30  					"linux",
    31  					"windows",
    32  					"darwin",
    33  				},
    34  				Goarch: []string{
    35  					"amd64",
    36  					"arm",
    37  				},
    38  				Goarm: []string{
    39  					"6",
    40  				},
    41  			},
    42  			targets: []string{
    43  				"linux_amd64",
    44  				"darwin_amd64",
    45  				"windows_amd64",
    46  				"linux_arm_6",
    47  			},
    48  		},
    49  		"empty": {
    50  			build: config.Build{
    51  				Binary: "foo",
    52  			},
    53  			targets: []string{
    54  				"linux_amd64",
    55  				"linux_386",
    56  				"darwin_amd64",
    57  				"darwin_386",
    58  			},
    59  		},
    60  	} {
    61  		t.Run(name, func(tt *testing.T) {
    62  			var config = config.Project{
    63  				Builds: []config.Build{
    64  					testcase.build,
    65  				},
    66  			}
    67  			var ctx = context.New(config)
    68  			ctx.Git.CurrentTag = "5.6.7"
    69  			var build = Default.WithDefaults(ctx.Config.Builds[0])
    70  			assert.ElementsMatch(t, build.Targets, testcase.targets)
    71  		})
    72  	}
    73  }
    74  
    75  func TestBuild(t *testing.T) {
    76  	folder, back := testlib.Mktmp(t)
    77  	defer back()
    78  	writeGoodMain(t, folder)
    79  	var config = config.Project{
    80  		Builds: []config.Build{
    81  			{
    82  				Binary: "foo",
    83  				Targets: []string{
    84  					"linux_amd64",
    85  					"darwin_amd64",
    86  					"windows_amd64",
    87  					"linux_arm_6",
    88  				},
    89  				Asmflags: []string{".=", "all="},
    90  				Gcflags:  []string{"all="},
    91  			},
    92  		},
    93  	}
    94  	var ctx = context.New(config)
    95  	ctx.Git.CurrentTag = "5.6.7"
    96  	var build = ctx.Config.Builds[0]
    97  	for _, target := range build.Targets {
    98  		var ext string
    99  		if strings.HasPrefix(target, "windows") {
   100  			ext = ".exe"
   101  		}
   102  		var err = Default.Build(ctx, build, api.Options{
   103  			Target: target,
   104  			Name:   build.Binary,
   105  			Path:   filepath.Join(folder, "dist", target, build.Binary),
   106  			Ext:    ext,
   107  		})
   108  		assert.NoError(t, err)
   109  	}
   110  	assert.ElementsMatch(t, ctx.Artifacts.List(), []artifact.Artifact{
   111  		{
   112  			Name:   "foo",
   113  			Path:   filepath.Join(folder, "dist", "linux_amd64", "foo"),
   114  			Goos:   "linux",
   115  			Goarch: "amd64",
   116  			Type:   artifact.Binary,
   117  			Extra: map[string]string{
   118  				"Ext":    "",
   119  				"Binary": "foo",
   120  			},
   121  		},
   122  		{
   123  			Name:   "foo",
   124  			Path:   filepath.Join(folder, "dist", "darwin_amd64", "foo"),
   125  			Goos:   "darwin",
   126  			Goarch: "amd64",
   127  			Type:   artifact.Binary,
   128  			Extra: map[string]string{
   129  				"Ext":    "",
   130  				"Binary": "foo",
   131  			},
   132  		},
   133  		{
   134  			Name:   "foo",
   135  			Path:   filepath.Join(folder, "dist", "linux_arm_6", "foo"),
   136  			Goos:   "linux",
   137  			Goarch: "arm",
   138  			Goarm:  "6",
   139  			Type:   artifact.Binary,
   140  			Extra: map[string]string{
   141  				"Ext":    "",
   142  				"Binary": "foo",
   143  			},
   144  		},
   145  		{
   146  			Name:   "foo",
   147  			Path:   filepath.Join(folder, "dist", "windows_amd64", "foo"),
   148  			Goos:   "windows",
   149  			Goarch: "amd64",
   150  			Type:   artifact.Binary,
   151  			Extra: map[string]string{
   152  				"Ext":    ".exe",
   153  				"Binary": "foo",
   154  			},
   155  		},
   156  	})
   157  }
   158  
   159  func TestBuildFailed(t *testing.T) {
   160  	folder, back := testlib.Mktmp(t)
   161  	defer back()
   162  	writeGoodMain(t, folder)
   163  	var config = config.Project{
   164  		Builds: []config.Build{
   165  			{
   166  				Flags: []string{"-flag-that-dont-exists-to-force-failure"},
   167  				Targets: []string{
   168  					runtimeTarget,
   169  				},
   170  			},
   171  		},
   172  	}
   173  	var ctx = context.New(config)
   174  	ctx.Git.CurrentTag = "5.6.7"
   175  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   176  		Target: "darwin_amd64",
   177  	})
   178  	assertContainsError(t, err, `flag provided but not defined: -flag-that-dont-exists-to-force-failure`)
   179  	assert.Empty(t, ctx.Artifacts.List())
   180  }
   181  
   182  func TestBuildInvalidTarget(t *testing.T) {
   183  	folder, back := testlib.Mktmp(t)
   184  	defer back()
   185  	writeGoodMain(t, folder)
   186  	var target = "linux"
   187  	var config = config.Project{
   188  		Builds: []config.Build{
   189  			{
   190  				Binary:  "foo",
   191  				Targets: []string{target},
   192  			},
   193  		},
   194  	}
   195  	var ctx = context.New(config)
   196  	ctx.Git.CurrentTag = "5.6.7"
   197  	var build = ctx.Config.Builds[0]
   198  	var err = Default.Build(ctx, build, api.Options{
   199  		Target: target,
   200  		Name:   build.Binary,
   201  		Path:   filepath.Join(folder, "dist", target, build.Binary),
   202  	})
   203  	assert.EqualError(t, err, "linux is not a valid build target")
   204  	assert.Len(t, ctx.Artifacts.List(), 0)
   205  }
   206  
   207  func TestRunInvalidAsmflags(t *testing.T) {
   208  	folder, back := testlib.Mktmp(t)
   209  	defer back()
   210  	writeGoodMain(t, folder)
   211  	var config = config.Project{
   212  		Builds: []config.Build{
   213  			{
   214  				Binary:   "nametest",
   215  				Asmflags: []string{"{{.Version}"},
   216  				Targets: []string{
   217  					runtimeTarget,
   218  				},
   219  			},
   220  		},
   221  	}
   222  	var ctx = context.New(config)
   223  	ctx.Git.CurrentTag = "5.6.7"
   224  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   225  		Target: runtimeTarget,
   226  	})
   227  	assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`)
   228  }
   229  
   230  func TestRunInvalidGcflags(t *testing.T) {
   231  	folder, back := testlib.Mktmp(t)
   232  	defer back()
   233  	writeGoodMain(t, folder)
   234  	var config = config.Project{
   235  		Builds: []config.Build{
   236  			{
   237  				Binary:  "nametest",
   238  				Gcflags: []string{"{{.Version}"},
   239  				Targets: []string{
   240  					runtimeTarget,
   241  				},
   242  			},
   243  		},
   244  	}
   245  	var ctx = context.New(config)
   246  	ctx.Git.CurrentTag = "5.6.7"
   247  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   248  		Target: runtimeTarget,
   249  	})
   250  	assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`)
   251  }
   252  
   253  func TestRunInvalidLdflags(t *testing.T) {
   254  	folder, back := testlib.Mktmp(t)
   255  	defer back()
   256  	writeGoodMain(t, folder)
   257  	var config = config.Project{
   258  		Builds: []config.Build{
   259  			{
   260  				Binary:  "nametest",
   261  				Flags:   []string{"-v"},
   262  				Ldflags: []string{"-s -w -X main.version={{.Version}"},
   263  				Targets: []string{
   264  					runtimeTarget,
   265  				},
   266  			},
   267  		},
   268  	}
   269  	var ctx = context.New(config)
   270  	ctx.Git.CurrentTag = "5.6.7"
   271  	var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   272  		Target: runtimeTarget,
   273  	})
   274  	assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`)
   275  }
   276  
   277  func TestRunPipeWithoutMainFunc(t *testing.T) {
   278  	folder, back := testlib.Mktmp(t)
   279  	defer back()
   280  	writeMainWithoutMainFunc(t, folder)
   281  	var config = config.Project{
   282  		Builds: []config.Build{
   283  			{
   284  				Binary: "no-main",
   285  				Hooks:  config.Hooks{},
   286  				Targets: []string{
   287  					runtimeTarget,
   288  				},
   289  			},
   290  		},
   291  	}
   292  	var ctx = context.New(config)
   293  	ctx.Git.CurrentTag = "5.6.7"
   294  	t.Run("empty", func(t *testing.T) {
   295  		ctx.Config.Builds[0].Main = ""
   296  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   297  			Target: runtimeTarget,
   298  		}), `build for no-main does not contain a main function`)
   299  	})
   300  	t.Run("not main.go", func(t *testing.T) {
   301  		ctx.Config.Builds[0].Main = "foo.go"
   302  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   303  			Target: runtimeTarget,
   304  		}), `stat foo.go: no such file or directory`)
   305  	})
   306  	t.Run("glob", func(t *testing.T) {
   307  		ctx.Config.Builds[0].Main = "."
   308  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   309  			Target: runtimeTarget,
   310  		}), `build for no-main does not contain a main function`)
   311  	})
   312  	t.Run("fixed main.go", func(t *testing.T) {
   313  		ctx.Config.Builds[0].Main = "main.go"
   314  		assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   315  			Target: runtimeTarget,
   316  		}), `build for no-main does not contain a main function`)
   317  	})
   318  }
   319  
   320  func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) {
   321  	folder, back := testlib.Mktmp(t)
   322  	defer back()
   323  	assert.NoError(t, ioutil.WriteFile(
   324  		filepath.Join(folder, "foo.go"),
   325  		[]byte("package main\nfunc main() {println(0)}"),
   326  		0644,
   327  	))
   328  	var config = config.Project{
   329  		Builds: []config.Build{
   330  			{
   331  				Binary: "foo",
   332  				Hooks:  config.Hooks{},
   333  				Targets: []string{
   334  					runtimeTarget,
   335  				},
   336  			},
   337  		},
   338  	}
   339  	var ctx = context.New(config)
   340  	ctx.Git.CurrentTag = "5.6.7"
   341  	t.Run("empty", func(t *testing.T) {
   342  		ctx.Config.Builds[0].Main = ""
   343  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   344  			Target: runtimeTarget,
   345  		}))
   346  	})
   347  	t.Run("foo.go", func(t *testing.T) {
   348  		ctx.Config.Builds[0].Main = "foo.go"
   349  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   350  			Target: runtimeTarget,
   351  		}))
   352  	})
   353  	t.Run("glob", func(t *testing.T) {
   354  		ctx.Config.Builds[0].Main = "."
   355  		assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{
   356  			Target: runtimeTarget,
   357  		}))
   358  	})
   359  }
   360  
   361  func TestLdFlagsFullTemplate(t *testing.T) {
   362  	var ctx = &context.Context{
   363  		Git: context.GitInfo{
   364  			CurrentTag: "v1.2.3",
   365  			Commit:     "123",
   366  		},
   367  		Version: "1.2.3",
   368  		Env:     map[string]string{"FOO": "123"},
   369  	}
   370  	flags, err := tmpl.New(ctx).
   371  		Apply(`-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}" -X main.time={{ time "20060102" }}`)
   372  	assert.NoError(t, err)
   373  	assert.Contains(t, flags, "-s -w")
   374  	assert.Contains(t, flags, "-X main.version=1.2.3")
   375  	assert.Contains(t, flags, "-X main.tag=v1.2.3")
   376  	assert.Contains(t, flags, "-X main.commit=123")
   377  	// TODO: this will break in 2019
   378  	assert.Contains(t, flags, "-X main.date=2018")
   379  	assert.Contains(t, flags, "-X main.time=2018")
   380  	assert.Contains(t, flags, `-X "main.foo=123"`)
   381  }
   382  
   383  func TestInvalidTemplate(t *testing.T) {
   384  	for template, eerr := range map[string]string{
   385  		"{{ .Nope }":    `template: tmpl:1: unexpected "}" in operand`,
   386  		"{{.Env.NOPE}}": `template: tmpl:1:6: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`,
   387  	} {
   388  		t.Run(template, func(tt *testing.T) {
   389  			var ctx = context.New(config.Project{})
   390  			ctx.Git.CurrentTag = "3.4.1"
   391  			flags, err := tmpl.New(ctx).Apply(template)
   392  			assert.EqualError(tt, err, eerr)
   393  			assert.Empty(tt, flags)
   394  		})
   395  	}
   396  }
   397  
   398  func TestProcessFlags(t *testing.T) {
   399  	var ctx = &context.Context{
   400  		Version: "1.2.3",
   401  	}
   402  	ctx.Git.CurrentTag = "5.6.7"
   403  
   404  	var source = []string{
   405  		"{{.Version}}",
   406  		"flag",
   407  	}
   408  
   409  	var expected = []string{
   410  		"-testflag=1.2.3",
   411  		"-testflag=flag",
   412  	}
   413  
   414  	flags, err := processFlags(ctx, source, "-testflag=")
   415  	assert.NoError(t, err)
   416  	assert.Len(t, flags, 2)
   417  	assert.Equal(t, expected, flags)
   418  }
   419  
   420  func TestProcessFlagsInvalid(t *testing.T) {
   421  	var ctx = &context.Context{}
   422  
   423  	var source = []string{
   424  		"{{.Version}",
   425  	}
   426  
   427  	var expected = `template: tmpl:1: unexpected "}" in operand`
   428  
   429  	flags, err := processFlags(ctx, source, "-testflag=")
   430  	assert.EqualError(t, err, expected)
   431  	assert.Nil(t, flags)
   432  }
   433  
   434  //
   435  // Helpers
   436  //
   437  
   438  func writeMainWithoutMainFunc(t *testing.T, folder string) {
   439  	assert.NoError(t, ioutil.WriteFile(
   440  		filepath.Join(folder, "main.go"),
   441  		[]byte("package main\nconst a = 2\nfunc notMain() {println(0)}"),
   442  		0644,
   443  	))
   444  }
   445  
   446  func writeGoodMain(t *testing.T, folder string) {
   447  	assert.NoError(t, ioutil.WriteFile(
   448  		filepath.Join(folder, "main.go"),
   449  		[]byte("package main\nvar a = 1\nfunc main() {println(0)}"),
   450  		0644,
   451  	))
   452  }
   453  
   454  func assertContainsError(t *testing.T, err error, s string) {
   455  	assert.Error(t, err)
   456  	assert.Contains(t, err.Error(), s)
   457  }