github.phpd.cn/goreleaser/goreleaser@v0.92.0/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 }