github.com/windmeup/goreleaser@v1.21.95/internal/pipe/artifactory/artifactory_test.go (about)

     1  package artifactory
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"os"
     8  	"path/filepath"
     9  	"sync"
    10  	"syscall"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/windmeup/goreleaser/internal/artifact"
    15  	"github.com/windmeup/goreleaser/internal/testctx"
    16  	"github.com/windmeup/goreleaser/internal/testlib"
    17  	"github.com/windmeup/goreleaser/pkg/config"
    18  )
    19  
    20  var (
    21  	// mux is the HTTP request multiplexer used with the test server.
    22  	mux *http.ServeMux
    23  
    24  	// server is a test HTTP server used to provide mock API responses.
    25  	server *httptest.Server
    26  )
    27  
    28  func setup() {
    29  	// test server
    30  	mux = http.NewServeMux()
    31  	server = httptest.NewServer(mux)
    32  }
    33  
    34  // teardown closes the test HTTP server.
    35  func teardown() {
    36  	server.Close()
    37  }
    38  
    39  func requireMethodPut(t *testing.T, r *http.Request) {
    40  	t.Helper()
    41  	require.Equal(t, http.MethodPut, r.Method)
    42  }
    43  
    44  func requireHeader(t *testing.T, r *http.Request, header, want string) {
    45  	t.Helper()
    46  	require.Equal(t, want, r.Header.Get(header))
    47  }
    48  
    49  // TODO: improve all tests below by checking whether the mocked handlers
    50  // were called or not.
    51  
    52  func TestRunPipe_ModeBinary(t *testing.T) {
    53  	setup()
    54  	defer teardown()
    55  
    56  	folder := t.TempDir()
    57  	dist := filepath.Join(folder, "dist")
    58  	require.NoError(t, os.Mkdir(dist, 0o755))
    59  	require.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0o755))
    60  	binPath := filepath.Join(dist, "mybin", "mybin")
    61  	d1 := []byte("hello\ngo\n")
    62  	require.NoError(t, os.WriteFile(binPath, d1, 0o666))
    63  
    64  	// Dummy artifactories
    65  	mux.HandleFunc("/example-repo-local/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    66  		requireMethodPut(t, r)
    67  		requireHeader(t, r, "Content-Length", "9")
    68  		// Basic auth of user "deployuser" with secret "deployuser-secret"
    69  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
    70  
    71  		w.WriteHeader(http.StatusCreated)
    72  		fmt.Fprint(w, `{
    73  			"repo" : "example-repo-local",
    74  			"path" : "/mybin/darwin/amd64/mybin",
    75  			"created" : "2017-12-02T19:30:45.436Z",
    76  			"createdBy" : "deployuser",
    77  			"downloadUri" : "http://127.0.0.1:56563/example-repo-local/mybin/darwin/amd64/mybin",
    78  			"mimeType" : "application/octet-stream",
    79  			"size" : "9",
    80  			"checksums" : {
    81  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
    82  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
    83  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
    84  			},
    85  			"originalChecksums" : {
    86  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
    87  			},
    88  			"uri" : "http://127.0.0.1:56563/example-repo-local/mybin/darwin/amd64/mybin"
    89  		  }`)
    90  	})
    91  	mux.HandleFunc("/example-repo-local/mybin/linux/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
    92  		requireMethodPut(t, r)
    93  		requireHeader(t, r, "Content-Length", "9")
    94  		// Basic auth of user "deployuser" with secret "deployuser-secret"
    95  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
    96  
    97  		w.WriteHeader(http.StatusCreated)
    98  		fmt.Fprint(w, `{
    99  			"repo" : "example-repo-local",
   100  			"path" : "mybin/linux/amd64/mybin",
   101  			"created" : "2017-12-02T19:30:46.436Z",
   102  			"createdBy" : "deployuser",
   103  			"downloadUri" : "http://127.0.0.1:56563/example-repo-local/mybin/linux/amd64/mybin",
   104  			"mimeType" : "application/octet-stream",
   105  			"size" : "9",
   106  			"checksums" : {
   107  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
   108  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
   109  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   110  			},
   111  			"originalChecksums" : {
   112  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   113  			},
   114  			"uri" : "http://127.0.0.1:56563/example-repo-local/mybin/linux/amd64/mybin"
   115  		  }`)
   116  	})
   117  	mux.HandleFunc("/production-repo-remote/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
   118  		requireMethodPut(t, r)
   119  		requireHeader(t, r, "Content-Length", "9")
   120  		// Basic auth of user "productionuser" with secret "productionuser-apikey"
   121  		requireHeader(t, r, "Authorization", "Basic cHJvZHVjdGlvbnVzZXI6cHJvZHVjdGlvbnVzZXItYXBpa2V5")
   122  
   123  		w.WriteHeader(http.StatusCreated)
   124  		fmt.Fprint(w, `{
   125  			"repo" : "production-repo-remote",
   126  			"path" : "mybin/darwin/amd64/mybin",
   127  			"created" : "2017-12-02T19:30:46.436Z",
   128  			"createdBy" : "productionuser",
   129  			"downloadUri" : "http://127.0.0.1:56563/production-repo-remote/mybin/darwin/amd64/mybin",
   130  			"mimeType" : "application/octet-stream",
   131  			"size" : "9",
   132  			"checksums" : {
   133  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
   134  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
   135  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   136  			},
   137  			"originalChecksums" : {
   138  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   139  			},
   140  			"uri" : "http://127.0.0.1:56563/production-repo-remote/mybin/darwin/amd64/mybin"
   141  		  }`)
   142  	})
   143  	mux.HandleFunc("/production-repo-remote/mybin/linux/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
   144  		requireMethodPut(t, r)
   145  		requireHeader(t, r, "Content-Length", "9")
   146  		// Basic auth of user "productionuser" with secret "productionuser-apikey"
   147  		requireHeader(t, r, "Authorization", "Basic cHJvZHVjdGlvbnVzZXI6cHJvZHVjdGlvbnVzZXItYXBpa2V5")
   148  
   149  		w.WriteHeader(http.StatusCreated)
   150  		fmt.Fprint(w, `{
   151  			"repo" : "production-repo-remote",
   152  			"path" : "mybin/linux/amd64/mybin",
   153  			"created" : "2017-12-02T19:30:46.436Z",
   154  			"createdBy" : "productionuser",
   155  			"downloadUri" : "http://127.0.0.1:56563/production-repo-remote/mybin/linux/amd64/mybin",
   156  			"mimeType" : "application/octet-stream",
   157  			"size" : "9",
   158  			"checksums" : {
   159  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
   160  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
   161  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   162  			},
   163  			"originalChecksums" : {
   164  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   165  			},
   166  			"uri" : "http://127.0.0.1:56563/production-repo-remote/mybin/linux/amd64/mybin"
   167  		  }`)
   168  	})
   169  
   170  	ctx := testctx.NewWithCfg(config.Project{
   171  		ProjectName: "mybin",
   172  		Dist:        dist,
   173  		Artifactories: []config.Upload{
   174  			{
   175  				Name:     "production-us",
   176  				Mode:     "binary",
   177  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   178  				Username: "deployuser",
   179  			},
   180  			{
   181  				Name:     "production-eu",
   182  				Mode:     "binary",
   183  				Target:   fmt.Sprintf("%s/production-repo-remote/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   184  				Username: "productionuser",
   185  			},
   186  		},
   187  		Archives: []config.Archive{{}},
   188  		Env: []string{
   189  			"ARTIFACTORY_PRODUCTION-US_SECRET=deployuser-secret",
   190  			"ARTIFACTORY_PRODUCTION-EU_SECRET=productionuser-apikey",
   191  		},
   192  	})
   193  	for _, goos := range []string{"linux", "darwin"} {
   194  		ctx.Artifacts.Add(&artifact.Artifact{
   195  			Name:   "mybin",
   196  			Path:   binPath,
   197  			Goarch: "amd64",
   198  			Goos:   goos,
   199  			Type:   artifact.UploadableBinary,
   200  		})
   201  	}
   202  
   203  	require.NoError(t, Pipe{}.Default(ctx))
   204  	require.NoError(t, Pipe{}.Publish(ctx))
   205  }
   206  
   207  func TestRunPipe_ModeArchive(t *testing.T) {
   208  	setup()
   209  	defer teardown()
   210  
   211  	folder := t.TempDir()
   212  	tarfile, err := os.Create(filepath.Join(folder, "bin.tar.gz"))
   213  	require.NoError(t, err)
   214  	require.NoError(t, tarfile.Close())
   215  	debfile, err := os.Create(filepath.Join(folder, "bin.deb"))
   216  	require.NoError(t, err)
   217  	require.NoError(t, debfile.Close())
   218  
   219  	ctx := testctx.NewWithCfg(config.Project{
   220  		ProjectName: "goreleaser",
   221  		Dist:        folder,
   222  		Artifactories: []config.Upload{
   223  			{
   224  				Name:     "production",
   225  				Mode:     "archive",
   226  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Version }}/", server.URL),
   227  				Username: "deployuser",
   228  			},
   229  		},
   230  		Archives: []config.Archive{{}},
   231  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   232  	}, testctx.WithVersion("1.0.0"))
   233  	ctx.Artifacts.Add(&artifact.Artifact{
   234  		Type: artifact.UploadableArchive,
   235  		Name: "bin.tar.gz",
   236  		Path: tarfile.Name(),
   237  	})
   238  	ctx.Artifacts.Add(&artifact.Artifact{
   239  		Type: artifact.LinuxPackage,
   240  		Name: "bin.deb",
   241  		Path: debfile.Name(),
   242  	})
   243  
   244  	var uploads sync.Map
   245  
   246  	// Dummy artifactories
   247  	mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.tar.gz", func(w http.ResponseWriter, r *http.Request) {
   248  		requireMethodPut(t, r)
   249  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   250  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   251  
   252  		w.WriteHeader(http.StatusCreated)
   253  		fmt.Fprint(w, `{
   254  			"repo" : "example-repo-local",
   255  			"path" : "/goreleaser/bin.tar.gz",
   256  			"created" : "2017-12-02T19:30:45.436Z",
   257  			"createdBy" : "deployuser",
   258  			"downloadUri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.tar.gz",
   259  			"mimeType" : "application/octet-stream",
   260  			"size" : "9",
   261  			"checksums" : {
   262  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
   263  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
   264  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   265  			},
   266  			"originalChecksums" : {
   267  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   268  			},
   269  			"uri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.tar.gz"
   270  		  }`)
   271  		uploads.Store("targz", true)
   272  	})
   273  	mux.HandleFunc("/example-repo-local/goreleaser/1.0.0/bin.deb", func(w http.ResponseWriter, r *http.Request) {
   274  		requireMethodPut(t, r)
   275  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   276  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   277  
   278  		w.WriteHeader(http.StatusCreated)
   279  		fmt.Fprint(w, `{
   280  			"repo" : "example-repo-local",
   281  			"path" : "goreleaser/bin.deb",
   282  			"created" : "2017-12-02T19:30:46.436Z",
   283  			"createdBy" : "deployuser",
   284  			"downloadUri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.deb",
   285  			"mimeType" : "application/octet-stream",
   286  			"size" : "9",
   287  			"checksums" : {
   288  			  "sha1" : "65d01857a69f14ade727fe1ceee0f52a264b6e57",
   289  			  "md5" : "a55e303e7327dc871a8e2a84f30b9983",
   290  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   291  			},
   292  			"originalChecksums" : {
   293  			  "sha256" : "ead9b172aec5c24ca6c12e85a1e6fc48dd341d8fac38c5ba00a78881eabccf0e"
   294  			},
   295  			"uri" : "http://127.0.0.1:56563/example-repo-local/goreleaser/bin.deb"
   296  		  }`)
   297  		uploads.Store("deb", true)
   298  	})
   299  
   300  	require.NoError(t, Pipe{}.Default(ctx))
   301  	require.NoError(t, Pipe{}.Publish(ctx))
   302  	_, ok := uploads.Load("targz")
   303  	require.True(t, ok, "tar.gz file was not uploaded")
   304  	_, ok = uploads.Load("deb")
   305  	require.True(t, ok, "deb file was not uploaded")
   306  }
   307  
   308  func TestRunPipe_ArtifactoryDown(t *testing.T) {
   309  	folder := t.TempDir()
   310  	tarfile, err := os.Create(filepath.Join(folder, "bin.tar.gz"))
   311  	require.NoError(t, err)
   312  	require.NoError(t, tarfile.Close())
   313  
   314  	ctx := testctx.NewWithCfg(config.Project{
   315  		ProjectName: "goreleaser",
   316  		Dist:        folder,
   317  		Artifactories: []config.Upload{
   318  			{
   319  				Name:     "production",
   320  				Mode:     "archive",
   321  				Target:   "http://localhost:1234/example-repo-local/{{ .ProjectName }}/{{ .Version }}/",
   322  				Username: "deployuser",
   323  			},
   324  		},
   325  		Env: []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   326  	}, testctx.WithVersion("2.0.0"))
   327  	ctx.Artifacts.Add(&artifact.Artifact{
   328  		Type: artifact.UploadableArchive,
   329  		Name: "bin.tar.gz",
   330  		Path: tarfile.Name(),
   331  	})
   332  
   333  	require.NoError(t, Pipe{}.Default(ctx))
   334  	require.ErrorIs(t, Pipe{}.Publish(ctx), syscall.ECONNREFUSED)
   335  }
   336  
   337  func TestRunPipe_TargetTemplateError(t *testing.T) {
   338  	folder := t.TempDir()
   339  	dist := filepath.Join(folder, "dist")
   340  	binPath := filepath.Join(dist, "mybin", "mybin")
   341  
   342  	ctx := testctx.NewWithCfg(config.Project{
   343  		ProjectName: "mybin",
   344  		Dist:        dist,
   345  		Artifactories: []config.Upload{
   346  			{
   347  				Name: "production",
   348  				Mode: "binary",
   349  				// This template is not correct and should fail
   350  				Target:   "http://storage.company.com/example-repo-local/{{.Name}",
   351  				Username: "deployuser",
   352  			},
   353  		},
   354  		Archives: []config.Archive{{}},
   355  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   356  	})
   357  	ctx.Artifacts.Add(&artifact.Artifact{
   358  		Name:   "mybin",
   359  		Path:   binPath,
   360  		Goarch: "amd64",
   361  		Goos:   "darwin",
   362  		Type:   artifact.UploadableBinary,
   363  	})
   364  
   365  	require.NoError(t, Pipe{}.Default(ctx))
   366  	testlib.RequireTemplateError(t, Pipe{}.Publish(ctx))
   367  }
   368  
   369  func TestRunPipe_BadCredentials(t *testing.T) {
   370  	setup()
   371  	defer teardown()
   372  
   373  	folder := t.TempDir()
   374  	dist := filepath.Join(folder, "dist")
   375  	require.NoError(t, os.Mkdir(dist, 0o755))
   376  	require.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0o755))
   377  	binPath := filepath.Join(dist, "mybin", "mybin")
   378  	d1 := []byte("hello\ngo\n")
   379  	require.NoError(t, os.WriteFile(binPath, d1, 0o666))
   380  
   381  	// Dummy artifactories
   382  	mux.HandleFunc("/example-repo-local/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
   383  		requireMethodPut(t, r)
   384  		requireHeader(t, r, "Content-Length", "9")
   385  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   386  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   387  
   388  		w.WriteHeader(http.StatusUnauthorized)
   389  		fmt.Fprint(w, `{
   390  			"errors" : [ {
   391  			  "status" : 401,
   392  			  "message" : "Bad credentials"
   393  			} ]
   394  		  }`)
   395  	})
   396  
   397  	ctx := testctx.NewWithCfg(config.Project{
   398  		ProjectName: "mybin",
   399  		Dist:        dist,
   400  		Artifactories: []config.Upload{
   401  			{
   402  				Name:     "production",
   403  				Mode:     "binary",
   404  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   405  				Username: "deployuser",
   406  			},
   407  		},
   408  		Archives: []config.Archive{{}},
   409  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   410  	})
   411  	ctx.Artifacts.Add(&artifact.Artifact{
   412  		Name:   "mybin",
   413  		Path:   binPath,
   414  		Goarch: "amd64",
   415  		Goos:   "darwin",
   416  		Type:   artifact.UploadableBinary,
   417  	})
   418  
   419  	require.NoError(t, Pipe{}.Default(ctx))
   420  	err := Pipe{}.Publish(ctx)
   421  	require.Error(t, err)
   422  	require.Contains(t, err.Error(), "Bad credentials")
   423  }
   424  
   425  func TestRunPipe_UnparsableErrorResponse(t *testing.T) {
   426  	setup()
   427  	defer teardown()
   428  
   429  	folder := t.TempDir()
   430  	dist := filepath.Join(folder, "dist")
   431  	require.NoError(t, os.Mkdir(dist, 0o755))
   432  	require.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0o755))
   433  	binPath := filepath.Join(dist, "mybin", "mybin")
   434  	d1 := []byte("hello\ngo\n")
   435  	require.NoError(t, os.WriteFile(binPath, d1, 0o666))
   436  
   437  	// Dummy artifactories
   438  	mux.HandleFunc("/example-repo-local/mybin/darwin/amd64/mybin", func(w http.ResponseWriter, r *http.Request) {
   439  		requireMethodPut(t, r)
   440  		requireHeader(t, r, "Content-Length", "9")
   441  		// Basic auth of user "deployuser" with secret "deployuser-secret"
   442  		requireHeader(t, r, "Authorization", "Basic ZGVwbG95dXNlcjpkZXBsb3l1c2VyLXNlY3JldA==")
   443  
   444  		w.WriteHeader(http.StatusUnauthorized)
   445  		fmt.Fprint(w, `<body><h1>error</h1></body>`)
   446  	})
   447  
   448  	ctx := testctx.NewWithCfg(config.Project{
   449  		ProjectName: "mybin",
   450  		Dist:        dist,
   451  		Artifactories: []config.Upload{
   452  			{
   453  				Name:     "production",
   454  				Mode:     "binary",
   455  				Target:   fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
   456  				Username: "deployuser",
   457  			},
   458  		},
   459  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   460  		Archives: []config.Archive{{}},
   461  	})
   462  	ctx.Artifacts.Add(&artifact.Artifact{
   463  		Name:   "mybin",
   464  		Path:   binPath,
   465  		Goarch: "amd64",
   466  		Goos:   "darwin",
   467  		Type:   artifact.UploadableBinary,
   468  	})
   469  
   470  	require.NoError(t, Pipe{}.Default(ctx))
   471  	require.EqualError(t, Pipe{}.Publish(ctx), `production: artifactory: upload failed: unexpected error: invalid character '<' looking for beginning of value: <body><h1>error</h1></body>`)
   472  }
   473  
   474  func TestRunPipe_FileNotFound(t *testing.T) {
   475  	ctx := testctx.NewWithCfg(config.Project{
   476  		ProjectName: "mybin",
   477  		Dist:        "archivetest/dist",
   478  		Artifactories: []config.Upload{
   479  			{
   480  				Name:     "production",
   481  				Mode:     "binary",
   482  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   483  				Username: "deployuser",
   484  			},
   485  		},
   486  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   487  		Archives: []config.Archive{{}},
   488  	})
   489  	ctx.Artifacts.Add(&artifact.Artifact{
   490  		Name:   "mybin",
   491  		Path:   "archivetest/dist/mybin/mybin",
   492  		Goarch: "amd64",
   493  		Goos:   "darwin",
   494  		Type:   artifact.UploadableBinary,
   495  	})
   496  
   497  	require.NoError(t, Pipe{}.Default(ctx))
   498  	require.ErrorIs(t, Pipe{}.Publish(ctx), os.ErrNotExist)
   499  }
   500  
   501  func TestRunPipe_UnparsableTarget(t *testing.T) {
   502  	folder := t.TempDir()
   503  	dist := filepath.Join(folder, "dist")
   504  	require.NoError(t, os.Mkdir(dist, 0o755))
   505  	require.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0o755))
   506  	binPath := filepath.Join(dist, "mybin", "mybin")
   507  	d1 := []byte("hello\ngo\n")
   508  	require.NoError(t, os.WriteFile(binPath, d1, 0o666))
   509  
   510  	ctx := testctx.NewWithCfg(config.Project{
   511  		ProjectName: "mybin",
   512  		Dist:        dist,
   513  		Artifactories: []config.Upload{
   514  			{
   515  				Name:     "production",
   516  				Mode:     "binary",
   517  				Target:   "://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   518  				Username: "deployuser",
   519  			},
   520  		},
   521  		Archives: []config.Archive{{}},
   522  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   523  	})
   524  	ctx.Artifacts.Add(&artifact.Artifact{
   525  		Name:   "mybin",
   526  		Path:   binPath,
   527  		Goarch: "amd64",
   528  		Goos:   "darwin",
   529  		Type:   artifact.UploadableBinary,
   530  	})
   531  
   532  	require.NoError(t, Pipe{}.Default(ctx))
   533  	require.EqualError(t, Pipe{}.Publish(ctx), `production: artifactory: upload failed: parse "://artifacts.company.com/example-repo-local/mybin/darwin/amd64/mybin": missing protocol scheme`)
   534  }
   535  
   536  func TestRunPipe_DirUpload(t *testing.T) {
   537  	folder := t.TempDir()
   538  	dist := filepath.Join(folder, "dist")
   539  	require.NoError(t, os.Mkdir(dist, 0o755))
   540  	require.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0o755))
   541  	binPath := filepath.Join(dist, "mybin")
   542  
   543  	ctx := testctx.NewWithCfg(config.Project{
   544  		ProjectName: "mybin",
   545  		Dist:        dist,
   546  		Artifactories: []config.Upload{
   547  			{
   548  				Name:     "production",
   549  				Mode:     "binary",
   550  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   551  				Username: "deployuser",
   552  			},
   553  		},
   554  		Archives: []config.Archive{{}},
   555  		Env:      []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   556  	})
   557  	ctx.Artifacts.Add(&artifact.Artifact{
   558  		Name:   "mybin",
   559  		Path:   filepath.Dir(binPath),
   560  		Goarch: "amd64",
   561  		Goos:   "darwin",
   562  		Type:   artifact.UploadableBinary,
   563  	})
   564  
   565  	require.NoError(t, Pipe{}.Default(ctx))
   566  	require.EqualError(t, Pipe{}.Publish(ctx), `artifactory: upload failed: the asset to upload can't be a directory`)
   567  }
   568  
   569  func TestDescription(t *testing.T) {
   570  	require.NotEmpty(t, Pipe{}.String())
   571  }
   572  
   573  func TestArtifactoriesWithoutTarget(t *testing.T) {
   574  	ctx := testctx.NewWithCfg(config.Project{
   575  		Artifactories: []config.Upload{
   576  			{
   577  				Name:     "production",
   578  				Username: "deployuser",
   579  			},
   580  		},
   581  		Env: []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   582  	})
   583  	require.NoError(t, Pipe{}.Default(ctx))
   584  	testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
   585  }
   586  
   587  func TestArtifactoriesWithoutUsername(t *testing.T) {
   588  	ctx := testctx.NewWithCfg(config.Project{
   589  		Artifactories: []config.Upload{
   590  			{
   591  				Name:   "production",
   592  				Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   593  			},
   594  		},
   595  		Env: []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   596  	})
   597  	require.NoError(t, Pipe{}.Default(ctx))
   598  	testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
   599  }
   600  
   601  func TestArtifactoriesWithoutName(t *testing.T) {
   602  	ctx := testctx.NewWithCfg(config.Project{
   603  		Artifactories: []config.Upload{
   604  			{
   605  				Username: "deployuser",
   606  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   607  			},
   608  		},
   609  	})
   610  	require.NoError(t, Pipe{}.Default(ctx))
   611  	testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
   612  }
   613  
   614  func TestArtifactoriesWithoutSecret(t *testing.T) {
   615  	ctx := testctx.NewWithCfg(config.Project{
   616  		Artifactories: []config.Upload{
   617  			{
   618  				Name:     "production",
   619  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   620  				Username: "deployuser",
   621  			},
   622  		},
   623  	})
   624  	require.NoError(t, Pipe{}.Default(ctx))
   625  	testlib.AssertSkipped(t, Pipe{}.Publish(ctx))
   626  }
   627  
   628  func TestArtifactoriesWithInvalidMode(t *testing.T) {
   629  	ctx := testctx.NewWithCfg(config.Project{
   630  		Artifactories: []config.Upload{
   631  			{
   632  				Name:     "production",
   633  				Mode:     "does-not-exists",
   634  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   635  				Username: "deployuser",
   636  			},
   637  		},
   638  		Env: []string{"ARTIFACTORY_PRODUCTION_SECRET=deployuser-secret"},
   639  	})
   640  	require.NoError(t, Pipe{}.Default(ctx))
   641  	require.Error(t, Pipe{}.Publish(ctx))
   642  }
   643  
   644  func TestDefault(t *testing.T) {
   645  	ctx := testctx.NewWithCfg(config.Project{
   646  		Artifactories: []config.Upload{
   647  			{
   648  				Name:     "production",
   649  				Target:   "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
   650  				Username: "deployuser",
   651  			},
   652  		},
   653  	})
   654  
   655  	require.NoError(t, Pipe{}.Default(ctx))
   656  	require.Len(t, ctx.Config.Artifactories, 1)
   657  	artifactory := ctx.Config.Artifactories[0]
   658  	require.Equal(t, "archive", artifactory.Mode)
   659  }
   660  
   661  func TestDefaultNoArtifactories(t *testing.T) {
   662  	ctx := testctx.NewWithCfg(config.Project{
   663  		Artifactories: []config.Upload{},
   664  	})
   665  	require.NoError(t, Pipe{}.Default(ctx))
   666  	require.Empty(t, ctx.Config.Artifactories)
   667  }
   668  
   669  func TestDefaultSet(t *testing.T) {
   670  	ctx := testctx.NewWithCfg(config.Project{
   671  		Artifactories: []config.Upload{
   672  			{
   673  				Mode:           "custom",
   674  				ChecksumHeader: "foo",
   675  			},
   676  		},
   677  	})
   678  	require.NoError(t, Pipe{}.Default(ctx))
   679  	require.Len(t, ctx.Config.Artifactories, 1)
   680  	artifactory := ctx.Config.Artifactories[0]
   681  	require.Equal(t, "custom", artifactory.Mode)
   682  	require.Equal(t, "foo", artifactory.ChecksumHeader)
   683  }
   684  
   685  func TestSkip(t *testing.T) {
   686  	t.Run("skip", func(t *testing.T) {
   687  		require.True(t, Pipe{}.Skip(testctx.New()))
   688  	})
   689  
   690  	t.Run("dont skip", func(t *testing.T) {
   691  		ctx := testctx.NewWithCfg(config.Project{
   692  			Artifactories: []config.Upload{{}},
   693  		})
   694  		require.False(t, Pipe{}.Skip(ctx))
   695  	})
   696  }