github.com/amane3/goreleaser@v0.182.0/internal/pipe/docker/docker_test.go (about) 1 package docker 2 3 import ( 4 "flag" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strings" 11 "syscall" 12 "testing" 13 14 "github.com/amane3/goreleaser/internal/artifact" 15 "github.com/amane3/goreleaser/internal/pipe" 16 "github.com/amane3/goreleaser/internal/testlib" 17 "github.com/amane3/goreleaser/pkg/config" 18 "github.com/amane3/goreleaser/pkg/context" 19 "github.com/stretchr/testify/require" 20 ) 21 22 var it = flag.Bool("it", false, "push images to docker hub") 23 var registry = "localhost:5000/" 24 var altRegistry = "localhost:5050/" 25 26 func TestMain(m *testing.M) { 27 flag.Parse() 28 if *it { 29 registry = "docker.io/" 30 } 31 os.Exit(m.Run()) 32 } 33 34 func start(t *testing.T) { 35 if *it { 36 return 37 } 38 if out, err := exec.Command( 39 "docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2", 40 ).CombinedOutput(); err != nil { 41 t.Log("failed to start docker registry", string(out), err) 42 t.FailNow() 43 } 44 if out, err := exec.Command( 45 "docker", "run", "-d", "-p", "5050:5000", "--name", "alt_registry", "registry:2", 46 ).CombinedOutput(); err != nil { 47 t.Log("failed to start alternate docker registry", string(out), err) 48 t.FailNow() 49 } 50 } 51 52 func killAndRm(t *testing.T) { 53 if *it { 54 return 55 } 56 t.Log("killing registry") 57 _ = exec.Command("docker", "kill", "registry").Run() 58 _ = exec.Command("docker", "rm", "registry").Run() 59 _ = exec.Command("docker", "kill", "alt_registry").Run() 60 _ = exec.Command("docker", "rm", "alt_registry").Run() 61 } 62 63 // TODO: this test is too big... split in smaller tests? Mainly the manifest ones... 64 func TestRunPipe(t *testing.T) { 65 type errChecker func(*testing.T, error) 66 var shouldErr = func(msg string) errChecker { 67 return func(t *testing.T, err error) { 68 require.Error(t, err) 69 require.Contains(t, err.Error(), msg) 70 } 71 } 72 var shouldNotErr = func(t *testing.T, err error) { 73 require.NoError(t, err) 74 } 75 type imageLabelFinder func(*testing.T, int) 76 var shouldFindImagesWithLabels = func(image string, filters ...string) func(*testing.T, int) { 77 return func(t *testing.T, count int) { 78 for _, filter := range filters { 79 output, err := exec.Command( 80 "docker", "images", "-q", "*/"+image, 81 "--filter", filter, 82 ).CombinedOutput() 83 require.NoError(t, err) 84 lines := strings.Split(strings.TrimSpace(string(output)), "\n") 85 require.Equal(t, count, len(lines)) 86 } 87 } 88 89 } 90 var noLabels = func(t *testing.T, count int) {} 91 92 var table = map[string]struct { 93 dockers []config.Docker 94 manifests []config.DockerManifest 95 env map[string]string 96 expect []string 97 assertImageLabels imageLabelFinder 98 assertError errChecker 99 pubAssertError errChecker 100 manifestAssertError errChecker 101 }{ 102 "multiarch": { 103 dockers: []config.Docker{ 104 { 105 ImageTemplates: []string{registry + "goreleaser/test_multiarch:test-amd64"}, 106 Goos: "linux", 107 Goarch: "amd64", 108 Dockerfile: "testdata/Dockerfile.arch", 109 Binaries: []string{"mybin"}, 110 BuildFlagTemplates: []string{"--build-arg", "ARCH=amd64"}, 111 }, 112 { 113 ImageTemplates: []string{registry + "goreleaser/test_multiarch:test-arm64v8"}, 114 Goos: "linux", 115 Goarch: "arm64", 116 Dockerfile: "testdata/Dockerfile.arch", 117 Binaries: []string{"mybin"}, 118 BuildFlagTemplates: []string{"--build-arg", "ARCH=arm64v8"}, 119 }, 120 }, 121 manifests: []config.DockerManifest{ 122 { 123 // XXX: fails if :latest https://github.com/docker/distribution/issues/3100 124 NameTemplate: registry + "goreleaser/test_multiarch:test", 125 ImageTemplates: []string{ 126 registry + "goreleaser/test_multiarch:test-amd64", 127 registry + "goreleaser/test_multiarch:test-arm64v8", 128 }, 129 CreateFlags: []string{"--insecure"}, 130 PushFlags: []string{"--insecure"}, 131 }, 132 }, 133 expect: []string{ 134 registry + "goreleaser/test_multiarch:test-amd64", 135 registry + "goreleaser/test_multiarch:test-arm64v8", 136 }, 137 assertError: shouldNotErr, 138 pubAssertError: shouldNotErr, 139 manifestAssertError: shouldNotErr, 140 assertImageLabels: noLabels, 141 }, 142 "multiarch image not found": { 143 dockers: []config.Docker{ 144 { 145 ImageTemplates: []string{registry + "goreleaser/test_multiarch_fail:latest-arm64v8"}, 146 Goos: "linux", 147 Goarch: "arm64", 148 Dockerfile: "testdata/Dockerfile.arch", 149 Binaries: []string{"mybin"}, 150 BuildFlagTemplates: []string{"--build-arg", "ARCH=arm64v8"}, 151 }, 152 }, 153 manifests: []config.DockerManifest{ 154 { 155 NameTemplate: registry + "goreleaser/test_multiarch_fail:test", 156 ImageTemplates: []string{registry + "goreleaser/test_multiarch_fail:latest-amd64"}, 157 CreateFlags: []string{"--insecure"}, 158 PushFlags: []string{"--insecure"}, 159 }, 160 }, 161 expect: []string{registry + "goreleaser/test_multiarch_fail:latest-arm64v8"}, 162 assertError: shouldNotErr, 163 pubAssertError: shouldNotErr, 164 manifestAssertError: shouldErr("failed to create docker manifest: localhost:5000/goreleaser/test_multiarch_fail:test"), 165 assertImageLabels: noLabels, 166 }, 167 "multiarch manifest template error": { 168 dockers: []config.Docker{ 169 { 170 ImageTemplates: []string{registry + "goreleaser/test_multiarch_manifest_tmpl_error"}, 171 Goos: "linux", 172 Goarch: "arm64", 173 Dockerfile: "testdata/Dockerfile", 174 Binaries: []string{"mybin"}, 175 }, 176 }, 177 manifests: []config.DockerManifest{ 178 { 179 NameTemplate: registry + "goreleaser/test_multiarch_manifest_tmpl_error:{{ .Goos }", 180 ImageTemplates: []string{registry + "goreleaser/test_multiarch_manifest_tmpl_error"}, 181 }, 182 }, 183 expect: []string{registry + "goreleaser/test_multiarch_manifest_tmpl_error"}, 184 assertError: shouldNotErr, 185 pubAssertError: shouldNotErr, 186 manifestAssertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`), 187 assertImageLabels: noLabels, 188 }, 189 "multiarch image template error": { 190 dockers: []config.Docker{ 191 { 192 ImageTemplates: []string{registry + "goreleaser/test_multiarch_img_tmpl_error"}, 193 Goos: "linux", 194 Goarch: "arm64", 195 Dockerfile: "testdata/Dockerfile", 196 Binaries: []string{"mybin"}, 197 }, 198 }, 199 manifests: []config.DockerManifest{ 200 { 201 NameTemplate: registry + "goreleaser/test_multiarch_img_tmpl_error", 202 ImageTemplates: []string{registry + "goreleaser/test_multiarch_img_tmpl_error:{{ .Goos }"}, 203 }, 204 }, 205 expect: []string{registry + "goreleaser/test_multiarch_img_tmpl_error"}, 206 assertError: shouldNotErr, 207 pubAssertError: shouldNotErr, 208 manifestAssertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`), 209 assertImageLabels: noLabels, 210 }, 211 "multiarch missing manifest name": { 212 dockers: []config.Docker{ 213 { 214 ImageTemplates: []string{registry + "goreleaser/test_multiarch_no_mainifest_name"}, 215 Goos: "linux", 216 Goarch: "arm64", 217 Dockerfile: "testdata/Dockerfile", 218 Binaries: []string{"mybin"}, 219 }, 220 }, 221 manifests: []config.DockerManifest{ 222 { 223 NameTemplate: " ", 224 ImageTemplates: []string{registry + "goreleaser/test_multiarch_no_mainifest_name"}, 225 }, 226 }, 227 expect: []string{registry + "goreleaser/test_multiarch_no_mainifest_name"}, 228 assertError: shouldNotErr, 229 pubAssertError: shouldNotErr, 230 manifestAssertError: testlib.AssertSkipped, 231 assertImageLabels: noLabels, 232 }, 233 "multiarch missing images": { 234 dockers: []config.Docker{ 235 { 236 ImageTemplates: []string{registry + "goreleaser/test_multiarch_no_mainifest_images"}, 237 Dockerfile: "testdata/Dockerfile", 238 Goos: "linux", 239 Goarch: "arm64", 240 Binaries: []string{"mybin"}, 241 }, 242 }, 243 manifests: []config.DockerManifest{ 244 { 245 NameTemplate: "ignored", 246 ImageTemplates: []string{" ", " ", ""}, 247 }, 248 }, 249 expect: []string{registry + "goreleaser/test_multiarch_no_mainifest_images"}, 250 assertError: shouldNotErr, 251 pubAssertError: shouldNotErr, 252 manifestAssertError: testlib.AssertSkipped, 253 assertImageLabels: noLabels, 254 }, 255 "valid": { 256 env: map[string]string{ 257 "FOO": "123", 258 }, 259 dockers: []config.Docker{ 260 { 261 ImageTemplates: []string{ 262 registry + "goreleaser/test_run_pipe:{{.Tag}}-{{.Env.FOO}}", 263 registry + "goreleaser/test_run_pipe:v{{.Major}}", 264 registry + "goreleaser/test_run_pipe:v{{.Major}}.{{.Minor}}", 265 registry + "goreleaser/test_run_pipe:commit-{{.Commit}}", 266 registry + "goreleaser/test_run_pipe:latest", 267 altRegistry + "goreleaser/test_run_pipe:{{.Tag}}-{{.Env.FOO}}", 268 altRegistry + "goreleaser/test_run_pipe:v{{.Major}}", 269 altRegistry + "goreleaser/test_run_pipe:v{{.Major}}.{{.Minor}}", 270 altRegistry + "goreleaser/test_run_pipe:commit-{{.Commit}}", 271 altRegistry + "goreleaser/test_run_pipe:latest", 272 }, 273 Goos: "linux", 274 Goarch: "amd64", 275 Dockerfile: "testdata/Dockerfile", 276 Binaries: []string{"mybin"}, 277 BuildFlagTemplates: []string{ 278 "--label=org.label-schema.schema-version=1.0", 279 "--label=org.label-schema.version={{.Version}}", 280 "--label=org.label-schema.vcs-ref={{.Commit}}", 281 "--label=org.label-schema.name={{.ProjectName}}", 282 "--build-arg=FRED={{.Tag}}", 283 }, 284 Files: []string{ 285 "testdata/extra_file.txt", 286 }, 287 }, 288 }, 289 expect: []string{ 290 registry + "goreleaser/test_run_pipe:v1.0.0-123", 291 registry + "goreleaser/test_run_pipe:v1", 292 registry + "goreleaser/test_run_pipe:v1.0", 293 registry + "goreleaser/test_run_pipe:commit-a1b2c3d4", 294 registry + "goreleaser/test_run_pipe:latest", 295 altRegistry + "goreleaser/test_run_pipe:v1.0.0-123", 296 altRegistry + "goreleaser/test_run_pipe:v1", 297 altRegistry + "goreleaser/test_run_pipe:v1.0", 298 altRegistry + "goreleaser/test_run_pipe:commit-a1b2c3d4", 299 altRegistry + "goreleaser/test_run_pipe:latest", 300 }, 301 assertImageLabels: shouldFindImagesWithLabels( 302 "goreleaser/test_run_pipe", 303 "label=org.label-schema.schema-version=1.0", 304 "label=org.label-schema.version=1.0.0", 305 "label=org.label-schema.vcs-ref=a1b2c3d4", 306 "label=org.label-schema.name=mybin", 307 ), 308 assertError: shouldNotErr, 309 pubAssertError: shouldNotErr, 310 manifestAssertError: shouldNotErr, 311 }, 312 "valid-with-builds": { 313 dockers: []config.Docker{ 314 { 315 ImageTemplates: []string{ 316 registry + "goreleaser/test_run_pipe_build:latest", 317 }, 318 Goos: "linux", 319 Goarch: "amd64", 320 Dockerfile: "testdata/Dockerfile", 321 Binaries: []string{"mybin"}, 322 Builds: []string{"mybin"}, 323 }, 324 }, 325 expect: []string{ 326 registry + "goreleaser/test_run_pipe_build:latest", 327 }, 328 assertImageLabels: noLabels, 329 assertError: shouldNotErr, 330 pubAssertError: shouldNotErr, 331 manifestAssertError: shouldNotErr, 332 }, 333 "multiple images with same extra file": { 334 dockers: []config.Docker{ 335 { 336 ImageTemplates: []string{ 337 registry + "goreleaser/multiplefiles1:latest", 338 }, 339 Goos: "linux", 340 Goarch: "amd64", 341 Dockerfile: "testdata/Dockerfile", 342 Binaries: []string{"mybin"}, 343 Files: []string{"testdata/extra_file.txt"}, 344 }, 345 { 346 ImageTemplates: []string{ 347 registry + "goreleaser/multiplefiles2:latest", 348 }, 349 Goos: "linux", 350 Goarch: "amd64", 351 Dockerfile: "testdata/Dockerfile", 352 Binaries: []string{"mybin"}, 353 Files: []string{"testdata/extra_file.txt"}, 354 }, 355 }, 356 expect: []string{ 357 registry + "goreleaser/multiplefiles1:latest", 358 registry + "goreleaser/multiplefiles2:latest", 359 }, 360 assertImageLabels: noLabels, 361 assertError: shouldNotErr, 362 pubAssertError: shouldNotErr, 363 manifestAssertError: shouldNotErr, 364 }, 365 "multiple images with same dockerfile": { 366 dockers: []config.Docker{ 367 { 368 ImageTemplates: []string{ 369 registry + "goreleaser/test_run_pipe:latest", 370 }, 371 Goos: "linux", 372 Goarch: "amd64", 373 Dockerfile: "testdata/Dockerfile", 374 Binaries: []string{"mybin"}, 375 }, 376 { 377 ImageTemplates: []string{ 378 registry + "goreleaser/test_run_pipe2:latest", 379 }, 380 Goos: "linux", 381 Goarch: "amd64", 382 Dockerfile: "testdata/Dockerfile", 383 Binaries: []string{"mybin"}, 384 }, 385 }, 386 assertImageLabels: noLabels, 387 expect: []string{ 388 registry + "goreleaser/test_run_pipe:latest", 389 registry + "goreleaser/test_run_pipe2:latest", 390 }, 391 assertError: shouldNotErr, 392 pubAssertError: shouldNotErr, 393 manifestAssertError: shouldNotErr, 394 }, 395 "valid_skip_push": { 396 dockers: []config.Docker{ 397 { 398 ImageTemplates: []string{ 399 registry + "goreleaser/test_run_pipe:latest", 400 }, 401 Goos: "linux", 402 Goarch: "amd64", 403 Dockerfile: "testdata/Dockerfile", 404 Binaries: []string{"mybin"}, 405 SkipPush: "true", 406 }, 407 }, 408 expect: []string{ 409 registry + "goreleaser/test_run_pipe:latest", 410 }, 411 assertImageLabels: noLabels, 412 assertError: testlib.AssertSkipped, 413 }, 414 "one_img_error_with_skip_push": { 415 dockers: []config.Docker{ 416 { 417 ImageTemplates: []string{ 418 registry + "goreleaser/one_img_error_with_skip_push:true", 419 }, 420 Goos: "linux", 421 Goarch: "amd64", 422 Dockerfile: "testdata/Dockerfile.true", 423 Binaries: []string{"mybin"}, 424 SkipPush: "true", 425 }, 426 { 427 ImageTemplates: []string{ 428 registry + "goreleaser/one_img_error_with_skip_push:false", 429 }, 430 Goos: "linux", 431 Goarch: "amd64", 432 Dockerfile: "testdata/Dockerfile.false", 433 Binaries: []string{"mybin"}, 434 SkipPush: "true", 435 }, 436 }, 437 expect: []string{ 438 registry + "goreleaser/one_img_error_with_skip_push:true", 439 }, 440 assertImageLabels: noLabels, 441 assertError: shouldErr("failed to build docker image"), 442 }, 443 "valid_no_latest": { 444 dockers: []config.Docker{ 445 { 446 ImageTemplates: []string{ 447 registry + "goreleaser/test_run_pipe:{{.Version}}", 448 }, 449 Goos: "linux", 450 Goarch: "amd64", 451 Dockerfile: "testdata/Dockerfile", 452 Binaries: []string{"mybin"}, 453 }, 454 }, 455 expect: []string{ 456 registry + "goreleaser/test_run_pipe:1.0.0", 457 }, 458 assertImageLabels: noLabels, 459 assertError: shouldNotErr, 460 pubAssertError: shouldNotErr, 461 manifestAssertError: shouldNotErr, 462 }, 463 "valid build args": { 464 dockers: []config.Docker{ 465 { 466 ImageTemplates: []string{ 467 registry + "goreleaser/test_build_args:latest", 468 }, 469 Goos: "linux", 470 Goarch: "amd64", 471 Dockerfile: "testdata/Dockerfile", 472 Binaries: []string{"mybin"}, 473 BuildFlagTemplates: []string{ 474 "--label=foo=bar", 475 }, 476 }, 477 }, 478 expect: []string{ 479 registry + "goreleaser/test_build_args:latest", 480 }, 481 assertImageLabels: noLabels, 482 assertError: shouldNotErr, 483 pubAssertError: shouldNotErr, 484 manifestAssertError: shouldNotErr, 485 }, 486 "bad build args": { 487 dockers: []config.Docker{ 488 { 489 ImageTemplates: []string{ 490 registry + "goreleaser/test_build_args:latest", 491 }, 492 Goos: "linux", 493 Goarch: "amd64", 494 Dockerfile: "testdata/Dockerfile", 495 Binaries: []string{"mybin"}, 496 BuildFlagTemplates: []string{ 497 "--bad-flag", 498 }, 499 }, 500 }, 501 assertImageLabels: noLabels, 502 assertError: shouldErr("unknown flag: --bad-flag"), 503 }, 504 "bad_dockerfile": { 505 dockers: []config.Docker{ 506 { 507 ImageTemplates: []string{ 508 registry + "goreleaser/bad_dockerfile:latest", 509 }, 510 Goos: "linux", 511 Goarch: "amd64", 512 Dockerfile: "testdata/Dockerfile.bad", 513 Binaries: []string{"mybin"}, 514 }, 515 }, 516 assertImageLabels: noLabels, 517 assertError: shouldErr("pull access denied for nope, repository does not exist"), 518 }, 519 "tag_template_error": { 520 dockers: []config.Docker{ 521 { 522 ImageTemplates: []string{ 523 registry + "goreleaser/test_run_pipe:{{.Tag}", 524 }, 525 Goos: "linux", 526 Goarch: "amd64", 527 Dockerfile: "testdata/Dockerfile", 528 Binaries: []string{"mybin"}, 529 }, 530 }, 531 assertImageLabels: noLabels, 532 assertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`), 533 }, 534 "build_flag_template_error": { 535 dockers: []config.Docker{ 536 { 537 ImageTemplates: []string{ 538 registry + "goreleaser/test_run_pipe:latest", 539 }, 540 Goos: "linux", 541 Goarch: "amd64", 542 Dockerfile: "testdata/Dockerfile", 543 Binaries: []string{"mybin"}, 544 BuildFlagTemplates: []string{ 545 "--label=tag={{.Tag}", 546 }, 547 }, 548 }, 549 assertImageLabels: noLabels, 550 assertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`), 551 }, 552 "missing_env_on_tag_template": { 553 dockers: []config.Docker{ 554 { 555 ImageTemplates: []string{ 556 registry + "goreleaser/test_run_pipe:{{.Env.NOPE}}", 557 }, 558 Goos: "linux", 559 Goarch: "amd64", 560 Dockerfile: "testdata/Dockerfile", 561 Binaries: []string{"mybin"}, 562 }, 563 }, 564 assertImageLabels: noLabels, 565 assertError: shouldErr(`template: tmpl:1:46: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`), 566 }, 567 "missing_env_on_build_flag_template": { 568 dockers: []config.Docker{ 569 { 570 ImageTemplates: []string{ 571 registry + "goreleaser/test_run_pipe:latest", 572 }, 573 Goos: "linux", 574 Goarch: "amd64", 575 Dockerfile: "testdata/Dockerfile", 576 Binaries: []string{"mybin"}, 577 BuildFlagTemplates: []string{ 578 "--label=nope={{.Env.NOPE}}", 579 }, 580 }, 581 }, 582 assertImageLabels: noLabels, 583 assertError: shouldErr(`template: tmpl:1:19: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`), 584 }, 585 "image_has_projectname_template_variable": { 586 dockers: []config.Docker{ 587 { 588 ImageTemplates: []string{ 589 registry + "goreleaser/{{.ProjectName}}:{{.Tag}}-{{.Env.FOO}}", 590 registry + "goreleaser/{{.ProjectName}}:latest", 591 }, 592 Goos: "linux", 593 Goarch: "amd64", 594 Dockerfile: "testdata/Dockerfile", 595 Binaries: []string{"mybin"}, 596 SkipPush: "true", 597 }, 598 }, 599 env: map[string]string{ 600 "FOO": "123", 601 }, 602 expect: []string{ 603 registry + "goreleaser/mybin:v1.0.0-123", 604 registry + "goreleaser/mybin:latest", 605 }, 606 assertImageLabels: noLabels, 607 assertError: testlib.AssertSkipped, 608 }, 609 "no_permissions": { 610 dockers: []config.Docker{ 611 { 612 ImageTemplates: []string{"docker.io/nope:latest"}, 613 Goos: "linux", 614 Goarch: "amd64", 615 Binaries: []string{"mybin"}, 616 Dockerfile: "testdata/Dockerfile", 617 }, 618 }, 619 expect: []string{ 620 "docker.io/nope:latest", 621 }, 622 assertImageLabels: noLabels, 623 assertError: shouldNotErr, 624 pubAssertError: shouldErr(`requested access to the resource is denied`), 625 manifestAssertError: shouldNotErr, 626 }, 627 "dockerfile_doesnt_exist": { 628 dockers: []config.Docker{ 629 { 630 ImageTemplates: []string{"whatever:latest"}, 631 Goos: "linux", 632 Goarch: "amd64", 633 Binaries: []string{"mybin"}, 634 Dockerfile: "testdata/Dockerfilezzz", 635 }, 636 }, 637 assertImageLabels: noLabels, 638 assertError: shouldErr(`failed to link dockerfile`), 639 }, 640 "extra_file_doesnt_exist": { 641 dockers: []config.Docker{ 642 { 643 ImageTemplates: []string{"whatever:latest"}, 644 Goos: "linux", 645 Goarch: "amd64", 646 Binaries: []string{"mybin"}, 647 Dockerfile: "testdata/Dockerfile", 648 Files: []string{ 649 "testdata/nope.txt", 650 }, 651 }, 652 }, 653 assertImageLabels: noLabels, 654 assertError: shouldErr(`failed to link extra file 'testdata/nope.txt'`), 655 }, 656 "no_matching_binaries": { 657 dockers: []config.Docker{ 658 { 659 ImageTemplates: []string{"whatever:latest"}, 660 Goos: "darwin", 661 Goarch: "amd64", 662 Binaries: []string{"mybinnnn"}, 663 Dockerfile: "testdata/Dockerfile", 664 }, 665 }, 666 assertImageLabels: noLabels, 667 assertError: shouldErr(`0 binaries match docker definition: [mybinnnn]: darwin_amd64_, should be 1`), 668 }, 669 "multiple_binaries": { 670 dockers: []config.Docker{ 671 { 672 ImageTemplates: []string{registry + "goreleaser/multiple:latest"}, 673 Goos: "darwin", 674 Goarch: "amd64", 675 Binaries: []string{"mybin", "anotherbin"}, 676 Dockerfile: "testdata/Dockerfile.multiple", 677 }, 678 }, 679 assertImageLabels: noLabels, 680 assertError: shouldNotErr, 681 pubAssertError: shouldNotErr, 682 manifestAssertError: shouldNotErr, 683 expect: []string{ 684 registry + "goreleaser/multiple:latest", 685 }, 686 }, 687 // TODO: add a test case for multiple matching binaries for the same name 688 "templated_binaries": { 689 env: map[string]string{ 690 "BIN_NAME": "mybin", 691 }, 692 dockers: []config.Docker{ 693 { 694 ImageTemplates: []string{registry + "goreleaser/templatedbins:latest"}, 695 Goos: "darwin", 696 Goarch: "amd64", 697 Binaries: []string{"{{.Env.BIN_NAME}}"}, 698 Dockerfile: "testdata/Dockerfile", 699 }, 700 }, 701 assertImageLabels: noLabels, 702 assertError: shouldNotErr, 703 pubAssertError: shouldNotErr, 704 manifestAssertError: shouldNotErr, 705 expect: []string{ 706 registry + "goreleaser/templatedbins:latest", 707 }, 708 }, 709 "binaries_template_error": { 710 dockers: []config.Docker{ 711 { 712 ImageTemplates: []string{ 713 registry + "goreleaser/binaries_template_error:latest", 714 }, 715 Goos: "linux", 716 Goarch: "amd64", 717 Dockerfile: "testdata/Dockerfile", 718 Binaries: []string{"{{.Env.BAR}"}, 719 }, 720 }, 721 assertImageLabels: noLabels, 722 assertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`), 723 }, 724 } 725 726 killAndRm(t) 727 start(t) 728 defer killAndRm(t) 729 730 for name, docker := range table { 731 t.Run(name, func(tt *testing.T) { 732 var folder = t.TempDir() 733 var dist = filepath.Join(folder, "dist") 734 require.NoError(tt, os.Mkdir(dist, 0755)) 735 require.NoError(tt, os.Mkdir(filepath.Join(dist, "mybin"), 0755)) 736 _, err := os.Create(filepath.Join(dist, "mybin", "mybin")) 737 require.NoError(tt, err) 738 _, err = os.Create(filepath.Join(dist, "mybin", "anotherbin")) 739 require.NoError(tt, err) 740 741 var ctx = context.New(config.Project{ 742 ProjectName: "mybin", 743 Dist: dist, 744 Dockers: docker.dockers, 745 DockerManifests: docker.manifests, 746 }) 747 ctx.Parallelism = 1 748 ctx.Env = docker.env 749 ctx.Version = "1.0.0" 750 ctx.Git = context.GitInfo{ 751 CurrentTag: "v1.0.0", 752 Commit: "a1b2c3d4", 753 } 754 ctx.Semver = context.Semver{ 755 Major: 1, 756 Minor: 0, 757 Patch: 0, 758 } 759 for _, os := range []string{"linux", "darwin"} { 760 for _, arch := range []string{"amd64", "386", "arm64"} { 761 for _, bin := range []string{"mybin", "anotherbin"} { 762 ctx.Artifacts.Add(&artifact.Artifact{ 763 Name: bin, 764 Path: filepath.Join(dist, "mybin", bin), 765 Goarch: arch, 766 Goos: os, 767 Type: artifact.Binary, 768 Extra: map[string]interface{}{ 769 "Binary": bin, 770 "ID": bin, 771 }, 772 }) 773 } 774 } 775 } 776 777 // this might fail as the image doesnt exist yet, so lets ignore the error 778 for _, img := range docker.expect { 779 _ = exec.Command("docker", "rmi", img).Run() 780 } 781 782 err = Pipe{}.Run(ctx) 783 docker.assertError(tt, err) 784 if err == nil { 785 docker.pubAssertError(tt, Pipe{}.Publish(ctx)) 786 docker.manifestAssertError(tt, ManifestPipe{}.Publish(ctx)) 787 } 788 789 for _, d := range docker.dockers { 790 docker.assertImageLabels(tt, len(d.ImageTemplates)) 791 } 792 793 // this might should not fail as the image should have been created when 794 // the step ran 795 for _, img := range docker.expect { 796 tt.Log("removing docker image", img) 797 require.NoError(tt, exec.Command("docker", "rmi", img).Run(), "could not delete image %s", img) 798 } 799 800 }) 801 } 802 } 803 804 func TestBuildCommand(t *testing.T) { 805 images := []string{"goreleaser/test_build_flag", "goreleaser/test_multiple_tags"} 806 tests := []struct { 807 name string 808 flags []string 809 expect []string 810 }{ 811 { 812 name: "no flags", 813 flags: []string{}, 814 expect: []string{"build", ".", "-t", images[0], "-t", images[1]}, 815 }, 816 { 817 name: "single flag", 818 flags: []string{"--label=foo"}, 819 expect: []string{"build", ".", "-t", images[0], "-t", images[1], "--label=foo"}, 820 }, 821 { 822 name: "multiple flags", 823 flags: []string{"--label=foo", "--build-arg=bar=baz"}, 824 expect: []string{"build", ".", "-t", images[0], "-t", images[1], "--label=foo", "--build-arg=bar=baz"}, 825 }, 826 } 827 for _, tt := range tests { 828 t.Run(tt.name, func(t *testing.T) { 829 command := buildCommand(images, tt.flags) 830 require.Equal(t, tt.expect, command) 831 }) 832 } 833 } 834 835 func TestDescription(t *testing.T) { 836 require.NotEmpty(t, Pipe{}.String()) 837 } 838 839 func TestNoDockers(t *testing.T) { 840 require.True(t, pipe.IsSkip(Pipe{}.Run(context.New(config.Project{})))) 841 } 842 843 func TestNoDockerWithoutImageName(t *testing.T) { 844 require.True(t, pipe.IsSkip(Pipe{}.Run(context.New(config.Project{ 845 Dockers: []config.Docker{ 846 { 847 Goos: "linux", 848 }, 849 }, 850 })))) 851 } 852 853 func TestDockerNotInPath(t *testing.T) { 854 var path = os.Getenv("PATH") 855 defer func() { 856 require.NoError(t, os.Setenv("PATH", path)) 857 }() 858 require.NoError(t, os.Setenv("PATH", "")) 859 var ctx = &context.Context{ 860 Version: "1.0.0", 861 Config: config.Project{ 862 Dockers: []config.Docker{ 863 { 864 ImageTemplates: []string{"a/b"}, 865 }, 866 }, 867 }, 868 } 869 require.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error()) 870 } 871 872 func TestDefault(t *testing.T) { 873 var ctx = &context.Context{ 874 Config: config.Project{ 875 Builds: []config.Build{ 876 { 877 Binary: "foo", 878 }, 879 }, 880 Dockers: []config.Docker{ 881 {}, 882 }, 883 }, 884 } 885 require.NoError(t, Pipe{}.Default(ctx)) 886 require.Len(t, ctx.Config.Dockers, 1) 887 var docker = ctx.Config.Dockers[0] 888 require.Equal(t, "linux", docker.Goos) 889 require.Equal(t, "amd64", docker.Goarch) 890 require.Equal(t, []string{ctx.Config.Builds[0].Binary}, docker.Binaries) 891 require.Empty(t, docker.Builds) 892 } 893 894 func TestDefaultDockerfile(t *testing.T) { 895 var ctx = &context.Context{ 896 Config: config.Project{ 897 Builds: []config.Build{ 898 {}, 899 }, 900 Dockers: []config.Docker{ 901 {}, 902 {}, 903 }, 904 }, 905 } 906 require.NoError(t, Pipe{}.Default(ctx)) 907 require.Len(t, ctx.Config.Dockers, 2) 908 require.Equal(t, "Dockerfile", ctx.Config.Dockers[0].Dockerfile) 909 require.Equal(t, "Dockerfile", ctx.Config.Dockers[1].Dockerfile) 910 } 911 912 func TestDefaultBinaries(t *testing.T) { 913 var ctx = &context.Context{ 914 Config: config.Project{ 915 Builds: []config.Build{ 916 { 917 ID: "foo", 918 }, 919 }, 920 Dockers: []config.Docker{ 921 { 922 Binaries: []string{"foo"}, 923 }, 924 }, 925 }, 926 } 927 require.NoError(t, Pipe{}.Default(ctx)) 928 require.Len(t, ctx.Config.Dockers, 1) 929 var docker = ctx.Config.Dockers[0] 930 require.Equal(t, "linux", docker.Goos) 931 require.Equal(t, "amd64", docker.Goarch) 932 require.Equal(t, []string{"foo"}, docker.Binaries) 933 } 934 935 func TestDefaultNoDockers(t *testing.T) { 936 var ctx = &context.Context{ 937 Config: config.Project{ 938 Dockers: []config.Docker{}, 939 }, 940 } 941 require.NoError(t, Pipe{}.Default(ctx)) 942 require.Empty(t, ctx.Config.Dockers) 943 } 944 945 func TestDefaultFilesDot(t *testing.T) { 946 var ctx = &context.Context{ 947 Config: config.Project{ 948 Dist: "/tmp/distt", 949 Dockers: []config.Docker{ 950 { 951 Files: []string{"./lala", "./lolsob", "."}, 952 }, 953 }, 954 }, 955 } 956 require.EqualError(t, Pipe{}.Default(ctx), `invalid docker.files: can't be . or inside dist folder: .`) 957 } 958 959 func TestDefaultFilesDis(t *testing.T) { 960 var ctx = &context.Context{ 961 Config: config.Project{ 962 Dist: "/tmp/dist", 963 Dockers: []config.Docker{ 964 { 965 Files: []string{"./fooo", "/tmp/dist/asdasd/asd", "./bar"}, 966 }, 967 }, 968 }, 969 } 970 require.EqualError(t, Pipe{}.Default(ctx), `invalid docker.files: can't be . or inside dist folder: /tmp/dist/asdasd/asd`) 971 } 972 973 func TestDefaultSet(t *testing.T) { 974 var ctx = &context.Context{ 975 Config: config.Project{ 976 Dockers: []config.Docker{ 977 { 978 Builds: []string{"foo"}, 979 Goos: "windows", 980 Goarch: "i386", 981 Binaries: []string{"bar"}, 982 Dockerfile: "Dockerfile.foo", 983 }, 984 }, 985 }, 986 } 987 require.NoError(t, Pipe{}.Default(ctx)) 988 require.Len(t, ctx.Config.Dockers, 1) 989 var docker = ctx.Config.Dockers[0] 990 require.Equal(t, "windows", docker.Goos) 991 require.Equal(t, "i386", docker.Goarch) 992 require.Equal(t, "bar", docker.Binaries[0]) 993 require.Equal(t, "foo", docker.Builds[0]) 994 require.Equal(t, "Dockerfile.foo", docker.Dockerfile) 995 } 996 997 func Test_processImageTemplates(t *testing.T) { 998 var ctx = &context.Context{ 999 Config: config.Project{ 1000 Builds: []config.Build{ 1001 { 1002 ID: "default", 1003 }, 1004 }, 1005 Dockers: []config.Docker{ 1006 { 1007 Binaries: []string{"foo"}, 1008 Dockerfile: "Dockerfile.foo", 1009 ImageTemplates: []string{ 1010 "user/image:{{.Tag}}", 1011 "gcr.io/image:{{.Tag}}-{{.Env.FOO}}", 1012 "gcr.io/image:v{{.Major}}.{{.Minor}}", 1013 }, 1014 SkipPush: "true", 1015 }, 1016 }, 1017 }, 1018 } 1019 ctx.SkipPublish = true 1020 ctx.Env = map[string]string{ 1021 "FOO": "123", 1022 } 1023 ctx.Version = "1.0.0" 1024 ctx.Git = context.GitInfo{ 1025 CurrentTag: "v1.0.0", 1026 Commit: "a1b2c3d4", 1027 } 1028 ctx.Semver = context.Semver{ 1029 Major: 1, 1030 Minor: 0, 1031 Patch: 0, 1032 } 1033 1034 require.NoError(t, Pipe{}.Default(ctx)) 1035 require.Len(t, ctx.Config.Dockers, 1) 1036 1037 docker := ctx.Config.Dockers[0] 1038 require.Equal(t, "Dockerfile.foo", docker.Dockerfile) 1039 1040 images, err := processImageTemplates(ctx, docker) 1041 require.NoError(t, err) 1042 require.Equal(t, []string{ 1043 "user/image:v1.0.0", 1044 "gcr.io/image:v1.0.0-123", 1045 "gcr.io/image:v1.0", 1046 }, images) 1047 } 1048 1049 func TestLinkFile(t *testing.T) { 1050 src, err := ioutil.TempFile(t.TempDir(), "src") 1051 require.NoError(t, err) 1052 require.NoError(t, src.Close()) 1053 dst := filepath.Join(filepath.Dir(src.Name()), "dst") 1054 t.Cleanup(func() { 1055 os.Remove(src.Name()) 1056 os.Remove(dst) 1057 }) 1058 fmt.Println("src:", src.Name()) 1059 fmt.Println("dst:", dst) 1060 require.NoError(t, ioutil.WriteFile(src.Name(), []byte("foo"), 0644)) 1061 require.NoError(t, link(src.Name(), dst)) 1062 require.Equal(t, inode(src.Name()), inode(dst)) 1063 } 1064 1065 func TestLinkDirectory(t *testing.T) { 1066 var srcDir = t.TempDir() 1067 var dstDir = t.TempDir() 1068 const testFile = "test" 1069 require.NoError(t, ioutil.WriteFile(filepath.Join(srcDir, testFile), []byte("foo"), 0644)) 1070 require.NoError(t, link(srcDir, dstDir)) 1071 require.Equal(t, inode(filepath.Join(srcDir, testFile)), inode(filepath.Join(dstDir, testFile))) 1072 } 1073 1074 func TestLinkTwoLevelDirectory(t *testing.T) { 1075 var srcDir = t.TempDir() 1076 var dstDir = t.TempDir() 1077 var srcLevel2 = filepath.Join(srcDir, "level2") 1078 const testFile = "test" 1079 1080 require.NoError(t, os.Mkdir(srcLevel2, 0755)) 1081 require.NoError(t, ioutil.WriteFile(filepath.Join(srcDir, testFile), []byte("foo"), 0644)) 1082 require.NoError(t, ioutil.WriteFile(filepath.Join(srcLevel2, testFile), []byte("foo"), 0644)) 1083 1084 require.NoError(t, link(srcDir, dstDir)) 1085 1086 require.Equal(t, inode(filepath.Join(srcDir, testFile)), inode(filepath.Join(dstDir, testFile))) 1087 require.Equal(t, inode(filepath.Join(srcLevel2, testFile)), inode(filepath.Join(dstDir, "level2", testFile))) 1088 } 1089 1090 func inode(file string) uint64 { 1091 fileInfo, err := os.Stat(file) 1092 if err != nil { 1093 return 0 1094 } 1095 stat := fileInfo.Sys().(*syscall.Stat_t) 1096 return stat.Ino 1097 }