github.com/goreleaser/goreleaser@v1.25.1/internal/builders/golang/build_test.go (about) 1 package golang 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "runtime" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/goreleaser/goreleaser/internal/artifact" 14 "github.com/goreleaser/goreleaser/internal/testctx" 15 "github.com/goreleaser/goreleaser/internal/testlib" 16 "github.com/goreleaser/goreleaser/internal/tmpl" 17 api "github.com/goreleaser/goreleaser/pkg/build" 18 "github.com/goreleaser/goreleaser/pkg/config" 19 "github.com/goreleaser/goreleaser/pkg/context" 20 "github.com/stretchr/testify/require" 21 ) 22 23 var runtimeTarget = runtime.GOOS + "_" + runtime.GOARCH 24 25 func TestWithDefaults(t *testing.T) { 26 for name, testcase := range map[string]struct { 27 build config.Build 28 targets []string 29 goBinary string 30 }{ 31 "full": { 32 build: config.Build{ 33 ID: "foo", 34 Binary: "foo", 35 Goos: []string{ 36 "linux", 37 "windows", 38 "darwin", 39 }, 40 Goarch: []string{ 41 "amd64", 42 "arm", 43 "mips", 44 }, 45 Goarm: []string{ 46 "6", 47 }, 48 Gomips: []string{ 49 "softfloat", 50 }, 51 Goamd64: []string{ 52 "v2", 53 "v3", 54 }, 55 GoBinary: "go1.2.3", 56 }, 57 targets: []string{ 58 "linux_amd64_v2", 59 "linux_amd64_v3", 60 "linux_mips_softfloat", 61 "darwin_amd64_v2", 62 "darwin_amd64_v3", 63 "windows_amd64_v3", 64 "windows_amd64_v2", 65 "windows_arm_6", 66 "linux_arm_6", 67 }, 68 goBinary: "go1.2.3", 69 }, 70 "empty": { 71 build: config.Build{ 72 ID: "foo2", 73 Binary: "foo", 74 }, 75 targets: []string{ 76 "linux_amd64_v1", 77 "linux_386", 78 "linux_arm64", 79 "darwin_amd64_v1", 80 "darwin_arm64", 81 "windows_amd64_v1", 82 "windows_arm64", 83 "windows_386", 84 }, 85 goBinary: "go", 86 }, 87 "custom targets": { 88 build: config.Build{ 89 ID: "foo3", 90 Binary: "foo", 91 Targets: []string{ 92 "linux_386", 93 "darwin_amd64_v2", 94 }, 95 }, 96 targets: []string{ 97 "linux_386", 98 "darwin_amd64_v2", 99 }, 100 goBinary: "go", 101 }, 102 "custom targets no amd64": { 103 build: config.Build{ 104 ID: "foo3", 105 Binary: "foo", 106 Targets: []string{ 107 "linux_386", 108 "darwin_amd64", 109 }, 110 }, 111 targets: []string{ 112 "linux_386", 113 "darwin_amd64_v1", 114 }, 115 goBinary: "go", 116 }, 117 "custom targets no arm": { 118 build: config.Build{ 119 ID: "foo3", 120 Binary: "foo", 121 Targets: []string{"linux_arm"}, 122 }, 123 targets: []string{"linux_arm_6"}, 124 goBinary: "go", 125 }, 126 "custom targets no mips": { 127 build: config.Build{ 128 ID: "foo3", 129 Binary: "foo", 130 Targets: []string{"linux_mips"}, 131 }, 132 targets: []string{"linux_mips_hardfloat"}, 133 goBinary: "go", 134 }, 135 "custom targets no mipsle": { 136 build: config.Build{ 137 ID: "foo3", 138 Binary: "foo", 139 Targets: []string{"linux_mipsle"}, 140 }, 141 targets: []string{"linux_mipsle_hardfloat"}, 142 goBinary: "go", 143 }, 144 "custom targets no mips64": { 145 build: config.Build{ 146 ID: "foo3", 147 Binary: "foo", 148 Targets: []string{"linux_mips64"}, 149 }, 150 targets: []string{"linux_mips64_hardfloat"}, 151 goBinary: "go", 152 }, 153 "custom targets no mips64le": { 154 build: config.Build{ 155 ID: "foo3", 156 Binary: "foo", 157 Targets: []string{"linux_mips64le"}, 158 }, 159 targets: []string{"linux_mips64le_hardfloat"}, 160 goBinary: "go", 161 }, 162 "empty with custom dir": { 163 build: config.Build{ 164 ID: "foo2", 165 Binary: "foo", 166 Dir: "./testdata", 167 }, 168 targets: []string{ 169 "linux_amd64_v1", 170 "linux_386", 171 "linux_arm64", 172 "darwin_amd64_v1", 173 "darwin_arm64", 174 "windows_amd64_v1", 175 "windows_arm64", 176 "windows_386", 177 }, 178 goBinary: "go", 179 }, 180 "empty with custom dir that doest exist": { 181 build: config.Build{ 182 ID: "foo2", 183 Binary: "foo", 184 Dir: "./nope", 185 }, 186 targets: []string{ 187 "linux_amd64_v1", 188 "linux_386", 189 "linux_arm64", 190 "darwin_amd64_v1", 191 "darwin_arm64", 192 "windows_amd64_v1", 193 "windows_arm64", 194 "windows_386", 195 }, 196 goBinary: "go", 197 }, 198 "go first class targets": { 199 build: config.Build{ 200 ID: "foo3", 201 Binary: "foo", 202 Targets: []string{goStableFirstClassTargetsName}, 203 }, 204 targets: go118FirstClassTargets, 205 goBinary: "go", 206 }, 207 "go 1.18 first class targets": { 208 build: config.Build{ 209 ID: "foo3", 210 Binary: "foo", 211 Targets: []string{go118FirstClassTargetsName}, 212 }, 213 targets: go118FirstClassTargets, 214 goBinary: "go", 215 }, 216 "go 1.18 first class targets plus custom": { 217 build: config.Build{ 218 ID: "foo3", 219 Binary: "foo", 220 Targets: []string{"linux_amd64_v1", go118FirstClassTargetsName, "darwin_amd64_v2"}, 221 }, 222 targets: append(go118FirstClassTargets, "darwin_amd64_v2"), 223 goBinary: "go", 224 }, 225 "repeatin targets": { 226 build: config.Build{ 227 ID: "foo3", 228 Binary: "foo", 229 Targets: []string{go118FirstClassTargetsName, go118FirstClassTargetsName, goStableFirstClassTargetsName}, 230 }, 231 targets: go118FirstClassTargets, 232 goBinary: "go", 233 }, 234 } { 235 t.Run(name, func(t *testing.T) { 236 if testcase.build.GoBinary != "" && testcase.build.GoBinary != "go" { 237 createFakeGoBinaryWithVersion(t, testcase.build.GoBinary, "go1.18") 238 } 239 ctx := testctx.NewWithCfg(config.Project{ 240 Builds: []config.Build{ 241 testcase.build, 242 }, 243 }, testctx.WithCurrentTag("5.6.7")) 244 build, err := Default.WithDefaults(ctx.Config.Builds[0]) 245 require.NoError(t, err) 246 require.ElementsMatch(t, build.Targets, testcase.targets) 247 require.EqualValues(t, testcase.goBinary, build.GoBinary) 248 }) 249 } 250 } 251 252 func TestDefaults(t *testing.T) { 253 t.Run("command not set", func(t *testing.T) { 254 build, err := Default.WithDefaults(config.Build{}) 255 require.NoError(t, err) 256 require.Equal(t, "build", build.Command) 257 }) 258 t.Run("command set", func(t *testing.T) { 259 build, err := Default.WithDefaults(config.Build{ 260 Command: "test", 261 }) 262 require.NoError(t, err) 263 require.Equal(t, "test", build.Command) 264 }) 265 } 266 267 // createFakeGoBinaryWithVersion creates a temporary executable with the 268 // given name, which will output a go version string with the given version. 269 // 270 // The temporary directory created by this function will be placed in the 271 // PATH variable for the duration of (and cleaned up at the end of) the 272 // current test run. 273 func createFakeGoBinaryWithVersion(tb testing.TB, name, version string) { 274 tb.Helper() 275 d := tb.TempDir() 276 277 require.NoError(tb, os.WriteFile( 278 filepath.Join(d, name), 279 []byte(fmt.Sprintf("#!/bin/sh\necho %s", version)), 280 0o755, 281 )) 282 283 currentPath := os.Getenv("PATH") 284 285 path := fmt.Sprintf("%s%c%s", d, os.PathListSeparator, currentPath) 286 tb.Setenv("PATH", path) 287 } 288 289 func TestInvalidTargets(t *testing.T) { 290 type testcase struct { 291 build config.Build 292 expectedErr string 293 } 294 for s, tc := range map[string]testcase{ 295 "goos": { 296 build: config.Build{ 297 Goos: []string{"darwin", "darwim"}, 298 }, 299 expectedErr: "invalid goos: darwim", 300 }, 301 "goarch": { 302 build: config.Build{ 303 Goarch: []string{"amd64", "i386", "386"}, 304 }, 305 expectedErr: "invalid goarch: i386", 306 }, 307 "goarm": { 308 build: config.Build{ 309 Goarch: []string{"arm"}, 310 Goarm: []string{"6", "9", "8", "7"}, 311 }, 312 expectedErr: "invalid goarm: 9", 313 }, 314 "gomips": { 315 build: config.Build{ 316 Goarch: []string{"mips"}, 317 Gomips: []string{"softfloat", "mehfloat", "hardfloat"}, 318 }, 319 expectedErr: "invalid gomips: mehfloat", 320 }, 321 "goamd64": { 322 build: config.Build{ 323 Goarch: []string{"amd64"}, 324 Goamd64: []string{"v1", "v431"}, 325 }, 326 expectedErr: "invalid goamd64: v431", 327 }, 328 } { 329 t.Run(s, func(t *testing.T) { 330 ctx := testctx.NewWithCfg(config.Project{ 331 Builds: []config.Build{ 332 tc.build, 333 }, 334 }) 335 _, err := Default.WithDefaults(ctx.Config.Builds[0]) 336 require.EqualError(t, err, tc.expectedErr) 337 }) 338 } 339 } 340 341 func TestBuild(t *testing.T) { 342 folder := testlib.Mktmp(t) 343 writeGoodMain(t, folder) 344 ctx := testctx.NewWithCfg(config.Project{ 345 Env: []string{"GO_FLAGS=-v", "GOBIN=go"}, 346 Builds: []config.Build{ 347 { 348 ID: "foo", 349 Binary: "bin/foo-{{ .Version }}", 350 Targets: []string{ 351 "linux_amd64", 352 "darwin_amd64", 353 "windows_amd64", 354 "linux_arm_6", 355 "js_wasm", 356 "linux_mips_softfloat", 357 "linux_mips64le_softfloat", 358 }, 359 GoBinary: "{{ .Env.GOBIN }}", 360 Command: "build", 361 BuildDetails: config.BuildDetails{ 362 Env: []string{ 363 "GO111MODULE=off", 364 `TEST_T={{- if eq .Os "windows" -}} 365 w 366 {{- else if eq .Os "darwin" -}} 367 d 368 {{- else if eq .Os "linux" -}} 369 l 370 {{- end -}}`, 371 }, 372 Asmflags: []string{".=", "all="}, 373 Gcflags: []string{"all="}, 374 Flags: []string{"{{.Env.GO_FLAGS}}"}, 375 Tags: []string{"osusergo", "netgo", "static_build"}, 376 }, 377 }, 378 }, 379 }, testctx.WithCurrentTag("v5.6.7"), testctx.WithVersion("v5.6.7")) 380 build := ctx.Config.Builds[0] 381 for _, target := range build.Targets { 382 var ext string 383 if strings.HasPrefix(target, "windows") { 384 ext = ".exe" 385 } else if target == "js_wasm" { 386 ext = ".wasm" 387 } 388 bin, terr := tmpl.New(ctx).Apply(build.Binary) 389 require.NoError(t, terr) 390 391 // injecting some delay here to force inconsistent mod times on bins 392 time.Sleep(2 * time.Second) 393 394 parts := strings.Split(target, "_") 395 goos := parts[0] 396 goarch := parts[1] 397 goarm := "" 398 gomips := "" 399 if len(parts) > 2 { 400 if strings.Contains(goarch, "arm") { 401 goarm = parts[2] 402 } 403 if strings.Contains(goarch, "mips") { 404 gomips = parts[2] 405 } 406 } 407 err := Default.Build(ctx, build, api.Options{ 408 Target: target, 409 Name: bin + ext, 410 Path: filepath.Join(folder, "dist", target, bin+ext), 411 Goos: goos, 412 Goarch: goarch, 413 Goarm: goarm, 414 Gomips: gomips, 415 Ext: ext, 416 }) 417 require.NoError(t, err) 418 } 419 require.ElementsMatch(t, ctx.Artifacts.List(), []*artifact.Artifact{ 420 { 421 Name: "bin/foo-v5.6.7", 422 Path: filepath.Join("dist", "linux_amd64", "bin", "foo-v5.6.7"), 423 Goos: "linux", 424 Goarch: "amd64", 425 Type: artifact.Binary, 426 Extra: map[string]interface{}{ 427 artifact.ExtraExt: "", 428 artifact.ExtraBinary: "foo-v5.6.7", 429 artifact.ExtraID: "foo", 430 "testEnvs": []string{"TEST_T=l"}, 431 }, 432 }, 433 { 434 Name: "bin/foo-v5.6.7", 435 Path: filepath.Join("dist", "linux_mips_softfloat", "bin", "foo-v5.6.7"), 436 Goos: "linux", 437 Goarch: "mips", 438 Gomips: "softfloat", 439 Type: artifact.Binary, 440 Extra: map[string]interface{}{ 441 artifact.ExtraExt: "", 442 artifact.ExtraBinary: "foo-v5.6.7", 443 artifact.ExtraID: "foo", 444 "testEnvs": []string{"TEST_T=l"}, 445 }, 446 }, 447 { 448 Name: "bin/foo-v5.6.7", 449 Path: filepath.Join("dist", "linux_mips64le_softfloat", "bin", "foo-v5.6.7"), 450 Goos: "linux", 451 Goarch: "mips64le", 452 Gomips: "softfloat", 453 Type: artifact.Binary, 454 Extra: map[string]interface{}{ 455 artifact.ExtraExt: "", 456 artifact.ExtraBinary: "foo-v5.6.7", 457 artifact.ExtraID: "foo", 458 "testEnvs": []string{"TEST_T=l"}, 459 }, 460 }, 461 { 462 Name: "bin/foo-v5.6.7", 463 Path: filepath.Join("dist", "darwin_amd64", "bin", "foo-v5.6.7"), 464 Goos: "darwin", 465 Goarch: "amd64", 466 Type: artifact.Binary, 467 Extra: map[string]interface{}{ 468 artifact.ExtraExt: "", 469 artifact.ExtraBinary: "foo-v5.6.7", 470 artifact.ExtraID: "foo", 471 "testEnvs": []string{"TEST_T=d"}, 472 }, 473 }, 474 { 475 Name: "bin/foo-v5.6.7", 476 Path: filepath.Join("dist", "linux_arm_6", "bin", "foo-v5.6.7"), 477 Goos: "linux", 478 Goarch: "arm", 479 Goarm: "6", 480 Type: artifact.Binary, 481 Extra: map[string]interface{}{ 482 artifact.ExtraExt: "", 483 artifact.ExtraBinary: "foo-v5.6.7", 484 artifact.ExtraID: "foo", 485 "testEnvs": []string{"TEST_T=l"}, 486 }, 487 }, 488 { 489 Name: "bin/foo-v5.6.7.exe", 490 Path: filepath.Join("dist", "windows_amd64", "bin", "foo-v5.6.7.exe"), 491 Goos: "windows", 492 Goarch: "amd64", 493 Type: artifact.Binary, 494 Extra: map[string]interface{}{ 495 artifact.ExtraExt: ".exe", 496 artifact.ExtraBinary: "foo-v5.6.7", 497 artifact.ExtraID: "foo", 498 "testEnvs": []string{"TEST_T=w"}, 499 }, 500 }, 501 { 502 Name: "bin/foo-v5.6.7.wasm", 503 Path: filepath.Join("dist", "js_wasm", "bin", "foo-v5.6.7.wasm"), 504 Goos: "js", 505 Goarch: "wasm", 506 Type: artifact.Binary, 507 Extra: map[string]interface{}{ 508 artifact.ExtraExt: ".wasm", 509 artifact.ExtraBinary: "foo-v5.6.7", 510 artifact.ExtraID: "foo", 511 "testEnvs": []string{"TEST_T="}, 512 }, 513 }, 514 }) 515 516 modTimes := map[int64]bool{} 517 for _, bin := range ctx.Artifacts.List() { 518 if bin.Type != artifact.Binary { 519 continue 520 } 521 522 fi, err := os.Stat(bin.Path) 523 require.NoError(t, err) 524 525 // make this a suitable map key, per docs: https://golang.org/pkg/time/#Time 526 modTime := fi.ModTime().UTC().Round(0).Unix() 527 528 if modTimes[modTime] { 529 t.Fatal("duplicate modified time found, times should be different by default") 530 } 531 modTimes[modTime] = true 532 } 533 } 534 535 func TestBuildInvalidEnv(t *testing.T) { 536 folder := testlib.Mktmp(t) 537 writeGoodMain(t, folder) 538 ctx := testctx.NewWithCfg(config.Project{ 539 Builds: []config.Build{ 540 { 541 ID: "foo", 542 Dir: ".", 543 Binary: "foo", 544 Targets: []string{ 545 runtimeTarget, 546 }, 547 GoBinary: "go", 548 BuildDetails: config.BuildDetails{ 549 Env: []string{"GO111MODULE={{ .Nope }}"}, 550 }, 551 }, 552 }, 553 }, testctx.WithCurrentTag("5.6.7")) 554 build := ctx.Config.Builds[0] 555 err := Default.Build(ctx, build, api.Options{ 556 Target: runtimeTarget, 557 Name: build.Binary, 558 Path: filepath.Join("dist", runtimeTarget, build.Binary), 559 Ext: "", 560 }) 561 testlib.RequireTemplateError(t, err) 562 } 563 564 func TestBuildCodeInSubdir(t *testing.T) { 565 folder := testlib.Mktmp(t) 566 subdir := filepath.Join(folder, "bar") 567 err := os.Mkdir(subdir, 0o755) 568 require.NoError(t, err) 569 writeGoodMain(t, subdir) 570 ctx := testctx.NewWithCfg(config.Project{ 571 Builds: []config.Build{ 572 { 573 ID: "foo", 574 Dir: "bar", 575 Binary: "foo", 576 Targets: []string{ 577 runtimeTarget, 578 }, 579 GoBinary: "go", 580 Command: "build", 581 BuildDetails: config.BuildDetails{ 582 Env: []string{"GO111MODULE=off"}, 583 }, 584 }, 585 }, 586 }, testctx.WithCurrentTag("5.6.7")) 587 build := ctx.Config.Builds[0] 588 err = Default.Build(ctx, build, api.Options{ 589 Target: runtimeTarget, 590 Name: build.Binary, 591 Path: filepath.Join("dist", runtimeTarget, build.Binary), 592 Ext: "", 593 }) 594 require.NoError(t, err) 595 } 596 597 func TestBuildWithDotGoDir(t *testing.T) { 598 folder := testlib.Mktmp(t) 599 require.NoError(t, os.Mkdir(filepath.Join(folder, ".go"), 0o755)) 600 writeGoodMain(t, folder) 601 ctx := testctx.NewWithCfg(config.Project{ 602 Builds: []config.Build{ 603 { 604 ID: "foo", 605 Binary: "foo", 606 Targets: []string{runtimeTarget}, 607 GoBinary: "go", 608 Command: "build", 609 BuildDetails: config.BuildDetails{ 610 Env: []string{"GO111MODULE=off"}, 611 }, 612 }, 613 }, 614 }, testctx.WithCurrentTag("5.6.7")) 615 build := ctx.Config.Builds[0] 616 require.NoError(t, Default.Build(ctx, build, api.Options{ 617 Target: runtimeTarget, 618 Name: build.Binary, 619 Path: filepath.Join("dist", runtimeTarget, build.Binary), 620 Ext: "", 621 })) 622 } 623 624 func TestBuildFailed(t *testing.T) { 625 folder := testlib.Mktmp(t) 626 writeGoodMain(t, folder) 627 ctx := testctx.NewWithCfg(config.Project{ 628 Builds: []config.Build{ 629 { 630 ID: "buildid", 631 BuildDetails: config.BuildDetails{ 632 Flags: []string{"-flag-that-dont-exists-to-force-failure"}, 633 }, 634 Targets: []string{ 635 runtimeTarget, 636 }, 637 GoBinary: "go", 638 Command: "build", 639 }, 640 }, 641 }, testctx.WithCurrentTag("5.6.7")) 642 err := Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 643 Target: "darwin_amd64", 644 }) 645 require.ErrorContains(t, err, `flag provided but not defined: -flag-that-dont-exists-to-force-failure`) 646 require.Empty(t, ctx.Artifacts.List()) 647 } 648 649 func TestRunInvalidAsmflags(t *testing.T) { 650 folder := testlib.Mktmp(t) 651 writeGoodMain(t, folder) 652 ctx := testctx.NewWithCfg(config.Project{ 653 Builds: []config.Build{ 654 { 655 Binary: "nametest", 656 BuildDetails: config.BuildDetails{ 657 Asmflags: []string{"{{.Version}"}, 658 }, 659 Targets: []string{ 660 runtimeTarget, 661 }, 662 }, 663 }, 664 }, testctx.WithCurrentTag("5.6.7")) 665 err := Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 666 Target: runtimeTarget, 667 }) 668 testlib.RequireTemplateError(t, err) 669 } 670 671 func TestRunInvalidGcflags(t *testing.T) { 672 folder := testlib.Mktmp(t) 673 writeGoodMain(t, folder) 674 ctx := testctx.NewWithCfg(config.Project{ 675 Builds: []config.Build{ 676 { 677 Binary: "nametest", 678 BuildDetails: config.BuildDetails{ 679 Gcflags: []string{"{{.Version}"}, 680 }, 681 Targets: []string{ 682 runtimeTarget, 683 }, 684 }, 685 }, 686 }, testctx.WithCurrentTag("5.6.7")) 687 err := Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 688 Target: runtimeTarget, 689 }) 690 testlib.RequireTemplateError(t, err) 691 } 692 693 func TestRunInvalidLdflags(t *testing.T) { 694 folder := testlib.Mktmp(t) 695 writeGoodMain(t, folder) 696 ctx := testctx.NewWithCfg(config.Project{ 697 Builds: []config.Build{ 698 { 699 Binary: "nametest", 700 BuildDetails: config.BuildDetails{ 701 Flags: []string{"-v"}, 702 Ldflags: []string{"-s -w -X main.version={{.Version}"}, 703 }, 704 Targets: []string{ 705 runtimeTarget, 706 }, 707 }, 708 }, 709 }, testctx.WithCurrentTag("5.6.7")) 710 err := Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 711 Target: runtimeTarget, 712 }) 713 testlib.RequireTemplateError(t, err) 714 } 715 716 func TestRunInvalidFlags(t *testing.T) { 717 folder := testlib.Mktmp(t) 718 writeGoodMain(t, folder) 719 ctx := testctx.NewWithCfg(config.Project{ 720 Builds: []config.Build{ 721 { 722 Binary: "nametest", 723 BuildDetails: config.BuildDetails{ 724 Flags: []string{"{{.Env.GOOS}"}, 725 }, 726 Targets: []string{ 727 runtimeTarget, 728 }, 729 }, 730 }, 731 }) 732 err := Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 733 Target: runtimeTarget, 734 }) 735 testlib.RequireTemplateError(t, err) 736 } 737 738 func TestRunPipeWithoutMainFunc(t *testing.T) { 739 newCtx := func(t *testing.T) *context.Context { 740 t.Helper() 741 folder := testlib.Mktmp(t) 742 writeMainWithoutMainFunc(t, folder) 743 ctx := testctx.NewWithCfg(config.Project{ 744 Builds: []config.Build{{Binary: "no-main"}}, 745 }, testctx.WithCurrentTag("5.6.7")) 746 return ctx 747 } 748 t.Run("empty", func(t *testing.T) { 749 ctx := newCtx(t) 750 ctx.Config.Builds[0].Main = "" 751 require.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 752 Target: runtimeTarget, 753 }), errNoMain{"no-main"}.Error()) 754 }) 755 t.Run("not main.go", func(t *testing.T) { 756 ctx := newCtx(t) 757 ctx.Config.Builds[0].Main = "foo.go" 758 require.ErrorIs(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 759 Target: runtimeTarget, 760 }), os.ErrNotExist) 761 }) 762 t.Run("glob", func(t *testing.T) { 763 ctx := newCtx(t) 764 ctx.Config.Builds[0].Main = "." 765 require.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 766 Target: runtimeTarget, 767 }), errNoMain{"no-main"}.Error()) 768 }) 769 t.Run("fixed main.go", func(t *testing.T) { 770 ctx := newCtx(t) 771 ctx.Config.Builds[0].Main = "main.go" 772 require.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 773 Target: runtimeTarget, 774 }), errNoMain{"no-main"}.Error()) 775 }) 776 t.Run("using gomod.proxy", func(t *testing.T) { 777 ctx := newCtx(t) 778 ctx.Config.GoMod.Proxy = true 779 ctx.Config.Builds[0].Dir = "dist/proxy/test" 780 ctx.Config.Builds[0].Main = "github.com/caarlos0/test" 781 ctx.Config.Builds[0].UnproxiedDir = "." 782 ctx.Config.Builds[0].UnproxiedMain = "." 783 require.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 784 Target: runtimeTarget, 785 }), errNoMain{"no-main"}.Error()) 786 }) 787 } 788 789 func TestBuildTests(t *testing.T) { 790 folder := testlib.Mktmp(t) 791 writeTest(t, folder) 792 ctx := testctx.NewWithCfg(config.Project{ 793 Builds: []config.Build{{ 794 Binary: "foo.test", 795 Command: "test", 796 BuildDetails: config.BuildDetails{ 797 Flags: []string{"-c"}, 798 }, 799 NoMainCheck: true, 800 }}, 801 }, testctx.WithCurrentTag("5.6.7")) 802 build, err := Default.WithDefaults(ctx.Config.Builds[0]) 803 require.NoError(t, err) 804 require.NoError(t, Default.Build(ctx, build, api.Options{ 805 Target: runtimeTarget, 806 })) 807 } 808 809 func TestRunPipeWithProxiedRepo(t *testing.T) { 810 folder := testlib.Mktmp(t) 811 out, err := exec.Command("git", "clone", "https://github.com/goreleaser/goreleaser", "-b", "v0.161.1", "--depth=1", ".").CombinedOutput() 812 require.NoError(t, err, string(out)) 813 814 proxied := filepath.Join(folder, "dist/proxy/default") 815 require.NoError(t, os.MkdirAll(proxied, 0o750)) 816 require.NoError(t, os.WriteFile( 817 filepath.Join(proxied, "main.go"), 818 []byte(`// +build main 819 package main 820 821 import _ "github.com/goreleaser/goreleaser" 822 `), 823 0o666, 824 )) 825 require.NoError(t, os.WriteFile( 826 filepath.Join(proxied, "go.mod"), 827 []byte("module foo\nrequire github.com/goreleaser/goreleaser v0.161.1"), 828 0o666, 829 )) 830 831 cmd := exec.Command("go", "mod", "tidy") 832 cmd.Dir = proxied 833 require.NoError(t, cmd.Run()) 834 835 ctx := testctx.NewWithCfg(config.Project{ 836 GoMod: config.GoMod{ 837 Proxy: true, 838 }, 839 Builds: []config.Build{ 840 { 841 Binary: "foo", 842 Main: "github.com/goreleaser/goreleaser", 843 Dir: proxied, 844 UnproxiedMain: ".", 845 UnproxiedDir: ".", 846 Targets: []string{ 847 runtimeTarget, 848 }, 849 GoBinary: "go", 850 Command: "build", 851 }, 852 }, 853 }) 854 855 require.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 856 Target: runtimeTarget, 857 })) 858 } 859 860 func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) { 861 folder := testlib.Mktmp(t) 862 require.NoError(t, os.WriteFile( 863 filepath.Join(folder, "foo.go"), 864 []byte("package main\nfunc main() {println(0)}"), 865 0o644, 866 )) 867 ctx := testctx.NewWithCfg(config.Project{ 868 Builds: []config.Build{ 869 { 870 Binary: "foo", 871 Hooks: config.BuildHookConfig{}, 872 Targets: []string{ 873 runtimeTarget, 874 }, 875 BuildDetails: config.BuildDetails{ 876 Env: []string{"GO111MODULE=off"}, 877 }, 878 GoBinary: "go", 879 Command: "build", 880 }, 881 }, 882 }, testctx.WithCurrentTag("5.6.7")) 883 t.Run("empty", func(t *testing.T) { 884 ctx.Config.Builds[0].Main = "" 885 require.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 886 Target: runtimeTarget, 887 })) 888 }) 889 t.Run("foo.go", func(t *testing.T) { 890 ctx.Config.Builds[0].Main = "foo.go" 891 require.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 892 Target: runtimeTarget, 893 })) 894 }) 895 t.Run("glob", func(t *testing.T) { 896 ctx.Config.Builds[0].Main = "." 897 require.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ 898 Target: runtimeTarget, 899 })) 900 }) 901 } 902 903 func TestLdFlagsFullTemplate(t *testing.T) { 904 run := time.Now().UTC() 905 commit := time.Now().AddDate(-1, 0, 0) 906 ctx := testctx.New( 907 testctx.WithCurrentTag("v1.2.3"), 908 testctx.WithCommit("123"), 909 testctx.WithCommitDate(commit), 910 testctx.WithVersion("1.2.3"), 911 testctx.WithEnv(map[string]string{"FOO": "123"}), 912 testctx.WithDate(run), 913 ) 914 artifact := &artifact.Artifact{Goarch: "amd64"} 915 flags, err := tmpl.New(ctx).WithArtifact(artifact). 916 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" }} -X main.arch={{.Arch}} -X main.commitDate={{.CommitDate}}`) 917 require.NoError(t, err) 918 require.Contains(t, flags, "-s -w") 919 require.Contains(t, flags, "-X main.version=1.2.3") 920 require.Contains(t, flags, "-X main.tag=v1.2.3") 921 require.Contains(t, flags, "-X main.commit=123") 922 require.Contains(t, flags, fmt.Sprintf("-X main.date=%d", run.Year())) 923 require.Contains(t, flags, fmt.Sprintf("-X main.time=%d", run.Year())) 924 require.Contains(t, flags, `-X "main.foo=123"`) 925 require.Contains(t, flags, `-X main.arch=amd64`) 926 require.Contains(t, flags, fmt.Sprintf("-X main.commitDate=%d", commit.Year())) 927 } 928 929 func TestInvalidTemplate(t *testing.T) { 930 for _, template := range []string{ 931 "{{ .Nope }", 932 "{{.Env.NOPE}}", 933 } { 934 t.Run(template, func(t *testing.T) { 935 ctx := testctx.New(testctx.WithCurrentTag("3.4.1")) 936 flags, err := tmpl.New(ctx).Apply(template) 937 testlib.RequireTemplateError(t, err) 938 require.Empty(t, flags) 939 }) 940 } 941 } 942 943 func TestProcessFlags(t *testing.T) { 944 ctx := testctx.New( 945 testctx.WithVersion("1.2.3"), 946 testctx.WithCurrentTag("5.6.7"), 947 ) 948 949 artifact := &artifact.Artifact{ 950 Name: "name", 951 Goos: "darwin", 952 Goarch: "amd64", 953 Goarm: "7", 954 Extra: map[string]interface{}{ 955 artifact.ExtraBinary: "binary", 956 }, 957 } 958 959 source := []string{ 960 "flag", 961 "{{.Version}}", 962 "{{.Os}}", 963 "{{.Arch}}", 964 "{{.Arm}}", 965 "{{.Binary}}", 966 "{{.ArtifactName}}", 967 } 968 969 expected := []string{ 970 "-testflag=flag", 971 "-testflag=1.2.3", 972 "-testflag=darwin", 973 "-testflag=amd64", 974 "-testflag=7", 975 "-testflag=binary", 976 "-testflag=name", 977 } 978 979 flags, err := processFlags(ctx, artifact, []string{}, source, "-testflag=") 980 require.NoError(t, err) 981 require.Len(t, flags, 7) 982 require.Equal(t, expected, flags) 983 } 984 985 func TestProcessFlagsInvalid(t *testing.T) { 986 ctx := testctx.New() 987 source := []string{ 988 "{{.Version}", 989 } 990 flags, err := processFlags(ctx, &artifact.Artifact{}, []string{}, source, "-testflag=") 991 testlib.RequireTemplateError(t, err) 992 require.Nil(t, flags) 993 } 994 995 func TestBuildModTimestamp(t *testing.T) { 996 // round to seconds since this will be a unix timestamp 997 modTime := time.Now().AddDate(-1, 0, 0).Round(1 * time.Second).UTC() 998 999 folder := testlib.Mktmp(t) 1000 writeGoodMain(t, folder) 1001 1002 ctx := testctx.NewWithCfg( 1003 config.Project{ 1004 Env: []string{"GO_FLAGS=-v"}, 1005 Builds: []config.Build{{ 1006 ID: "foo", 1007 Binary: "bin/foo-{{ .Version }}", 1008 Targets: []string{ 1009 "linux_amd64", 1010 "darwin_amd64", 1011 "windows_amd64", 1012 "linux_arm_6", 1013 "js_wasm", 1014 "linux_mips_softfloat", 1015 "linux_mips64le_softfloat", 1016 }, 1017 BuildDetails: config.BuildDetails{ 1018 Env: []string{"GO111MODULE=off"}, 1019 Asmflags: []string{".=", "all="}, 1020 Gcflags: []string{"all="}, 1021 Flags: []string{"{{.Env.GO_FLAGS}}"}, 1022 }, 1023 ModTimestamp: fmt.Sprintf("%d", modTime.Unix()), 1024 GoBinary: "go", 1025 Command: "build", 1026 }}, 1027 }, 1028 testctx.WithCurrentTag("v5.6.7"), 1029 testctx.WithVersion("5.6.7"), 1030 ) 1031 build := ctx.Config.Builds[0] 1032 for _, target := range build.Targets { 1033 var ext string 1034 if strings.HasPrefix(target, "windows") { 1035 ext = ".exe" 1036 } else if target == "js_wasm" { 1037 ext = ".wasm" 1038 } 1039 bin, terr := tmpl.New(ctx).Apply(build.Binary) 1040 require.NoError(t, terr) 1041 1042 // injecting some delay here to force inconsistent mod times on bins 1043 time.Sleep(2 * time.Second) 1044 1045 err := Default.Build(ctx, build, api.Options{ 1046 Target: target, 1047 Name: bin + ext, 1048 Path: filepath.Join(folder, "dist", target, bin+ext), 1049 Ext: ext, 1050 }) 1051 require.NoError(t, err) 1052 } 1053 1054 for _, bin := range ctx.Artifacts.List() { 1055 if bin.Type != artifact.Binary { 1056 continue 1057 } 1058 1059 fi, err := os.Stat(bin.Path) 1060 require.NoError(t, err) 1061 require.True(t, modTime.Equal(fi.ModTime()), "inconsistent mod times found when specifying ModTimestamp") 1062 } 1063 } 1064 1065 func TestBuildGoBuildLine(t *testing.T) { 1066 requireEqualCmd := func(tb testing.TB, build config.Build, expected []string) { 1067 tb.Helper() 1068 ctx := testctx.NewWithCfg( 1069 config.Project{ 1070 Builds: []config.Build{build}, 1071 }, 1072 testctx.WithVersion("1.2.3"), 1073 testctx.WithGitInfo(context.GitInfo{Commit: "aaa"}), 1074 testctx.WithEnv(map[string]string{"GOBIN": "go"}), 1075 ) 1076 options := api.Options{ 1077 Path: ctx.Config.Builds[0].Binary, 1078 Goos: "linux", 1079 Goarch: "amd64", 1080 } 1081 1082 dets, err := withOverrides(ctx, build, options) 1083 require.NoError(t, err) 1084 1085 line, err := buildGoBuildLine( 1086 ctx, 1087 build, 1088 dets, 1089 options, 1090 &artifact.Artifact{}, 1091 []string{}, 1092 ) 1093 require.NoError(t, err) 1094 require.Equal(t, expected, line) 1095 } 1096 1097 t.Run("full", func(t *testing.T) { 1098 requireEqualCmd(t, config.Build{ 1099 Main: ".", 1100 BuildDetails: config.BuildDetails{ 1101 Asmflags: []string{"asmflag1", "asmflag2"}, 1102 Gcflags: []string{"gcflag1", "gcflag2"}, 1103 Flags: []string{"-flag1", "-flag2"}, 1104 Tags: []string{"tag1", "tag2"}, 1105 Ldflags: []string{"ldflag1", "ldflag2"}, 1106 }, 1107 Binary: "foo", 1108 GoBinary: "{{ .Env.GOBIN }}", 1109 Command: "build", 1110 }, []string{ 1111 "go", "build", 1112 "-flag1", "-flag2", 1113 "-asmflags=asmflag1", "-asmflags=asmflag2", 1114 "-gcflags=gcflag1", "-gcflags=gcflag2", 1115 "-tags=tag1,tag2", 1116 "-ldflags=ldflag1 ldflag2", 1117 "-o", "foo", ".", 1118 }) 1119 }) 1120 1121 t.Run("with overrides", func(t *testing.T) { 1122 requireEqualCmd(t, config.Build{ 1123 Main: ".", 1124 BuildDetails: config.BuildDetails{ 1125 Asmflags: []string{"asmflag1", "asmflag2"}, 1126 Gcflags: []string{"gcflag1", "gcflag2"}, 1127 Flags: []string{"-flag1", "-flag2"}, 1128 Tags: []string{"tag1", "tag2"}, 1129 Ldflags: []string{"ldflag1", "ldflag2"}, 1130 }, 1131 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1132 { 1133 Goos: "linux", 1134 Goarch: "amd64", 1135 BuildDetails: config.BuildDetails{ 1136 Asmflags: []string{"asmflag3"}, 1137 Gcflags: []string{"gcflag3"}, 1138 Flags: []string{"-flag3"}, 1139 Tags: []string{"tag3"}, 1140 Ldflags: []string{"ldflag3"}, 1141 }, 1142 }, 1143 }, 1144 GoBinary: "go", 1145 Binary: "foo", 1146 Command: "build", 1147 }, []string{ 1148 "go", "build", 1149 "-flag3", 1150 "-asmflags=asmflag3", 1151 "-gcflags=gcflag3", 1152 "-tags=tag3", 1153 "-ldflags=ldflag3", 1154 "-o", "foo", ".", 1155 }) 1156 }) 1157 1158 t.Run("simple", func(t *testing.T) { 1159 requireEqualCmd(t, config.Build{ 1160 Main: ".", 1161 GoBinary: "go", 1162 Command: "build", 1163 Binary: "foo", 1164 }, strings.Fields("go build -o foo .")) 1165 }) 1166 1167 t.Run("test", func(t *testing.T) { 1168 requireEqualCmd(t, config.Build{ 1169 Main: ".", 1170 GoBinary: "go", 1171 Command: "test", 1172 Binary: "foo.test", 1173 BuildDetails: config.BuildDetails{ 1174 Flags: []string{"-c"}, 1175 }, 1176 }, strings.Fields("go test -c -o foo.test .")) 1177 }) 1178 1179 t.Run("build test always as c flags", func(t *testing.T) { 1180 requireEqualCmd(t, config.Build{ 1181 Main: ".", 1182 GoBinary: "go", 1183 Command: "test", 1184 Binary: "foo.test", 1185 }, strings.Fields("go test -c -o foo.test .")) 1186 }) 1187 1188 t.Run("ldflags1", func(t *testing.T) { 1189 requireEqualCmd(t, config.Build{ 1190 Main: ".", 1191 BuildDetails: config.BuildDetails{ 1192 Ldflags: []string{"-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.builtBy=goreleaser"}, 1193 }, 1194 GoBinary: "go", 1195 Command: "build", 1196 Binary: "foo", 1197 }, []string{ 1198 "go", "build", 1199 "-ldflags=-s -w -X main.version=1.2.3 -X main.commit=aaa -X main.builtBy=goreleaser", 1200 "-o", "foo", ".", 1201 }) 1202 }) 1203 1204 t.Run("ldflags2", func(t *testing.T) { 1205 requireEqualCmd(t, config.Build{ 1206 Main: ".", 1207 BuildDetails: config.BuildDetails{ 1208 Ldflags: []string{"-s -w", "-X main.version={{.Version}}"}, 1209 }, 1210 GoBinary: "go", 1211 Binary: "foo", 1212 Command: "build", 1213 }, []string{"go", "build", "-ldflags=-s -w -X main.version=1.2.3", "-o", "foo", "."}) 1214 }) 1215 } 1216 1217 func TestOverrides(t *testing.T) { 1218 t.Run("linux amd64", func(t *testing.T) { 1219 dets, err := withOverrides( 1220 testctx.New(), 1221 config.Build{ 1222 BuildDetails: config.BuildDetails{ 1223 Ldflags: []string{"original"}, 1224 Env: []string{"BAR=foo", "FOO=bar"}, 1225 }, 1226 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1227 { 1228 Goos: "linux", 1229 Goarch: "amd64", 1230 BuildDetails: config.BuildDetails{ 1231 Ldflags: []string{"overridden"}, 1232 Env: []string{"FOO=overridden"}, 1233 }, 1234 }, 1235 }, 1236 }, api.Options{ 1237 Goos: "linux", 1238 Goarch: "amd64", 1239 }, 1240 ) 1241 require.NoError(t, err) 1242 require.ElementsMatch(t, dets.Ldflags, []string{"overridden"}) 1243 require.ElementsMatch(t, dets.Env, []string{"BAR=foo", "FOO=overridden"}) 1244 }) 1245 1246 t.Run("single sided", func(t *testing.T) { 1247 dets, err := withOverrides( 1248 testctx.New(), 1249 config.Build{ 1250 BuildDetails: config.BuildDetails{}, 1251 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1252 { 1253 Goos: "linux", 1254 Goarch: "amd64", 1255 BuildDetails: config.BuildDetails{ 1256 Ldflags: []string{"overridden"}, 1257 Tags: []string{"tag1"}, 1258 Asmflags: []string{"asm1"}, 1259 Gcflags: []string{"gcflag1"}, 1260 }, 1261 }, 1262 }, 1263 }, api.Options{ 1264 Goos: "linux", 1265 Goarch: "amd64", 1266 }, 1267 ) 1268 require.NoError(t, err) 1269 require.Equal(t, config.BuildDetails{ 1270 Ldflags: []string{"overridden"}, 1271 Gcflags: []string{"gcflag1"}, 1272 Asmflags: []string{"asm1"}, 1273 Tags: []string{"tag1"}, 1274 Env: []string{}, 1275 }, dets) 1276 }) 1277 1278 t.Run("with template", func(t *testing.T) { 1279 dets, err := withOverrides( 1280 testctx.New(), 1281 config.Build{ 1282 BuildDetails: config.BuildDetails{ 1283 Ldflags: []string{"original"}, 1284 Asmflags: []string{"asm1"}, 1285 }, 1286 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1287 { 1288 Goos: "{{ .Runtime.Goos }}", 1289 Goarch: "{{ .Runtime.Goarch }}", 1290 BuildDetails: config.BuildDetails{ 1291 Ldflags: []string{"overridden"}, 1292 }, 1293 }, 1294 }, 1295 }, api.Options{ 1296 Goos: runtime.GOOS, 1297 Goarch: runtime.GOARCH, 1298 }, 1299 ) 1300 require.NoError(t, err) 1301 require.Equal(t, config.BuildDetails{ 1302 Ldflags: []string{"overridden"}, 1303 Asmflags: []string{"asm1"}, 1304 Env: []string{}, 1305 }, dets) 1306 }) 1307 1308 t.Run("with invalid template", func(t *testing.T) { 1309 _, err := withOverrides( 1310 testctx.New(), 1311 config.Build{ 1312 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1313 { 1314 Goos: "{{ .Runtime.Goos }", 1315 }, 1316 }, 1317 }, api.Options{ 1318 Goos: runtime.GOOS, 1319 Goarch: runtime.GOARCH, 1320 }, 1321 ) 1322 testlib.RequireTemplateError(t, err) 1323 }) 1324 1325 t.Run("with goarm", func(t *testing.T) { 1326 dets, err := withOverrides( 1327 testctx.New(), 1328 config.Build{ 1329 BuildDetails: config.BuildDetails{ 1330 Ldflags: []string{"original"}, 1331 }, 1332 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1333 { 1334 Goos: "linux", 1335 Goarch: "arm", 1336 Goarm: "6", 1337 BuildDetails: config.BuildDetails{ 1338 Ldflags: []string{"overridden"}, 1339 }, 1340 }, 1341 }, 1342 }, api.Options{ 1343 Goos: "linux", 1344 Goarch: "arm", 1345 Goarm: "6", 1346 }, 1347 ) 1348 require.NoError(t, err) 1349 require.Equal(t, config.BuildDetails{ 1350 Ldflags: []string{"overridden"}, 1351 Env: []string{}, 1352 }, dets) 1353 }) 1354 1355 t.Run("with gomips", func(t *testing.T) { 1356 dets, err := withOverrides( 1357 testctx.New(), 1358 config.Build{ 1359 BuildDetails: config.BuildDetails{ 1360 Ldflags: []string{"original"}, 1361 }, 1362 BuildDetailsOverrides: []config.BuildDetailsOverride{ 1363 { 1364 Goos: "linux", 1365 Goarch: "mips", 1366 Gomips: "softfloat", 1367 BuildDetails: config.BuildDetails{ 1368 Ldflags: []string{"overridden"}, 1369 }, 1370 }, 1371 }, 1372 }, api.Options{ 1373 Goos: "linux", 1374 Goarch: "mips", 1375 Gomips: "softfloat", 1376 }, 1377 ) 1378 require.NoError(t, err) 1379 require.Equal(t, config.BuildDetails{ 1380 Ldflags: []string{"overridden"}, 1381 Env: []string{}, 1382 }, dets) 1383 }) 1384 } 1385 1386 func TestWarnIfTargetsAndOtherOptionsTogether(t *testing.T) { 1387 nonEmpty := []string{"foo", "bar"} 1388 for name, fn := range map[string]func(*config.Build){ 1389 "goos": func(b *config.Build) { b.Goos = nonEmpty }, 1390 "goarch": func(b *config.Build) { b.Goarch = nonEmpty }, 1391 "goarm": func(b *config.Build) { b.Goarm = nonEmpty }, 1392 "gomips": func(b *config.Build) { b.Gomips = nonEmpty }, 1393 "goamd64": func(b *config.Build) { b.Goamd64 = nonEmpty }, 1394 "ignores": func(b *config.Build) { b.Ignore = []config.IgnoredBuild{{Goos: "linux"}} }, 1395 "multiple": func(b *config.Build) { 1396 b.Goos = nonEmpty 1397 b.Goarch = nonEmpty 1398 b.Goarm = nonEmpty 1399 b.Gomips = nonEmpty 1400 b.Goamd64 = nonEmpty 1401 b.Ignore = []config.IgnoredBuild{{Goos: "linux"}} 1402 }, 1403 } { 1404 t.Run(name, func(t *testing.T) { 1405 b := config.Build{ 1406 Targets: nonEmpty, 1407 } 1408 fn(&b) 1409 require.True(t, warnIfTargetsAndOtherOptionTogether(b)) 1410 }) 1411 } 1412 } 1413 1414 func TestInvalidGoBinaryTpl(t *testing.T) { 1415 folder := testlib.Mktmp(t) 1416 require.NoError(t, os.Mkdir(filepath.Join(folder, ".go"), 0o755)) 1417 writeGoodMain(t, folder) 1418 ctx := testctx.NewWithCfg(config.Project{ 1419 Builds: []config.Build{ 1420 { 1421 Targets: []string{runtimeTarget}, 1422 GoBinary: "{{.Foo}}", 1423 Command: "build", 1424 }, 1425 }, 1426 }) 1427 build := ctx.Config.Builds[0] 1428 testlib.RequireTemplateError(t, Default.Build(ctx, build, api.Options{ 1429 Target: runtimeTarget, 1430 Name: build.Binary, 1431 Path: filepath.Join("dist", runtimeTarget, build.Binary), 1432 Ext: "", 1433 })) 1434 } 1435 1436 // 1437 // Helpers 1438 // 1439 1440 func writeMainWithoutMainFunc(t *testing.T, folder string) { 1441 t.Helper() 1442 require.NoError(t, os.WriteFile( 1443 filepath.Join(folder, "main.go"), 1444 []byte("package main\nconst a = 2\nfunc notMain() {println(0)}"), 1445 0o644, 1446 )) 1447 } 1448 1449 func writeGoodMain(t *testing.T, folder string) { 1450 t.Helper() 1451 require.NoError(t, os.WriteFile( 1452 filepath.Join(folder, "main.go"), 1453 []byte("package main\nvar a = 1\nfunc main() {println(0)}"), 1454 0o644, 1455 )) 1456 } 1457 1458 func writeTest(t *testing.T, folder string) { 1459 t.Helper() 1460 require.NoError(t, os.WriteFile( 1461 filepath.Join(folder, "main_test.go"), 1462 []byte("package main\nimport\"testing\"\nfunc TestFoo(t *testing.T) {t.Log(\"OK\")}"), 1463 0o644, 1464 )) 1465 require.NoError(t, os.WriteFile( 1466 filepath.Join(folder, "go.mod"), 1467 []byte("module foo\n"), 1468 0o666, 1469 )) 1470 }