github.phpd.cn/goreleaser/goreleaser@v0.92.0/internal/pipe/docker/docker_test.go (about)

     1  package docker
     2  
     3  import (
     4  	"flag"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"regexp"
    10  	"syscall"
    11  	"testing"
    12  
    13  	"github.com/goreleaser/goreleaser/internal/artifact"
    14  	"github.com/goreleaser/goreleaser/internal/pipe"
    15  	"github.com/goreleaser/goreleaser/pkg/config"
    16  	"github.com/goreleaser/goreleaser/pkg/context"
    17  	"github.com/stretchr/testify/assert"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  var it = flag.Bool("it", false, "push images to docker hub")
    22  var registry = "localhost:5000/"
    23  var altRegistry = "localhost:5050/"
    24  
    25  func TestMain(m *testing.M) {
    26  	flag.Parse()
    27  	if *it {
    28  		registry = "docker.io/"
    29  	}
    30  	os.Exit(m.Run())
    31  }
    32  
    33  func start(t *testing.T) {
    34  	if *it {
    35  		return
    36  	}
    37  	if out, err := exec.Command(
    38  		"docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2",
    39  	).CombinedOutput(); err != nil {
    40  		t.Log("failed to start docker registry", string(out), err)
    41  		t.FailNow()
    42  	}
    43  	if out, err := exec.Command(
    44  		"docker", "run", "-d", "-p", "5050:5000", "--name", "alt_registry", "registry:2",
    45  	).CombinedOutput(); err != nil {
    46  		t.Log("failed to start alternate docker registry", string(out), err)
    47  		t.FailNow()
    48  	}
    49  }
    50  
    51  func killAndRm(t *testing.T) {
    52  	if *it {
    53  		return
    54  	}
    55  	t.Log("killing registry")
    56  	_ = exec.Command("docker", "kill", "registry").Run()
    57  	_ = exec.Command("docker", "rm", "registry").Run()
    58  	_ = exec.Command("docker", "kill", "alt_registry").Run()
    59  	_ = exec.Command("docker", "rm", "alt_registry").Run()
    60  }
    61  
    62  func TestRunPipe(t *testing.T) {
    63  	type errChecker func(*testing.T, error)
    64  	var shouldErr = func(msg string) errChecker {
    65  		return func(t *testing.T, err error) {
    66  			require.Error(t, err)
    67  			require.Contains(t, err.Error(), msg)
    68  		}
    69  	}
    70  	var shouldNotErr = func(t *testing.T, err error) {
    71  		require.NoError(t, err)
    72  	}
    73  	type imageLabelFinder func(*testing.T, int)
    74  	var shouldFindImagesWithLabels = func(image string, filters ...string) func(*testing.T, int) {
    75  		return func(t *testing.T, count int) {
    76  			for _, filter := range filters {
    77  				output, err := exec.Command("docker", "images", "--filter", filter).CombinedOutput()
    78  				require.NoError(t, err)
    79  
    80  				matcher := regexp.MustCompile(image)
    81  				matches := matcher.FindAllStringIndex(string(output), -1)
    82  				require.Equal(t, count, len(matches))
    83  			}
    84  		}
    85  
    86  	}
    87  	var noLabels = func(t *testing.T, count int) {}
    88  
    89  	var table = map[string]struct {
    90  		dockers           []config.Docker
    91  		publish           bool
    92  		expect            []string
    93  		assertImageLabels imageLabelFinder
    94  		assertError       errChecker
    95  		pubAssertError    errChecker
    96  	}{
    97  		"valid": {
    98  			publish: true,
    99  			dockers: []config.Docker{
   100  				{
   101  					ImageTemplates: []string{
   102  						registry + "goreleaser/test_run_pipe:{{.Tag}}-{{.Env.FOO}}",
   103  						registry + "goreleaser/test_run_pipe:v{{.Major}}",
   104  						registry + "goreleaser/test_run_pipe:v{{.Major}}.{{.Minor}}",
   105  						registry + "goreleaser/test_run_pipe:commit-{{.Commit}}",
   106  						registry + "goreleaser/test_run_pipe:le-{{.Os}}",
   107  						registry + "goreleaser/test_run_pipe:latest",
   108  						altRegistry + "goreleaser/test_run_pipe:{{.Tag}}-{{.Env.FOO}}",
   109  						altRegistry + "goreleaser/test_run_pipe:v{{.Major}}",
   110  						altRegistry + "goreleaser/test_run_pipe:v{{.Major}}.{{.Minor}}",
   111  						altRegistry + "goreleaser/test_run_pipe:commit-{{.Commit}}",
   112  						altRegistry + "goreleaser/test_run_pipe:le-{{.Os}}",
   113  						altRegistry + "goreleaser/test_run_pipe:latest",
   114  					},
   115  					Goos:       "linux",
   116  					Goarch:     "amd64",
   117  					Dockerfile: "testdata/Dockerfile",
   118  					Binary:     "mybin",
   119  					BuildFlagTemplates: []string{
   120  						"--label=org.label-schema.schema-version=1.0",
   121  						"--label=org.label-schema.version={{.Version}}",
   122  						"--label=org.label-schema.vcs-ref={{.Commit}}",
   123  						"--label=org.label-schema.name={{.ProjectName}}",
   124  						"--build-arg=FRED={{.Tag}}",
   125  					},
   126  					Files: []string{
   127  						"testdata/extra_file.txt",
   128  					},
   129  				},
   130  			},
   131  			expect: []string{
   132  				registry + "goreleaser/test_run_pipe:v1.0.0-123",
   133  				registry + "goreleaser/test_run_pipe:v1",
   134  				registry + "goreleaser/test_run_pipe:v1.0",
   135  				registry + "goreleaser/test_run_pipe:commit-a1b2c3d4",
   136  				registry + "goreleaser/test_run_pipe:le-linux",
   137  				registry + "goreleaser/test_run_pipe:latest",
   138  				altRegistry + "goreleaser/test_run_pipe:v1.0.0-123",
   139  				altRegistry + "goreleaser/test_run_pipe:v1",
   140  				altRegistry + "goreleaser/test_run_pipe:v1.0",
   141  				altRegistry + "goreleaser/test_run_pipe:commit-a1b2c3d4",
   142  				altRegistry + "goreleaser/test_run_pipe:le-linux",
   143  				altRegistry + "goreleaser/test_run_pipe:latest",
   144  			},
   145  			assertImageLabels: shouldFindImagesWithLabels(
   146  				"goreleaser/test_run_pipe",
   147  				"label=org.label-schema.schema-version=1.0",
   148  				"label=org.label-schema.version=1.0.0",
   149  				"label=org.label-schema.vcs-ref=a1b2c3d4",
   150  				"label=org.label-schema.name=mybin"),
   151  			assertError:    shouldNotErr,
   152  			pubAssertError: shouldNotErr,
   153  		},
   154  		"with deprecated image name & tag templates": {
   155  			publish: true,
   156  			dockers: []config.Docker{
   157  				{
   158  					Image:      registry + "goreleaser/test_run_pipe",
   159  					Goos:       "linux",
   160  					Goarch:     "amd64",
   161  					Dockerfile: "testdata/Dockerfile",
   162  					Binary:     "mybin",
   163  					TagTemplates: []string{
   164  						"{{.Tag}}-{{.Env.FOO}}",
   165  					},
   166  					BuildFlagTemplates: []string{
   167  						"--label=org.label-schema.version={{.Version}}",
   168  					},
   169  				},
   170  			},
   171  			expect: []string{
   172  				registry + "goreleaser/test_run_pipe:v1.0.0-123",
   173  			},
   174  			assertImageLabels: shouldFindImagesWithLabels(
   175  				"goreleaser/test_run_pipe",
   176  				"label=org.label-schema.version=1.0.0",
   177  			),
   178  			assertError:    shouldNotErr,
   179  			pubAssertError: shouldNotErr,
   180  		},
   181  		"multiple images with same extra file": {
   182  			publish: true,
   183  			dockers: []config.Docker{
   184  				{
   185  					Image:        registry + "goreleaser/multiplefiles1",
   186  					Goos:         "linux",
   187  					Goarch:       "amd64",
   188  					Dockerfile:   "testdata/Dockerfile",
   189  					Binary:       "mybin",
   190  					TagTemplates: []string{"latest"},
   191  					Files:        []string{"testdata/extra_file.txt"},
   192  				},
   193  				{
   194  					Image:        registry + "goreleaser/multiplefiles2",
   195  					Goos:         "linux",
   196  					Goarch:       "amd64",
   197  					Dockerfile:   "testdata/Dockerfile",
   198  					Binary:       "mybin",
   199  					TagTemplates: []string{"latest"},
   200  					Files:        []string{"testdata/extra_file.txt"},
   201  				},
   202  			},
   203  			expect: []string{
   204  				registry + "goreleaser/multiplefiles1:latest",
   205  				registry + "goreleaser/multiplefiles2:latest",
   206  			},
   207  			assertImageLabels: noLabels,
   208  			assertError:       shouldNotErr,
   209  			pubAssertError:    shouldNotErr,
   210  		},
   211  		"multiple images with same dockerfile": {
   212  			publish: true,
   213  			dockers: []config.Docker{
   214  				{
   215  					Image:        registry + "goreleaser/test_run_pipe",
   216  					Goos:         "linux",
   217  					Goarch:       "amd64",
   218  					Dockerfile:   "testdata/Dockerfile",
   219  					Binary:       "mybin",
   220  					TagTemplates: []string{"latest"},
   221  				},
   222  				{
   223  					Image:        registry + "goreleaser/test_run_pipe2",
   224  					Goos:         "linux",
   225  					Goarch:       "amd64",
   226  					Dockerfile:   "testdata/Dockerfile",
   227  					Binary:       "mybin",
   228  					TagTemplates: []string{"latest"},
   229  				},
   230  			},
   231  			assertImageLabels: noLabels,
   232  			expect: []string{
   233  				registry + "goreleaser/test_run_pipe:latest",
   234  				registry + "goreleaser/test_run_pipe2:latest",
   235  			},
   236  			assertError:    shouldNotErr,
   237  			pubAssertError: shouldNotErr,
   238  		},
   239  		"valid_skip_push": {
   240  			publish: true,
   241  			dockers: []config.Docker{
   242  				{
   243  					Image:        registry + "goreleaser/test_run_pipe",
   244  					Goos:         "linux",
   245  					Goarch:       "amd64",
   246  					Dockerfile:   "testdata/Dockerfile",
   247  					Binary:       "mybin",
   248  					SkipPush:     true,
   249  					TagTemplates: []string{"latest"},
   250  				},
   251  			},
   252  			expect: []string{
   253  				registry + "goreleaser/test_run_pipe:latest",
   254  			},
   255  			assertImageLabels: noLabels,
   256  			assertError:       shouldNotErr,
   257  			pubAssertError:    shouldNotErr,
   258  		},
   259  		"valid_no_latest": {
   260  			publish: true,
   261  			dockers: []config.Docker{
   262  				{
   263  					Image:        registry + "goreleaser/test_run_pipe",
   264  					Goos:         "linux",
   265  					Goarch:       "amd64",
   266  					Dockerfile:   "testdata/Dockerfile",
   267  					Binary:       "mybin",
   268  					TagTemplates: []string{"{{.Version}}"},
   269  				},
   270  			},
   271  			expect: []string{
   272  				registry + "goreleaser/test_run_pipe:1.0.0",
   273  			},
   274  			assertImageLabels: noLabels,
   275  			assertError:       shouldNotErr,
   276  			pubAssertError:    shouldNotErr,
   277  		},
   278  		"valid_dont_publish": {
   279  			publish: false,
   280  			dockers: []config.Docker{
   281  				{
   282  					Image:        registry + "goreleaser/test_run_pipe",
   283  					Goos:         "linux",
   284  					Goarch:       "amd64",
   285  					Dockerfile:   "testdata/Dockerfile",
   286  					Binary:       "mybin",
   287  					TagTemplates: []string{"latest"},
   288  				},
   289  			},
   290  			expect: []string{
   291  				registry + "goreleaser/test_run_pipe:latest",
   292  			},
   293  			assertImageLabels: noLabels,
   294  			assertError:       shouldNotErr,
   295  			pubAssertError:    shouldNotErr,
   296  		},
   297  		"valid build args": {
   298  			publish: false,
   299  			dockers: []config.Docker{
   300  				{
   301  					Image:        registry + "goreleaser/test_build_args",
   302  					Goos:         "linux",
   303  					Goarch:       "amd64",
   304  					Dockerfile:   "testdata/Dockerfile",
   305  					Binary:       "mybin",
   306  					TagTemplates: []string{"latest"},
   307  					BuildFlagTemplates: []string{
   308  						"--label=foo=bar",
   309  					},
   310  				},
   311  			},
   312  			expect: []string{
   313  				registry + "goreleaser/test_build_args:latest",
   314  			},
   315  			assertImageLabels: noLabels,
   316  			assertError:       shouldNotErr,
   317  			pubAssertError:    shouldNotErr,
   318  		},
   319  		"bad build args": {
   320  			publish: false,
   321  			dockers: []config.Docker{
   322  				{
   323  					Image:        registry + "goreleaser/test_build_args",
   324  					Goos:         "linux",
   325  					Goarch:       "amd64",
   326  					Dockerfile:   "testdata/Dockerfile",
   327  					Binary:       "mybin",
   328  					TagTemplates: []string{"latest"},
   329  					BuildFlagTemplates: []string{
   330  						"--bad-flag",
   331  					},
   332  				},
   333  			},
   334  			assertImageLabels: noLabels,
   335  			assertError:       shouldErr("unknown flag: --bad-flag"),
   336  		},
   337  		"bad_dockerfile": {
   338  			publish: true,
   339  			dockers: []config.Docker{
   340  				{
   341  					Image:        registry + "goreleaser/bad_dockerfile",
   342  					Goos:         "linux",
   343  					Goarch:       "amd64",
   344  					Dockerfile:   "testdata/Dockerfile.bad",
   345  					Binary:       "mybin",
   346  					TagTemplates: []string{"latest"},
   347  				},
   348  			},
   349  			assertImageLabels: noLabels,
   350  			assertError:       shouldErr("pull access denied for nope, repository does not exist"),
   351  		},
   352  		"tag_template_error": {
   353  			publish: true,
   354  			dockers: []config.Docker{
   355  				{
   356  					Image:      registry + "goreleaser/test_run_pipe",
   357  					Goos:       "linux",
   358  					Goarch:     "amd64",
   359  					Dockerfile: "testdata/Dockerfile",
   360  					Binary:     "mybin",
   361  					TagTemplates: []string{
   362  						"{{.Tag}",
   363  					},
   364  				},
   365  			},
   366  			assertImageLabels: noLabels,
   367  			assertError:       shouldErr(`template: tmpl:1: unexpected "}" in operand`),
   368  		},
   369  		"build_flag_template_error": {
   370  			publish: true,
   371  			dockers: []config.Docker{
   372  				{
   373  					Image:        registry + "goreleaser/test_run_pipe",
   374  					Goos:         "linux",
   375  					Goarch:       "amd64",
   376  					Dockerfile:   "testdata/Dockerfile",
   377  					Binary:       "mybin",
   378  					TagTemplates: []string{"latest"},
   379  					BuildFlagTemplates: []string{
   380  						"--label=tag={{.Tag}",
   381  					},
   382  				},
   383  			},
   384  			assertImageLabels: noLabels,
   385  			assertError:       shouldErr(`template: tmpl:1: unexpected "}" in operand`),
   386  		},
   387  		"missing_env_on_tag_template": {
   388  			publish: true,
   389  			dockers: []config.Docker{
   390  				{
   391  					Image:      registry + "goreleaser/test_run_pipe",
   392  					Goos:       "linux",
   393  					Goarch:     "amd64",
   394  					Dockerfile: "testdata/Dockerfile",
   395  					Binary:     "mybin",
   396  					TagTemplates: []string{
   397  						"{{.Env.NOPE}}",
   398  					},
   399  				},
   400  			},
   401  			assertImageLabels: noLabels,
   402  			assertError:       shouldErr(`template: tmpl:1:46: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`),
   403  		},
   404  		"missing_env_on_build_flag_template": {
   405  			publish: true,
   406  			dockers: []config.Docker{
   407  				{
   408  					Image:        registry + "goreleaser/test_run_pipe",
   409  					Goos:         "linux",
   410  					Goarch:       "amd64",
   411  					Dockerfile:   "testdata/Dockerfile",
   412  					Binary:       "mybin",
   413  					TagTemplates: []string{"latest"},
   414  					BuildFlagTemplates: []string{
   415  						"--label=nope={{.Env.NOPE}}",
   416  					},
   417  				},
   418  			},
   419  			assertImageLabels: noLabels,
   420  			assertError:       shouldErr(`template: tmpl:1:19: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`),
   421  		},
   422  		"image_has_projectname_template_variable": {
   423  			publish: true,
   424  			dockers: []config.Docker{
   425  				{
   426  					Image:      registry + "goreleaser/{{.ProjectName}}",
   427  					Goos:       "linux",
   428  					Goarch:     "amd64",
   429  					Dockerfile: "testdata/Dockerfile",
   430  					Binary:     "mybin",
   431  					SkipPush:   true,
   432  					TagTemplates: []string{
   433  						"{{.Tag}}-{{.Env.FOO}}",
   434  						"latest",
   435  					},
   436  				},
   437  			},
   438  			expect: []string{
   439  				registry + "goreleaser/mybin:v1.0.0-123",
   440  				registry + "goreleaser/mybin:latest",
   441  			},
   442  			assertImageLabels: noLabels,
   443  			assertError:       shouldNotErr,
   444  			pubAssertError:    shouldNotErr,
   445  		},
   446  		"no_permissions": {
   447  			publish: true,
   448  			dockers: []config.Docker{
   449  				{
   450  					Image:        "docker.io/nope",
   451  					Goos:         "linux",
   452  					Goarch:       "amd64",
   453  					Binary:       "mybin",
   454  					Dockerfile:   "testdata/Dockerfile",
   455  					TagTemplates: []string{"latest"},
   456  				},
   457  			},
   458  			expect: []string{
   459  				"docker.io/nope:latest",
   460  			},
   461  			assertImageLabels: noLabels,
   462  			assertError:       shouldNotErr,
   463  			pubAssertError:    shouldErr(`requested access to the resource is denied`),
   464  		},
   465  		"dockerfile_doesnt_exist": {
   466  			publish: true,
   467  			dockers: []config.Docker{
   468  				{
   469  					Image:        "whatever",
   470  					Goos:         "linux",
   471  					Goarch:       "amd64",
   472  					Binary:       "mybin",
   473  					Dockerfile:   "testdata/Dockerfilezzz",
   474  					TagTemplates: []string{"latest"},
   475  				},
   476  			},
   477  			assertImageLabels: noLabels,
   478  			assertError:       shouldErr(`failed to link dockerfile`),
   479  		},
   480  		"extra_file_doesnt_exist": {
   481  			publish: true,
   482  			dockers: []config.Docker{
   483  				{
   484  					Image:        "whatever",
   485  					Goos:         "linux",
   486  					Goarch:       "amd64",
   487  					Binary:       "mybin",
   488  					Dockerfile:   "testdata/Dockerfile",
   489  					TagTemplates: []string{"latest"},
   490  					Files: []string{
   491  						"testdata/nope.txt",
   492  					},
   493  				},
   494  			},
   495  			assertImageLabels: noLabels,
   496  			assertError:       shouldErr(`failed to link extra file 'testdata/nope.txt'`),
   497  		},
   498  		"no_matching_binaries": {
   499  			publish: true,
   500  			dockers: []config.Docker{
   501  				{
   502  					Image:      "whatever",
   503  					Goos:       "darwin",
   504  					Goarch:     "amd64",
   505  					Binary:     "mybinnnn",
   506  					Dockerfile: "testdata/Dockerfile",
   507  				},
   508  			},
   509  			assertImageLabels: noLabels,
   510  			assertError:       shouldErr(`0 binaries match docker definition: mybinnnn: darwin_amd64_`),
   511  		},
   512  		"mixed image and image template": {
   513  			publish: true,
   514  			dockers: []config.Docker{
   515  				{
   516  					ImageTemplates: []string{
   517  						registry + "goreleaser/test_run_pipe:latest",
   518  					},
   519  					Image:        registry + "goreleaser/test_run_pipe",
   520  					Goos:         "darwin",
   521  					Goarch:       "amd64",
   522  					Binary:       "mybin",
   523  					Dockerfile:   "testdata/Dockerfile",
   524  					TagTemplates: []string{"latest"},
   525  				},
   526  			},
   527  			assertImageLabels: noLabels,
   528  			assertError:       shouldErr("failed to process image, use either image_templates (preferred) or image, not both"),
   529  		},
   530  	}
   531  
   532  	killAndRm(t)
   533  	start(t)
   534  	defer killAndRm(t)
   535  
   536  	for name, docker := range table {
   537  		t.Run(name, func(tt *testing.T) {
   538  			folder, err := ioutil.TempDir("", "dockertest")
   539  			require.NoError(tt, err)
   540  			var dist = filepath.Join(folder, "dist")
   541  			require.NoError(tt, os.Mkdir(dist, 0755))
   542  			require.NoError(tt, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
   543  			var binPath = filepath.Join(dist, "mybin", "mybin")
   544  			_, err = os.Create(binPath)
   545  			require.NoError(tt, err)
   546  
   547  			var ctx = context.New(config.Project{
   548  				ProjectName: "mybin",
   549  				Dist:        dist,
   550  				Dockers:     docker.dockers,
   551  			})
   552  			ctx.SkipPublish = !docker.publish
   553  			ctx.Env = map[string]string{
   554  				"FOO": "123",
   555  			}
   556  			ctx.Version = "1.0.0"
   557  			ctx.Git = context.GitInfo{
   558  				CurrentTag: "v1.0.0",
   559  				Commit:     "a1b2c3d4",
   560  			}
   561  			for _, os := range []string{"linux", "darwin"} {
   562  				for _, arch := range []string{"amd64", "386"} {
   563  					ctx.Artifacts.Add(artifact.Artifact{
   564  						Name:   "mybin",
   565  						Path:   binPath,
   566  						Goarch: arch,
   567  						Goos:   os,
   568  						Type:   artifact.Binary,
   569  						Extra: map[string]string{
   570  							"Binary": "mybin",
   571  						},
   572  					})
   573  				}
   574  			}
   575  
   576  			// this might fail as the image doesnt exist yet, so lets ignore the error
   577  			for _, img := range docker.expect {
   578  				_ = exec.Command("docker", "rmi", img).Run()
   579  			}
   580  
   581  			err = Pipe{}.Run(ctx)
   582  			docker.assertError(tt, err)
   583  			if err == nil {
   584  				docker.pubAssertError(tt, Pipe{}.Publish(ctx))
   585  			}
   586  
   587  			for _, d := range docker.dockers {
   588  				if d.ImageTemplates == nil {
   589  					docker.assertImageLabels(tt, len(d.TagTemplates))
   590  				} else {
   591  					docker.assertImageLabels(tt, len(d.ImageTemplates))
   592  				}
   593  			}
   594  
   595  			// this might should not fail as the image should have been created when
   596  			// the step ran
   597  			for _, img := range docker.expect {
   598  				tt.Log("removing docker image", img)
   599  				require.NoError(tt, exec.Command("docker", "rmi", img).Run(), "could not delete image %s", img)
   600  			}
   601  
   602  		})
   603  	}
   604  }
   605  
   606  func TestBuildCommand(t *testing.T) {
   607  	images := []string{"goreleaser/test_build_flag", "goreleaser/test_multiple_tags"}
   608  	tests := []struct {
   609  		name   string
   610  		images []string
   611  		flags  []string
   612  		expect []string
   613  	}{
   614  		{
   615  			name:   "no flags",
   616  			flags:  []string{},
   617  			expect: []string{"build", ".", "-t", images[0], "-t", images[1]},
   618  		},
   619  		{
   620  			name:   "single flag",
   621  			flags:  []string{"--label=foo"},
   622  			expect: []string{"build", ".", "-t", images[0], "-t", images[1], "--label=foo"},
   623  		},
   624  		{
   625  			name:   "multiple flags",
   626  			flags:  []string{"--label=foo", "--build-arg=bar=baz"},
   627  			expect: []string{"build", ".", "-t", images[0], "-t", images[1], "--label=foo", "--build-arg=bar=baz"},
   628  		},
   629  	}
   630  	for _, tt := range tests {
   631  		t.Run(tt.name, func(t *testing.T) {
   632  			command := buildCommand(images, tt.flags)
   633  			assert.Equal(t, tt.expect, command)
   634  		})
   635  	}
   636  }
   637  
   638  func TestDescription(t *testing.T) {
   639  	assert.NotEmpty(t, Pipe{}.String())
   640  }
   641  
   642  func TestNoDockers(t *testing.T) {
   643  	assert.True(t, pipe.IsSkip(Pipe{}.Run(context.New(config.Project{}))))
   644  }
   645  
   646  func TestNoDockerWithoutImageName(t *testing.T) {
   647  	assert.True(t, pipe.IsSkip(Pipe{}.Run(context.New(config.Project{
   648  		Dockers: []config.Docker{
   649  			{
   650  				Goos: "linux",
   651  			},
   652  		},
   653  	}))))
   654  }
   655  
   656  func TestDockerNotInPath(t *testing.T) {
   657  	var path = os.Getenv("PATH")
   658  	defer func() {
   659  		assert.NoError(t, os.Setenv("PATH", path))
   660  	}()
   661  	assert.NoError(t, os.Setenv("PATH", ""))
   662  	var ctx = &context.Context{
   663  		Version: "1.0.0",
   664  		Config: config.Project{
   665  			Dockers: []config.Docker{
   666  				{
   667  					Image: "a/b",
   668  				},
   669  			},
   670  		},
   671  	}
   672  	assert.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error())
   673  }
   674  
   675  func TestDefault(t *testing.T) {
   676  	var ctx = &context.Context{
   677  		Config: config.Project{
   678  			Builds: []config.Build{
   679  				{
   680  					Binary: "foo",
   681  				},
   682  			},
   683  			Dockers: []config.Docker{
   684  				{},
   685  			},
   686  		},
   687  	}
   688  	assert.NoError(t, Pipe{}.Default(ctx))
   689  	assert.Len(t, ctx.Config.Dockers, 1)
   690  	var docker = ctx.Config.Dockers[0]
   691  	assert.Equal(t, "linux", docker.Goos)
   692  	assert.Equal(t, "amd64", docker.Goarch)
   693  	assert.Equal(t, ctx.Config.Builds[0].Binary, docker.Binary)
   694  	assert.Equal(t, "Dockerfile", docker.Dockerfile)
   695  }
   696  
   697  func TestDefaultNoDockers(t *testing.T) {
   698  	var ctx = &context.Context{
   699  		Config: config.Project{
   700  			Dockers: []config.Docker{},
   701  		},
   702  	}
   703  	assert.NoError(t, Pipe{}.Default(ctx))
   704  	assert.Empty(t, ctx.Config.Dockers)
   705  }
   706  
   707  func TestDefaultSet(t *testing.T) {
   708  	var ctx = &context.Context{
   709  		Config: config.Project{
   710  			Dockers: []config.Docker{
   711  				{
   712  					Goos:       "windows",
   713  					Goarch:     "i386",
   714  					Binary:     "bar",
   715  					Dockerfile: "Dockerfile.foo",
   716  				},
   717  			},
   718  		},
   719  	}
   720  	assert.NoError(t, Pipe{}.Default(ctx))
   721  	assert.Len(t, ctx.Config.Dockers, 1)
   722  	var docker = ctx.Config.Dockers[0]
   723  	assert.Equal(t, "windows", docker.Goos)
   724  	assert.Equal(t, "i386", docker.Goarch)
   725  	assert.Equal(t, "bar", docker.Binary)
   726  	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
   727  }
   728  
   729  func TestDefaultWithImage(t *testing.T) {
   730  	var ctx = &context.Context{
   731  		Config: config.Project{
   732  			Dockers: []config.Docker{
   733  				{
   734  					Goos:       "windows",
   735  					Goarch:     "i386",
   736  					Binary:     "bar",
   737  					Dockerfile: "Dockerfile.foo",
   738  					Image:      "my/image",
   739  				},
   740  			},
   741  		},
   742  	}
   743  	assert.NoError(t, Pipe{}.Default(ctx))
   744  	assert.Len(t, ctx.Config.Dockers, 1)
   745  	var docker = ctx.Config.Dockers[0]
   746  	assert.Equal(t, "windows", docker.Goos)
   747  	assert.Equal(t, "i386", docker.Goarch)
   748  	assert.Equal(t, "bar", docker.Binary)
   749  	assert.Equal(t, []string{"{{ .Version }}"}, docker.TagTemplates)
   750  	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
   751  }
   752  
   753  func Test_processImageTemplates(t *testing.T) {
   754  
   755  	var table = map[string]struct {
   756  		image          string
   757  		tagTemplates   []string
   758  		imageTemplates []string
   759  		expectImages   []string
   760  	}{
   761  		"with image templates": {
   762  			imageTemplates: []string{"user/image:{{.Tag}}", "gcr.io/image:{{.Tag}}-{{.Env.FOO}}", "gcr.io/image:v{{.Major}}.{{.Minor}}"},
   763  			expectImages:   []string{"user/image:v1.0.0", "gcr.io/image:v1.0.0-123", "gcr.io/image:v1.0"},
   764  		},
   765  		"with image name and tag template": {
   766  			image:        "my/image",
   767  			tagTemplates: []string{"{{.Tag}}-{{.Env.FOO}}", "v{{.Major}}.{{.Minor}}"},
   768  			expectImages: []string{"my/image:v1.0.0-123", "my/image:v1.0"},
   769  		},
   770  	}
   771  
   772  	for name, tt := range table {
   773  		t.Run(name, func(t *testing.T) {
   774  
   775  			var ctx = &context.Context{
   776  				Config: config.Project{
   777  					Dockers: []config.Docker{
   778  						{
   779  							Binary:         "foo",
   780  							Image:          tt.image,
   781  							Dockerfile:     "Dockerfile.foo",
   782  							ImageTemplates: tt.imageTemplates,
   783  							SkipPush:       true,
   784  							TagTemplates:   tt.tagTemplates,
   785  						},
   786  					},
   787  				},
   788  			}
   789  			ctx.SkipPublish = true
   790  			ctx.Env = map[string]string{
   791  				"FOO": "123",
   792  			}
   793  			ctx.Version = "1.0.0"
   794  			ctx.Git = context.GitInfo{
   795  				CurrentTag: "v1.0.0",
   796  				Commit:     "a1b2c3d4",
   797  			}
   798  
   799  			assert.NoError(t, Pipe{}.Default(ctx))
   800  			assert.Len(t, ctx.Config.Dockers, 1)
   801  
   802  			docker := ctx.Config.Dockers[0]
   803  			assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
   804  
   805  			images, err := processImageTemplates(ctx, docker, artifact.Artifact{})
   806  			assert.NoError(t, err)
   807  			assert.Equal(t, tt.expectImages, images)
   808  		})
   809  	}
   810  
   811  }
   812  
   813  func TestLinkFile(t *testing.T) {
   814  	const srcFile = "/tmp/test"
   815  	const dstFile = "/tmp/linked"
   816  	err := ioutil.WriteFile(srcFile, []byte("foo"), 0644)
   817  	if err != nil {
   818  		t.Log("Cannot setup test file")
   819  		t.Fail()
   820  	}
   821  	err = link(srcFile, dstFile)
   822  	if err != nil {
   823  		t.Log("Failed to link: ", err)
   824  		t.Fail()
   825  	}
   826  	if inode(srcFile) != inode(dstFile) {
   827  		t.Log("Inodes do not match, destination file is not a link")
   828  		t.Fail()
   829  	}
   830  	// cleanup
   831  	os.Remove(srcFile)
   832  	os.Remove(dstFile)
   833  }
   834  
   835  func TestLinkDirectory(t *testing.T) {
   836  	const srcDir = "/tmp/testdir"
   837  	const testFile = "test"
   838  	const dstDir = "/tmp/linkedDir"
   839  
   840  	os.Mkdir(srcDir, 0755)
   841  	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
   842  	if err != nil {
   843  		t.Log("Cannot setup test file")
   844  		t.Fail()
   845  	}
   846  	err = link(srcDir, dstDir)
   847  	if err != nil {
   848  		t.Log("Failed to link: ", err)
   849  		t.Fail()
   850  	}
   851  	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
   852  		t.Log("Inodes do not match, destination file is not a link")
   853  		t.Fail()
   854  	}
   855  
   856  	// cleanup
   857  	os.RemoveAll(srcDir)
   858  	os.RemoveAll(dstDir)
   859  }
   860  
   861  func TestLinkTwoLevelDirectory(t *testing.T) {
   862  	const srcDir = "/tmp/testdir"
   863  	const srcLevel2 = srcDir + "/level2"
   864  	const testFile = "test"
   865  	const dstDir = "/tmp/linkedDir"
   866  
   867  	os.Mkdir(srcDir, 0755)
   868  	os.Mkdir(srcLevel2, 0755)
   869  	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
   870  	if err != nil {
   871  		t.Log("Cannot setup test file")
   872  		t.Fail()
   873  	}
   874  	err = ioutil.WriteFile(srcLevel2+"/"+testFile, []byte("foo"), 0644)
   875  	if err != nil {
   876  		t.Log("Cannot setup test file")
   877  		t.Fail()
   878  	}
   879  	err = link(srcDir, dstDir)
   880  	if err != nil {
   881  		t.Log("Failed to link: ", err)
   882  		t.Fail()
   883  	}
   884  	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
   885  		t.Log("Inodes do not match")
   886  		t.Fail()
   887  	}
   888  	if inode(srcLevel2+"/"+testFile) != inode(dstDir+"/level2/"+testFile) {
   889  		t.Log("Inodes do not match")
   890  		t.Fail()
   891  	}
   892  	// cleanup
   893  	os.RemoveAll(srcDir)
   894  	os.RemoveAll(dstDir)
   895  }
   896  
   897  func inode(file string) uint64 {
   898  	fileInfo, err := os.Stat(file)
   899  	if err != nil {
   900  		return 0
   901  	}
   902  	stat := fileInfo.Sys().(*syscall.Stat_t)
   903  	return stat.Ino
   904  }