github.com/amane3/goreleaser@v0.182.0/internal/pipe/upload/upload_test.go (about)

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