github.com/amane3/goreleaser@v0.182.0/internal/pipe/build/build_test.go (about) 1 package build 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "testing" 10 11 "github.com/amane3/goreleaser/internal/artifact" 12 "github.com/amane3/goreleaser/internal/testlib" 13 "github.com/amane3/goreleaser/internal/tmpl" 14 api "github.com/amane3/goreleaser/pkg/build" 15 "github.com/amane3/goreleaser/pkg/config" 16 "github.com/amane3/goreleaser/pkg/context" 17 "github.com/stretchr/testify/require" 18 ) 19 20 var errFailedBuild = errors.New("fake builder failed") 21 var errFailedDefault = errors.New("fake builder defaults failed") 22 23 type fakeBuilder struct { 24 fail bool 25 failDefault bool 26 } 27 28 func (f *fakeBuilder) WithDefaults(build config.Build) (config.Build, error) { 29 if f.failDefault { 30 return build, errFailedDefault 31 } 32 return build, nil 33 } 34 35 func (f *fakeBuilder) Build(ctx *context.Context, build config.Build, options api.Options) error { 36 if f.fail { 37 return errFailedBuild 38 } 39 if err := os.MkdirAll(filepath.Dir(options.Path), 0755); err != nil { 40 return err 41 } 42 if err := ioutil.WriteFile(options.Path, []byte("foo"), 0755); err != nil { 43 return err 44 } 45 ctx.Artifacts.Add(&artifact.Artifact{ 46 Name: options.Name, 47 }) 48 return nil 49 } 50 51 func init() { 52 api.Register("fake", &fakeBuilder{}) 53 api.Register("fakeFail", &fakeBuilder{ 54 fail: true, 55 }) 56 api.Register("fakeFailDefault", &fakeBuilder{ 57 failDefault: true, 58 }) 59 } 60 61 func TestPipeDescription(t *testing.T) { 62 require.NotEmpty(t, Pipe{}.String()) 63 } 64 65 func TestBuild(t *testing.T) { 66 var folder = testlib.Mktmp(t) 67 var config = config.Project{ 68 Dist: folder, 69 Builds: []config.Build{ 70 { 71 Lang: "fake", 72 Binary: "testing.v{{.Version}}", 73 Flags: []string{"-n"}, 74 Env: []string{"BLAH=1"}, 75 }, 76 }, 77 } 78 var ctx = &context.Context{ 79 Artifacts: artifact.New(), 80 Git: context.GitInfo{ 81 CurrentTag: "v1.2.3", 82 Commit: "123", 83 }, 84 Version: "1.2.3", 85 Config: config, 86 } 87 opts, err := buildOptionsForTarget(ctx, ctx.Config.Builds[0], "darwin_amd64") 88 require.NoError(t, err) 89 error := doBuild(ctx, ctx.Config.Builds[0], *opts) 90 require.NoError(t, error) 91 } 92 93 func TestRunPipe(t *testing.T) { 94 var folder = testlib.Mktmp(t) 95 var config = config.Project{ 96 Dist: folder, 97 Builds: []config.Build{ 98 { 99 Lang: "fake", 100 Binary: "testing", 101 Flags: []string{"-v"}, 102 Ldflags: []string{"-X main.test=testing"}, 103 Targets: []string{"whatever"}, 104 }, 105 }, 106 } 107 var ctx = context.New(config) 108 ctx.Git.CurrentTag = "2.4.5" 109 require.NoError(t, Pipe{}.Run(ctx)) 110 require.Equal(t, ctx.Artifacts.List(), []*artifact.Artifact{{ 111 Name: "testing", 112 }}) 113 } 114 115 func TestRunFullPipe(t *testing.T) { 116 var folder = testlib.Mktmp(t) 117 var pre = filepath.Join(folder, "pre") 118 var post = filepath.Join(folder, "post") 119 var config = config.Project{ 120 Builds: []config.Build{ 121 { 122 ID: "build1", 123 Lang: "fake", 124 Binary: "testing", 125 Flags: []string{"-v"}, 126 Ldflags: []string{"-X main.test=testing"}, 127 Hooks: config.HookConfig{ 128 Pre: []config.BuildHook{ 129 {Cmd: "touch " + pre}, 130 }, 131 Post: []config.BuildHook{ 132 {Cmd: "touch " + post}, 133 }, 134 }, 135 Targets: []string{"whatever"}, 136 }, 137 }, 138 Dist: folder, 139 } 140 var ctx = context.New(config) 141 ctx.Git.CurrentTag = "2.4.5" 142 require.NoError(t, Pipe{}.Run(ctx)) 143 require.Equal(t, ctx.Artifacts.List(), []*artifact.Artifact{{ 144 Name: "testing", 145 }}) 146 require.FileExists(t, post) 147 require.FileExists(t, pre) 148 require.FileExists(t, filepath.Join(folder, "build1_whatever", "testing")) 149 } 150 151 func TestRunFullPipeFail(t *testing.T) { 152 var folder = testlib.Mktmp(t) 153 var pre = filepath.Join(folder, "pre") 154 var post = filepath.Join(folder, "post") 155 var config = config.Project{ 156 Dist: folder, 157 Builds: []config.Build{ 158 { 159 Lang: "fakeFail", 160 Binary: "testing", 161 Flags: []string{"-v"}, 162 Ldflags: []string{"-X main.test=testing"}, 163 Hooks: config.HookConfig{ 164 Pre: []config.BuildHook{ 165 {Cmd: "touch " + pre}, 166 }, 167 Post: []config.BuildHook{ 168 {Cmd: "touch " + post}, 169 }, 170 }, 171 Targets: []string{"whatever"}, 172 }, 173 }, 174 } 175 var ctx = context.New(config) 176 ctx.Git.CurrentTag = "2.4.5" 177 require.EqualError(t, Pipe{}.Run(ctx), errFailedBuild.Error()) 178 require.Empty(t, ctx.Artifacts.List()) 179 require.FileExists(t, pre) 180 } 181 182 func TestRunPipeFailingHooks(t *testing.T) { 183 var folder = testlib.Mktmp(t) 184 var cfg = config.Project{ 185 Dist: folder, 186 Builds: []config.Build{ 187 { 188 Lang: "fake", 189 Binary: "hooks", 190 Hooks: config.HookConfig{}, 191 Targets: []string{"whatever"}, 192 }, 193 }, 194 } 195 t.Run("pre-hook", func(t *testing.T) { 196 var ctx = context.New(cfg) 197 ctx.Git.CurrentTag = "2.3.4" 198 ctx.Config.Builds[0].Hooks.Pre = []config.BuildHook{{Cmd: "exit 1"}} 199 ctx.Config.Builds[0].Hooks.Post = []config.BuildHook{{Cmd: "echo post"}} 200 require.EqualError(t, Pipe{}.Run(ctx), `pre hook failed: "": exec: "exit": executable file not found in $PATH`) 201 }) 202 t.Run("post-hook", func(t *testing.T) { 203 var ctx = context.New(cfg) 204 ctx.Git.CurrentTag = "2.3.4" 205 ctx.Config.Builds[0].Hooks.Pre = []config.BuildHook{{Cmd: "echo pre"}} 206 ctx.Config.Builds[0].Hooks.Post = []config.BuildHook{{Cmd: "exit 1"}} 207 require.EqualError(t, Pipe{}.Run(ctx), `post hook failed: "": exec: "exit": executable file not found in $PATH`) 208 }) 209 } 210 211 func TestDefaultNoBuilds(t *testing.T) { 212 var ctx = &context.Context{ 213 Config: config.Project{}, 214 } 215 require.NoError(t, Pipe{}.Default(ctx)) 216 } 217 218 func TestDefaultFail(t *testing.T) { 219 var folder = testlib.Mktmp(t) 220 var config = config.Project{ 221 Dist: folder, 222 Builds: []config.Build{ 223 { 224 Lang: "fakeFailDefault", 225 }, 226 }, 227 } 228 var ctx = context.New(config) 229 require.EqualError(t, Pipe{}.Default(ctx), errFailedDefault.Error()) 230 require.Empty(t, ctx.Artifacts.List()) 231 } 232 233 func TestDefaultExpandEnv(t *testing.T) { 234 require.NoError(t, os.Setenv("XBAR", "FOOBAR")) 235 var ctx = &context.Context{ 236 Config: config.Project{ 237 Builds: []config.Build{ 238 { 239 Env: []string{ 240 "XFOO=bar_$XBAR", 241 }, 242 }, 243 }, 244 }, 245 } 246 require.NoError(t, Pipe{}.Default(ctx)) 247 var env = ctx.Config.Builds[0].Env[0] 248 require.Equal(t, "XFOO=bar_FOOBAR", env) 249 } 250 251 func TestDefaultEmptyBuild(t *testing.T) { 252 var ctx = &context.Context{ 253 Config: config.Project{ 254 ProjectName: "foo", 255 Builds: []config.Build{ 256 {}, 257 }, 258 }, 259 } 260 require.NoError(t, Pipe{}.Default(ctx)) 261 var build = ctx.Config.Builds[0] 262 require.Equal(t, ctx.Config.ProjectName, build.ID) 263 require.Equal(t, ctx.Config.ProjectName, build.Binary) 264 require.Equal(t, ".", build.Dir) 265 require.Equal(t, ".", build.Main) 266 require.Equal(t, []string{"linux", "darwin"}, build.Goos) 267 require.Equal(t, []string{"amd64", "386"}, build.Goarch) 268 require.Equal(t, []string{"6"}, build.Goarm) 269 require.Len(t, build.Ldflags, 1) 270 require.Equal(t, "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser", build.Ldflags[0]) 271 } 272 273 func TestDefaultBuildID(t *testing.T) { 274 var ctx = &context.Context{ 275 Config: config.Project{ 276 ProjectName: "foo", 277 Builds: []config.Build{ 278 { 279 Binary: "{{.Env.FOO}}", 280 }, 281 { 282 Binary: "bar", 283 }, 284 }, 285 }, 286 } 287 require.EqualError(t, Pipe{}.Default(ctx), "found 2 builds with the ID 'foo', please fix your config") 288 var build = ctx.Config.Builds[0] 289 require.Equal(t, ctx.Config.ProjectName, build.ID) 290 } 291 292 func TestSeveralBuildsWithTheSameID(t *testing.T) { 293 var ctx = &context.Context{ 294 Config: config.Project{ 295 Builds: []config.Build{ 296 { 297 ID: "a", 298 Binary: "bar", 299 }, 300 { 301 ID: "a", 302 Binary: "foo", 303 }, 304 }, 305 }, 306 } 307 require.EqualError(t, Pipe{}.Default(ctx), "found 2 builds with the ID 'a', please fix your config") 308 } 309 310 func TestDefaultPartialBuilds(t *testing.T) { 311 var ctx = &context.Context{ 312 Config: config.Project{ 313 Builds: []config.Build{ 314 { 315 ID: "build1", 316 Binary: "bar", 317 Goos: []string{"linux"}, 318 Main: "./cmd/main.go", 319 }, 320 { 321 ID: "build2", 322 Binary: "foo", 323 Dir: "baz", 324 Ldflags: []string{"-s -w"}, 325 Goarch: []string{"386"}, 326 }, 327 }, 328 }, 329 } 330 require.NoError(t, Pipe{}.Default(ctx)) 331 t.Run("build0", func(t *testing.T) { 332 var build = ctx.Config.Builds[0] 333 require.Equal(t, "bar", build.Binary) 334 require.Equal(t, ".", build.Dir) 335 require.Equal(t, "./cmd/main.go", build.Main) 336 require.Equal(t, []string{"linux"}, build.Goos) 337 require.Equal(t, []string{"amd64", "386"}, build.Goarch) 338 require.Equal(t, []string{"6"}, build.Goarm) 339 require.Len(t, build.Ldflags, 1) 340 require.Equal(t, "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser", build.Ldflags[0]) 341 }) 342 t.Run("build1", func(t *testing.T) { 343 var build = ctx.Config.Builds[1] 344 require.Equal(t, "foo", build.Binary) 345 require.Equal(t, ".", build.Main) 346 require.Equal(t, "baz", build.Dir) 347 require.Equal(t, []string{"linux", "darwin"}, build.Goos) 348 require.Equal(t, []string{"386"}, build.Goarch) 349 require.Equal(t, []string{"6"}, build.Goarm) 350 require.Len(t, build.Ldflags, 1) 351 require.Equal(t, "-s -w", build.Ldflags[0]) 352 }) 353 } 354 355 func TestDefaultFillSingleBuild(t *testing.T) { 356 testlib.Mktmp(t) 357 358 var ctx = &context.Context{ 359 Config: config.Project{ 360 ProjectName: "foo", 361 SingleBuild: config.Build{ 362 Main: "testreleaser", 363 }, 364 }, 365 } 366 require.NoError(t, Pipe{}.Default(ctx)) 367 require.Len(t, ctx.Config.Builds, 1) 368 require.Equal(t, ctx.Config.Builds[0].Binary, "foo") 369 } 370 371 func TestDefaultFailSingleBuild(t *testing.T) { 372 var folder = testlib.Mktmp(t) 373 var config = config.Project{ 374 Dist: folder, 375 SingleBuild: config.Build{ 376 Lang: "fakeFailDefault", 377 }, 378 } 379 var ctx = context.New(config) 380 require.EqualError(t, Pipe{}.Default(ctx), errFailedDefault.Error()) 381 require.Empty(t, ctx.Artifacts.List()) 382 } 383 384 func TestSkipBuild(t *testing.T) { 385 var folder = testlib.Mktmp(t) 386 var config = config.Project{ 387 Dist: folder, 388 Builds: []config.Build{ 389 { 390 Skip: true, 391 }, 392 }, 393 } 394 var ctx = context.New(config) 395 ctx.Git.CurrentTag = "2.4.5" 396 require.NoError(t, Pipe{}.Run(ctx)) 397 require.Len(t, ctx.Artifacts.List(), 0) 398 } 399 400 func TestExtWindows(t *testing.T) { 401 require.Equal(t, ".exe", extFor("windows_amd64", config.FlagArray{})) 402 require.Equal(t, ".exe", extFor("windows_386", config.FlagArray{})) 403 require.Equal(t, ".exe", extFor("windows_amd64", config.FlagArray{"-tags=dev", "-v"})) 404 require.Equal(t, ".dll", extFor("windows_amd64", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-shared"})) 405 require.Equal(t, ".dll", extFor("windows_386", config.FlagArray{"-buildmode=c-shared"})) 406 require.Equal(t, ".lib", extFor("windows_amd64", config.FlagArray{"-buildmode=c-archive"})) 407 require.Equal(t, ".lib", extFor("windows_386", config.FlagArray{"-tags=dev", "-v", "-buildmode=c-archive"})) 408 } 409 410 func TestExtWasm(t *testing.T) { 411 require.Equal(t, ".wasm", extFor("js_wasm", config.FlagArray{})) 412 } 413 414 func TestExtOthers(t *testing.T) { 415 require.Empty(t, "", extFor("linux_amd64", config.FlagArray{})) 416 require.Empty(t, "", extFor("linuxwin_386", config.FlagArray{})) 417 require.Empty(t, "", extFor("winasdasd_sad", config.FlagArray{})) 418 } 419 420 func TestTemplate(t *testing.T) { 421 var ctx = context.New(config.Project{}) 422 ctx.Git = context.GitInfo{ 423 CurrentTag: "v1.2.3", 424 Commit: "123", 425 } 426 ctx.Version = "1.2.3" 427 ctx.Env = map[string]string{"FOO": "123"} 428 binary, err := tmpl.New(ctx). 429 Apply(`-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}"`) 430 require.NoError(t, err) 431 require.Contains(t, binary, "-s -w") 432 require.Contains(t, binary, "-X main.version=1.2.3") 433 require.Contains(t, binary, "-X main.tag=v1.2.3") 434 require.Contains(t, binary, "-X main.commit=123") 435 require.Contains(t, binary, "-X main.date=") 436 require.Contains(t, binary, `-X "main.foo=123"`) 437 } 438 439 func TestRunHookEnvs(t *testing.T) { 440 var tmp = testlib.Mktmp(t) 441 442 var build = config.Build{ 443 Env: []string{ 444 fmt.Sprintf("FOO=%s/foo", tmp), 445 fmt.Sprintf("BAR=%s/bar", tmp), 446 }, 447 } 448 449 var opts = api.Options{ 450 Name: "binary-name", 451 Path: "./binary-name", 452 Target: "darwin_amd64", 453 } 454 455 simpleHook := func(cmd string) config.BuildHooks { 456 return []config.BuildHook{{Cmd: cmd}} 457 } 458 459 t.Run("valid cmd template with ctx env", func(t *testing.T) { 460 var err = runHook(context.New(config.Project{ 461 Builds: []config.Build{ 462 build, 463 }, 464 Env: []string{ 465 fmt.Sprintf("CTXFOO=%s/foo", tmp), 466 }, 467 }), opts, []string{}, simpleHook("touch {{ .Env.CTXFOO }}")) 468 require.NoError(t, err) 469 require.FileExists(t, filepath.Join(tmp, "foo")) 470 }) 471 472 t.Run("valid cmd template with build env", func(t *testing.T) { 473 var err = runHook(context.New(config.Project{ 474 Builds: []config.Build{ 475 build, 476 }, 477 }), opts, build.Env, simpleHook("touch {{ .Env.FOO }}")) 478 require.NoError(t, err) 479 require.FileExists(t, filepath.Join(tmp, "foo")) 480 }) 481 482 t.Run("valid cmd template with hook env", func(t *testing.T) { 483 var err = runHook(context.New(config.Project{ 484 Builds: []config.Build{ 485 build, 486 }, 487 }), opts, []string{}, []config.BuildHook{{ 488 Cmd: "touch {{ .Env.HOOK_ONLY_FOO }}", 489 Env: []string{ 490 fmt.Sprintf("HOOK_ONLY_FOO=%s/hook_only", tmp), 491 }, 492 }}) 493 require.NoError(t, err) 494 require.FileExists(t, filepath.Join(tmp, "hook_only")) 495 }) 496 497 t.Run("valid cmd template with ctx and build env", func(t *testing.T) { 498 var err = runHook(context.New(config.Project{ 499 Builds: []config.Build{ 500 build, 501 }, 502 Env: []string{ 503 fmt.Sprintf("OVER_FOO=%s/ctx_over_build", tmp), 504 }, 505 }), opts, []string{ 506 fmt.Sprintf("OVER_FOO=%s/build_over_ctx", tmp), 507 }, simpleHook("touch {{ .Env.OVER_FOO }}")) 508 require.NoError(t, err) 509 510 require.FileExists(t, filepath.Join(tmp, "build_over_ctx")) 511 require.NoFileExists(t, filepath.Join(tmp, "ctx_over_build")) 512 }) 513 514 t.Run("valid cmd template with ctx and hook env", func(t *testing.T) { 515 var err = runHook(context.New(config.Project{ 516 Builds: []config.Build{ 517 build, 518 }, 519 Env: []string{ 520 fmt.Sprintf("CTX_OR_HOOK_FOO=%s/ctx_over_hook", tmp), 521 }, 522 }), opts, []string{}, []config.BuildHook{{ 523 Cmd: "touch {{ .Env.CTX_OR_HOOK_FOO }}", 524 Env: []string{ 525 fmt.Sprintf("CTX_OR_HOOK_FOO=%s/hook_over_ctx", tmp), 526 }, 527 }}) 528 require.NoError(t, err) 529 require.FileExists(t, filepath.Join(tmp, "hook_over_ctx")) 530 require.NoFileExists(t, filepath.Join(tmp, "ctx_over_hook")) 531 }) 532 533 t.Run("valid cmd template with build and hook env", func(t *testing.T) { 534 var err = runHook(context.New(config.Project{ 535 Builds: []config.Build{ 536 build, 537 }, 538 }), opts, []string{ 539 fmt.Sprintf("BUILD_OR_HOOK_FOO=%s/build_over_hook", tmp), 540 }, []config.BuildHook{{ 541 Cmd: "touch {{ .Env.BUILD_OR_HOOK_FOO }}", 542 Env: []string{ 543 fmt.Sprintf("BUILD_OR_HOOK_FOO=%s/hook_over_build", tmp), 544 }, 545 }}) 546 require.NoError(t, err) 547 require.FileExists(t, filepath.Join(tmp, "hook_over_build")) 548 require.NoFileExists(t, filepath.Join(tmp, "build_over_hook")) 549 }) 550 551 t.Run("valid cmd template with ctx, build and hook env", func(t *testing.T) { 552 var err = runHook(context.New(config.Project{ 553 Builds: []config.Build{ 554 build, 555 }, 556 Env: []string{ 557 fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/ctx_wins", tmp), 558 }, 559 }), opts, []string{ 560 fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/build_wins", tmp), 561 }, []config.BuildHook{{ 562 Cmd: "touch {{ .Env.CTX_OR_BUILD_OR_HOOK_FOO }}", 563 Env: []string{ 564 fmt.Sprintf("CTX_OR_BUILD_OR_HOOK_FOO=%s/hook_wins", tmp), 565 }, 566 }}) 567 require.NoError(t, err) 568 require.FileExists(t, filepath.Join(tmp, "hook_wins")) 569 require.NoFileExists(t, filepath.Join(tmp, "ctx_wins")) 570 require.NoFileExists(t, filepath.Join(tmp, "build_wins")) 571 }) 572 573 t.Run("invalid cmd template", func(t *testing.T) { 574 var err = runHook(context.New(config.Project{ 575 Builds: []config.Build{ 576 build, 577 }, 578 }), opts, build.Env, simpleHook("touch {{ .Env.FOOss }}")) 579 require.EqualError(t, err, `template: tmpl:1:13: executing "tmpl" at <.Env.FOOss>: map has no entry for key "FOOss"`) 580 }) 581 582 t.Run("invalid dir template", func(t *testing.T) { 583 var err = runHook(context.New(config.Project{ 584 Builds: []config.Build{ 585 build, 586 }, 587 }), opts, build.Env, []config.BuildHook{{ 588 Cmd: "echo something", 589 Dir: "{{ .Env.INVALID_ENV }}", 590 }}) 591 require.EqualError(t, err, `template: tmpl:1:7: executing "tmpl" at <.Env.INVALID_ENV>: map has no entry for key "INVALID_ENV"`) 592 }) 593 594 t.Run("invalid hook env template", func(t *testing.T) { 595 var err = runHook(context.New(config.Project{ 596 Builds: []config.Build{ 597 build, 598 }, 599 }), opts, build.Env, []config.BuildHook{{ 600 Cmd: "echo something", 601 Env: []string{ 602 "TEST={{ .Env.MISSING_ENV }}", 603 }, 604 }}) 605 require.EqualError(t, err, `template: tmpl:1:12: executing "tmpl" at <.Env.MISSING_ENV>: map has no entry for key "MISSING_ENV"`) 606 }) 607 608 t.Run("build env inside shell", func(t *testing.T) { 609 var shell = `#!/bin/sh -e 610 touch "$BAR"` 611 err := ioutil.WriteFile(filepath.Join(tmp, "test.sh"), []byte(shell), 0750) 612 require.NoError(t, err) 613 err = runHook(context.New(config.Project{ 614 Builds: []config.Build{ 615 build, 616 }, 617 }), opts, build.Env, simpleHook("sh test.sh")) 618 require.NoError(t, err) 619 require.FileExists(t, filepath.Join(tmp, "bar")) 620 }) 621 } 622 623 func TestBuild_hooksKnowGoosGoarch(t *testing.T) { 624 var tmpDir = testlib.Mktmp(t) 625 build := config.Build{ 626 Lang: "fake", 627 Goarch: []string{"amd64"}, 628 Goos: []string{"linux"}, 629 Binary: "testing-goos-goarch.v{{.Version}}", 630 Targets: []string{ 631 "linux_amd64", 632 }, 633 Hooks: config.HookConfig{ 634 Pre: []config.BuildHook{ 635 {Cmd: "touch pre-hook-{{.Arch}}-{{.Os}}", Dir: tmpDir}, 636 }, 637 Post: config.BuildHooks{ 638 {Cmd: "touch post-hook-{{.Arch}}-{{.Os}}", Dir: tmpDir}, 639 }, 640 }, 641 } 642 643 ctx := context.New(config.Project{ 644 Builds: []config.Build{ 645 build, 646 }, 647 }) 648 err := runPipeOnBuild(ctx, build) 649 require.NoError(t, err) 650 require.FileExists(t, filepath.Join(tmpDir, "pre-hook-amd64-linux")) 651 require.FileExists(t, filepath.Join(tmpDir, "post-hook-amd64-linux")) 652 } 653 654 func TestPipeOnBuild_hooksRunPerTarget(t *testing.T) { 655 var tmpDir = testlib.Mktmp(t) 656 657 build := config.Build{ 658 Lang: "fake", 659 Binary: "testing.v{{.Version}}", 660 Targets: []string{ 661 "linux_amd64", 662 "darwin_amd64", 663 "windows_amd64", 664 }, 665 Hooks: config.HookConfig{ 666 Pre: []config.BuildHook{ 667 {Cmd: "touch pre-hook-{{.Target}}", Dir: tmpDir}, 668 }, 669 Post: config.BuildHooks{ 670 {Cmd: "touch post-hook-{{.Target}}", Dir: tmpDir}, 671 }, 672 }, 673 } 674 ctx := context.New(config.Project{ 675 Builds: []config.Build{ 676 build, 677 }, 678 }) 679 err := runPipeOnBuild(ctx, build) 680 require.NoError(t, err) 681 require.FileExists(t, filepath.Join(tmpDir, "pre-hook-linux_amd64")) 682 require.FileExists(t, filepath.Join(tmpDir, "pre-hook-darwin_amd64")) 683 require.FileExists(t, filepath.Join(tmpDir, "pre-hook-windows_amd64")) 684 require.FileExists(t, filepath.Join(tmpDir, "post-hook-linux_amd64")) 685 require.FileExists(t, filepath.Join(tmpDir, "post-hook-darwin_amd64")) 686 require.FileExists(t, filepath.Join(tmpDir, "post-hook-windows_amd64")) 687 } 688 689 func TestPipeOnBuild_invalidBinaryTpl(t *testing.T) { 690 build := config.Build{ 691 Lang: "fake", 692 Binary: "testing.v{{.XYZ}}", 693 Targets: []string{ 694 "linux_amd64", 695 }, 696 } 697 ctx := context.New(config.Project{ 698 Builds: []config.Build{ 699 build, 700 }, 701 }) 702 err := runPipeOnBuild(ctx, build) 703 require.EqualError(t, err, `template: tmpl:1:11: executing "tmpl" at <.XYZ>: map has no entry for key "XYZ"`) 704 } 705 706 func TestBuildOptionsForTarget(t *testing.T) { 707 var tmpDir = testlib.Mktmp(t) 708 709 build := config.Build{ 710 ID: "testid", 711 Binary: "testbinary", 712 Targets: []string{ 713 "linux_amd64", 714 "darwin_amd64", 715 "windows_amd64", 716 }, 717 } 718 ctx := context.New(config.Project{ 719 Dist: tmpDir, 720 Builds: []config.Build{build}, 721 }) 722 opts, err := buildOptionsForTarget(ctx, build, "linux_amd64") 723 require.NoError(t, err) 724 require.Equal(t, &api.Options{ 725 Name: "testbinary", 726 Path: filepath.Join(tmpDir, "testid_linux_amd64", "testbinary"), 727 Target: "linux_amd64", 728 Os: "linux", 729 Arch: "amd64", 730 }, opts) 731 } 732 733 func TestHookComplex(t *testing.T) { 734 var tmp = testlib.Mktmp(t) 735 736 require.NoError(t, runHook(context.New(config.Project{}), api.Options{}, []string{}, config.BuildHooks{ 737 { 738 Cmd: `bash -c "touch foo"`, 739 }, 740 { 741 Cmd: `bash -c "touch \"bar\""`, 742 }, 743 })) 744 745 require.FileExists(t, filepath.Join(tmp, "foo")) 746 require.FileExists(t, filepath.Join(tmp, "bar")) 747 } 748 749 func TestHookInvalidShelCommand(t *testing.T) { 750 require.Error(t, runHook(context.New(config.Project{}), api.Options{}, []string{}, config.BuildHooks{ 751 { 752 Cmd: `bash -c "echo \"unterminated command\"`, 753 }, 754 })) 755 } 756 757 func TestRunHookFailWithLogs(t *testing.T) { 758 var folder = testlib.Mktmp(t) 759 var config = config.Project{ 760 Dist: folder, 761 Builds: []config.Build{ 762 { 763 Lang: "fakeFail", 764 Binary: "testing", 765 Flags: []string{"-v"}, 766 Hooks: config.HookConfig{ 767 Pre: []config.BuildHook{ 768 {Cmd: "sh -c 'echo foo; exit 1'"}, 769 }, 770 }, 771 Targets: []string{"whatever"}, 772 }, 773 }, 774 } 775 var ctx = context.New(config) 776 ctx.Git.CurrentTag = "2.4.5" 777 require.EqualError(t, Pipe{}.Run(ctx), "pre hook failed: \"foo\\n\": exit status 1") 778 require.Empty(t, ctx.Artifacts.List()) 779 }