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