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  }