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