diff --git a/go.sum b/go.sum index cd6b545171d..728fb666ecf 100644 --- a/go.sum +++ b/go.sum @@ -168,6 +168,7 @@ github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUr github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/internal/http/http.go b/internal/http/http.go index 9b75c0cb887..63cad0a0a22 100644 --- a/internal/http/http.go +++ b/internal/http/http.go @@ -68,47 +68,74 @@ func assetOpenDefault(kind string, a *artifact.Artifact) (*asset, error) { }, nil } -// Defaults sets default configuration options on Put structs -func Defaults(puts []config.Put) error { - for i := range puts { - defaults(&puts[i]) +// Defaults sets default configuration options on upload structs +func Defaults(uploads []config.Upload) error { + for i := range uploads { + defaults(&uploads[i]) } return nil } -func defaults(put *config.Put) { - if put.Mode == "" { - put.Mode = ModeArchive +func defaults(upload *config.Upload) { + if upload.Mode == "" { + upload.Mode = ModeArchive + } + if upload.Method == "" { + upload.Method = h.MethodPut } } -// CheckConfig validates a Put configuration returning a descriptive error when appropriate -func CheckConfig(ctx *context.Context, put *config.Put, kind string) error { - if put.Target == "" { - return misconfigured(kind, put, "missing target") +// CheckConfig validates an upload configuration returning a descriptive error when appropriate +func CheckConfig(ctx *context.Context, upload *config.Upload, kind string) error { + if upload.Target == "" { + return misconfigured(kind, upload, "missing target") } - if put.Name == "" { - return misconfigured(kind, put, "missing name") + if upload.Name == "" { + return misconfigured(kind, upload, "missing name") } - if put.Mode != ModeArchive && put.Mode != ModeBinary { - return misconfigured(kind, put, "mode must be 'binary' or 'archive'") + if upload.Mode != ModeArchive && upload.Mode != ModeBinary { + return misconfigured(kind, upload, "mode must be 'binary' or 'archive'") } - envName := fmt.Sprintf("%s_%s_SECRET", strings.ToUpper(kind), strings.ToUpper(put.Name)) - if _, ok := ctx.Env[envName]; !ok { - return misconfigured(kind, put, fmt.Sprintf("missing %s environment variable", envName)) + if _, err := getUsername(ctx, upload, kind); err != nil { + return err + } + + if _, err := getPassword(ctx, upload, kind); err != nil { + return err } - if put.TrustedCerts != "" && !x509.NewCertPool().AppendCertsFromPEM([]byte(put.TrustedCerts)) { - return misconfigured(kind, put, "no certificate could be added from the specified trusted_certificates configuration") + if upload.TrustedCerts != "" && !x509.NewCertPool().AppendCertsFromPEM([]byte(upload.TrustedCerts)) { + return misconfigured(kind, upload, "no certificate could be added from the specified trusted_certificates configuration") } return nil } -func misconfigured(kind string, upload *config.Put, reason string) error { +func getUsername(ctx *context.Context, upload *config.Upload, kind string) (string, error) { + if upload.Username != "" { + return upload.Username, nil + } + var key = fmt.Sprintf("%s_%s_USERNAME", strings.ToUpper(kind), strings.ToUpper(upload.Name)) + user, ok := ctx.Env[key] + if !ok { + return "", misconfigured(kind, upload, fmt.Sprintf("missing username or %s environment variable", key)) + } + return user, nil +} + +func getPassword(ctx *context.Context, upload *config.Upload, kind string) (string, error) { + var key = fmt.Sprintf("%s_%s_SECRET", strings.ToUpper(kind), strings.ToUpper(upload.Name)) + pwd, ok := ctx.Env[key] + if !ok { + return "", misconfigured(kind, upload, fmt.Sprintf("missing %s environment variable", key)) + } + return pwd, nil +} + +func misconfigured(kind string, upload *config.Upload, reason string) error { return pipe.Skip(fmt.Sprintf("%s section '%s' is not configured properly (%s)", kind, upload.Name, reason)) } @@ -117,25 +144,25 @@ func misconfigured(kind string, upload *config.Put, reason string) error { type ResponseChecker func(*h.Response) error // Upload does the actual uploading work -func Upload(ctx *context.Context, puts []config.Put, kind string, check ResponseChecker) error { +func Upload(ctx *context.Context, uploads []config.Upload, kind string, check ResponseChecker) error { if ctx.SkipPublish { return pipe.ErrSkipPublishEnabled } - // Handle every configured put - for _, put := range puts { - put := put + // Handle every configured upload + for _, upload := range uploads { + upload := upload filters := []artifact.Filter{} - if put.Checksum { + if upload.Checksum { filters = append(filters, artifact.ByType(artifact.Checksum)) } - if put.Signature { + if upload.Signature { filters = append(filters, artifact.ByType(artifact.Signature)) } // We support two different modes // - "archive": Upload all artifacts // - "binary": Upload only the raw binaries - switch v := strings.ToLower(put.Mode); v { + switch v := strings.ToLower(upload.Mode); v { case ModeArchive: filters = append(filters, artifact.ByType(artifact.UploadableArchive), @@ -146,17 +173,17 @@ func Upload(ctx *context.Context, puts []config.Put, kind string, check Response default: err := fmt.Errorf("%s: mode \"%s\" not supported", kind, v) log.WithFields(log.Fields{ - kind: put.Name, + kind: upload.Name, "mode": v, }).Error(err.Error()) return err } var filter = artifact.Or(filters...) - if len(put.IDs) > 0 { - filter = artifact.And(filter, artifact.ByIDs(put.IDs...)) + if len(upload.IDs) > 0 { + filter = artifact.And(filter, artifact.ByIDs(upload.IDs...)) } - if err := uploadWithFilter(ctx, &put, filter, kind, check); err != nil { + if err := uploadWithFilter(ctx, &upload, filter, kind, check); err != nil { return err } } @@ -164,34 +191,36 @@ func Upload(ctx *context.Context, puts []config.Put, kind string, check Response return nil } -func uploadWithFilter(ctx *context.Context, put *config.Put, filter artifact.Filter, kind string, check ResponseChecker) error { +func uploadWithFilter(ctx *context.Context, upload *config.Upload, filter artifact.Filter, kind string, check ResponseChecker) error { var artifacts = ctx.Artifacts.Filter(filter).List() log.Debugf("will upload %d artifacts", len(artifacts)) var g = semerrgroup.New(ctx.Parallelism) for _, artifact := range artifacts { artifact := artifact g.Go(func() error { - return uploadAsset(ctx, put, artifact, kind, check) + return uploadAsset(ctx, upload, artifact, kind, check) }) } return g.Wait() } // uploadAsset uploads file to target and logs all actions -func uploadAsset(ctx *context.Context, put *config.Put, artifact *artifact.Artifact, kind string, check ResponseChecker) error { - envBase := fmt.Sprintf("%s_%s_", strings.ToUpper(kind), strings.ToUpper(put.Name)) - username := put.Username - if username == "" { - // username not configured: using env - username = ctx.Env[envBase+"USERNAME"] +func uploadAsset(ctx *context.Context, upload *config.Upload, artifact *artifact.Artifact, kind string, check ResponseChecker) error { + username, err := getUsername(ctx, upload, kind) + if err != nil { + return err + } + + secret, err := getPassword(ctx, upload, kind) + if err != nil { + return err } - secret := ctx.Env[envBase+"SECRET"] // Generate the target url - targetURL, err := resolveTargetTemplate(ctx, put, artifact) + targetURL, err := resolveTargetTemplate(ctx, upload, artifact) if err != nil { msg := fmt.Sprintf("%s: error while building the target url", kind) - log.WithField("instance", put.Name).WithError(err).Error(msg) + log.WithField("instance", upload.Name).WithError(err).Error(msg) return errors.Wrap(err, msg) } @@ -209,19 +238,19 @@ func uploadAsset(ctx *context.Context, put *config.Put, artifact *artifact.Artif targetURL += artifact.Name var headers = map[string]string{} - if put.ChecksumHeader != "" { + if upload.ChecksumHeader != "" { sum, err := artifact.Checksum("sha256") if err != nil { return err } - headers[put.ChecksumHeader] = sum + headers[upload.ChecksumHeader] = sum } - res, err := uploadAssetToServer(ctx, put, targetURL, username, secret, headers, asset, check) + res, err := uploadAssetToServer(ctx, upload, targetURL, username, secret, headers, asset, check) if err != nil { msg := fmt.Sprintf("%s: upload failed", kind) log.WithError(err).WithFields(log.Fields{ - "instance": put.Name, + "instance": upload.Name, "username": username, }).Error(msg) return errors.Wrap(err, msg) @@ -231,26 +260,26 @@ func uploadAsset(ctx *context.Context, put *config.Put, artifact *artifact.Artif } log.WithFields(log.Fields{ - "instance": put.Name, - "mode": put.Mode, + "instance": upload.Name, + "mode": upload.Mode, }).Info("uploaded successful") return nil } // uploadAssetToServer uploads the asset file to target -func uploadAssetToServer(ctx *context.Context, put *config.Put, target, username, secret string, headers map[string]string, a *asset, check ResponseChecker) (*h.Response, error) { - req, err := newUploadRequest(target, username, secret, headers, a) +func uploadAssetToServer(ctx *context.Context, upload *config.Upload, target, username, secret string, headers map[string]string, a *asset, check ResponseChecker) (*h.Response, error) { + req, err := newUploadRequest(upload.Method, target, username, secret, headers, a) if err != nil { return nil, err } - return executeHTTPRequest(ctx, put, req, check) + return executeHTTPRequest(ctx, upload, req, check) } // newUploadRequest creates a new h.Request for uploading -func newUploadRequest(target, username, secret string, headers map[string]string, a *asset) (*h.Request, error) { - req, err := h.NewRequest(h.MethodPut, target, a.ReadCloser) +func newUploadRequest(method, target, username, secret string, headers map[string]string, a *asset) (*h.Request, error) { + req, err := h.NewRequest(method, target, a.ReadCloser) if err != nil { return nil, err } @@ -264,8 +293,8 @@ func newUploadRequest(target, username, secret string, headers map[string]string return req, err } -func getHTTPClient(put *config.Put) (*h.Client, error) { - if put.TrustedCerts == "" { +func getHTTPClient(upload *config.Upload) (*h.Client, error) { + if upload.TrustedCerts == "" { return h.DefaultClient, nil } pool, err := x509.SystemCertPool() @@ -277,7 +306,7 @@ func getHTTPClient(put *config.Put) (*h.Client, error) { return nil, err } } - pool.AppendCertsFromPEM([]byte(put.TrustedCerts)) // already validated certs checked by CheckConfig + pool.AppendCertsFromPEM([]byte(upload.TrustedCerts)) // already validated certs checked by CheckConfig return &h.Client{ Transport: &h.Transport{ TLSClientConfig: &tls.Config{ @@ -288,8 +317,8 @@ func getHTTPClient(put *config.Put) (*h.Client, error) { } // executeHTTPRequest processes the http call with respect of context ctx -func executeHTTPRequest(ctx *context.Context, put *config.Put, req *h.Request, check ResponseChecker) (*h.Response, error) { - client, err := getHTTPClient(put) +func executeHTTPRequest(ctx *context.Context, upload *config.Upload, req *h.Request, check ResponseChecker) (*h.Response, error) { + client, err := getHTTPClient(upload) if err != nil { return nil, err } @@ -334,14 +363,14 @@ type targetData struct { // resolveTargetTemplate returns the resolved target template with replaced variables // Those variables can be replaced by the given context, goos, goarch, goarm and more // TODO: replace this with our internal template pkg -func resolveTargetTemplate(ctx *context.Context, put *config.Put, artifact *artifact.Artifact) (string, error) { +func resolveTargetTemplate(ctx *context.Context, upload *config.Upload, artifact *artifact.Artifact) (string, error) { data := targetData{ Version: ctx.Version, Tag: ctx.Git.CurrentTag, ProjectName: ctx.Config.ProjectName, } - if put.Mode == ModeBinary { + if upload.Mode == ModeBinary { // TODO: multiple archives here data.Os = replace(ctx.Config.Archive.Replacements, artifact.Goos) data.Arch = replace(ctx.Config.Archive.Replacements, artifact.Goarch) @@ -349,7 +378,7 @@ func resolveTargetTemplate(ctx *context.Context, put *config.Put, artifact *arti } var out bytes.Buffer - t, err := template.New(ctx.Config.ProjectName).Parse(put.Target) + t, err := template.New(ctx.Config.ProjectName).Parse(upload.Target) if err != nil { return "", err } diff --git a/internal/http/http_test.go b/internal/http/http_test.go index 8f35f4981bd..e99e6653944 100644 --- a/internal/http/http_test.go +++ b/internal/http/http_test.go @@ -58,7 +58,7 @@ func TestAssetOpenDefault(t *testing.T) { func TestDefaults(t *testing.T) { type args struct { - puts []config.Put + uploads []config.Upload } tests := []struct { name string @@ -66,16 +66,16 @@ func TestDefaults(t *testing.T) { wantErr bool wantMode string }{ - {"set default", args{[]config.Put{{Name: "a", Target: "http://"}}}, false, ModeArchive}, - {"keep value", args{[]config.Put{{Name: "a", Target: "http://...", Mode: ModeBinary}}}, false, ModeBinary}, + {"set default", args{[]config.Upload{{Name: "a", Target: "http://"}}}, false, ModeArchive}, + {"keep value", args{[]config.Upload{{Name: "a", Target: "http://...", Mode: ModeBinary}}}, false, ModeBinary}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := Defaults(tt.args.puts); (err != nil) != tt.wantErr { + if err := Defaults(tt.args.uploads); (err != nil) != tt.wantErr { t.Errorf("Defaults() error = %v, wantErr %v", err, tt.wantErr) } - if tt.wantMode != tt.args.puts[0].Mode { - t.Errorf("Incorrect Defaults() mode %q , wanted %q", tt.args.puts[0].Mode, tt.wantMode) + if tt.wantMode != tt.args.uploads[0].Mode { + t.Errorf("Incorrect Defaults() mode %q , wanted %q", tt.args.uploads[0].Mode, tt.wantMode) } }) } @@ -86,7 +86,7 @@ func TestCheckConfig(t *testing.T) { ctx.Env["TEST_A_SECRET"] = "x" type args struct { ctx *context.Context - upload *config.Put + upload *config.Upload kind string } tests := []struct { @@ -94,13 +94,13 @@ func TestCheckConfig(t *testing.T) { args args wantErr bool }{ - {"ok", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, false}, - {"secret missing", args{ctx, &config.Put{Name: "b", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, - {"target missing", args{ctx, &config.Put{Name: "a", Username: "pepe", Mode: ModeArchive}, "test"}, true}, - {"name missing", args{ctx, &config.Put{Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, - {"mode missing", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe"}, "test"}, true}, - {"mode invalid", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe", Mode: "blabla"}, "test"}, true}, - {"cert invalid", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeBinary, TrustedCerts: "bad cert!"}, "test"}, true}, + {"ok", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, false}, + {"secret missing", args{ctx, &config.Upload{Name: "b", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, + {"target missing", args{ctx, &config.Upload{Name: "a", Username: "pepe", Mode: ModeArchive}, "test"}, true}, + {"name missing", args{ctx, &config.Upload{Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, + {"mode missing", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe"}, "test"}, true}, + {"mode invalid", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: "blabla"}, "test"}, true}, + {"cert invalid", args{ctx, &config.Upload{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeBinary, TrustedCerts: "bad cert!"}, "test"}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -242,12 +242,12 @@ func TestUpload(t *testing.T) { tryTLS bool wantErrPlain bool wantErrTLS bool - setup func(*httptest.Server) (*context.Context, config.Put) + setup func(*httptest.Server) (*context.Context, config.Upload) check func(r []*h.Request) error }{ {"wrong-mode", true, true, true, true, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: "wrong-mode", Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -258,8 +258,8 @@ func TestUpload(t *testing.T) { checks(), }, {"username-from-env", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeArchive, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -271,9 +271,25 @@ func TestUpload(t *testing.T) { check{"/blah/2.1.0/a.tar", "u2", "x", content, map[string]string{}}, ), }, + {"post", true, true, false, false, + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ + Method: h.MethodPost, + Mode: ModeArchive, + Name: "a", + Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", + Username: "u1", + TrustedCerts: cert(s), + } + }, + checks( + check{"/blah/2.1.0/a.deb", "u1", "x", content, map[string]string{}}, + check{"/blah/2.1.0/a.tar", "u1", "x", content, map[string]string{}}, + ), + }, {"archive", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeArchive, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -287,8 +303,8 @@ func TestUpload(t *testing.T) { ), }, {"archive_with_ids", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeArchive, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -303,8 +319,8 @@ func TestUpload(t *testing.T) { ), }, {"binary", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -315,8 +331,8 @@ func TestUpload(t *testing.T) { checks(check{"/blah/2.1.0/a.ubi", "u2", "x", content, map[string]string{}}), }, {"binary_with_ids", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -328,8 +344,8 @@ func TestUpload(t *testing.T) { checks(check{"/blah/2.1.0/a.ubi", "u2", "x", content, map[string]string{}}), }, {"binary-add-ending-bar", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}", @@ -340,8 +356,8 @@ func TestUpload(t *testing.T) { checks(check{"/blah/2.1.0/a.ubi", "u2", "x", content, map[string]string{}}), }, {"archive-with-checksum-and-signature", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeArchive, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -359,8 +375,8 @@ func TestUpload(t *testing.T) { ), }, {"bad-template", true, true, true, true, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectNameXXX}}/{{.VersionXXX}}/", @@ -373,8 +389,8 @@ func TestUpload(t *testing.T) { checks(), }, {"failed-request", true, true, true, true, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL[0:strings.LastIndex(s.URL, ":")] + "/{{.ProjectName}}/{{.Version}}/", @@ -387,8 +403,8 @@ func TestUpload(t *testing.T) { checks(), }, {"broken-cert", false, true, false, true, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -401,16 +417,16 @@ func TestUpload(t *testing.T) { checks(), }, {"skip-publishing", true, true, true, true, - func(s *httptest.Server) (*context.Context, config.Put) { + func(s *httptest.Server) (*context.Context, config.Upload) { c := *ctx c.SkipPublish = true - return &c, config.Put{} + return &c, config.Upload{} }, checks(), }, {"checksumheader", true, true, false, false, - func(s *httptest.Server) (*context.Context, config.Put) { - return ctx, config.Put{ + func(s *httptest.Server) (*context.Context, config.Upload) { + return ctx, config.Upload{ Mode: ModeBinary, Name: "a", Target: s.URL + "/{{.ProjectName}}/{{.Version}}/", @@ -423,14 +439,14 @@ func TestUpload(t *testing.T) { }, } - uploadAndCheck := func(t *testing.T, setup func(*httptest.Server) (*context.Context, config.Put), wantErrPlain, wantErrTLS bool, check func(r []*h.Request) error, srv *httptest.Server) { + uploadAndCheck := func(t *testing.T, setup func(*httptest.Server) (*context.Context, config.Upload), wantErrPlain, wantErrTLS bool, check func(r []*h.Request) error, srv *httptest.Server) { requests = nil - ctx, put := setup(srv) + ctx, upload := setup(srv) wantErr := wantErrPlain if srv.Certificate() != nil { wantErr = wantErrTLS } - if err := Upload(ctx, []config.Put{put}, "test", is2xx); (err != nil) != wantErr { + if err := Upload(ctx, []config.Upload{upload}, "test", is2xx); (err != nil) != wantErr { t.Errorf("Upload() error = %v, wantErr %v", err, wantErr) } if err := check(requests); err != nil { diff --git a/internal/pipe/artifactory/artifactory.go b/internal/pipe/artifactory/artifactory.go index 622add4d506..a50e0844069 100644 --- a/internal/pipe/artifactory/artifactory.go +++ b/internal/pipe/artifactory/artifactory.go @@ -47,6 +47,7 @@ func (Pipe) String() string { func (Pipe) Default(ctx *context.Context) error { for i := range ctx.Config.Artifactories { ctx.Config.Artifactories[i].ChecksumHeader = "X-Checksum-SHA256" + ctx.Config.Artifactories[i].Method = h.MethodPut } return http.Defaults(ctx.Config.Artifactories) } diff --git a/internal/pipe/artifactory/artifactory_test.go b/internal/pipe/artifactory/artifactory_test.go index 1ece7d32769..e1b50108820 100644 --- a/internal/pipe/artifactory/artifactory_test.go +++ b/internal/pipe/artifactory/artifactory_test.go @@ -174,7 +174,7 @@ func TestRunPipe_ModeBinary(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production-us", Mode: "binary", @@ -203,6 +203,7 @@ func TestRunPipe_ModeBinary(t *testing.T) { }) } + assert.NoError(t, Pipe{}.Default(ctx)) assert.NoError(t, Pipe{}.Publish(ctx)) } @@ -220,7 +221,7 @@ func TestRunPipe_ModeArchive(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "goreleaser", Dist: folder, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "archive", @@ -300,6 +301,7 @@ func TestRunPipe_ModeArchive(t *testing.T) { uploads.Store("deb", true) }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.NoError(t, Pipe{}.Publish(ctx)) _, ok := uploads.Load("targz") assert.True(t, ok, "tar.gz file was not uploaded") @@ -316,7 +318,7 @@ func TestRunPipe_ArtifactoryDown(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "goreleaser", Dist: folder, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "archive", @@ -334,6 +336,8 @@ func TestRunPipe_ArtifactoryDown(t *testing.T) { Name: "bin.tar.gz", Path: tarfile.Name(), }) + + assert.NoError(t, Pipe{}.Default(ctx)) err = Pipe{}.Publish(ctx) assert.Error(t, err) assert.Contains(t, err.Error(), "connection refused") @@ -348,7 +352,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -369,6 +373,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: error while building the target url: template: mybin:1: unexpected "/" in operand`) } @@ -405,7 +410,7 @@ func TestRunPipe_BadCredentials(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -425,6 +430,7 @@ func TestRunPipe_BadCredentials(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) err = Pipe{}.Publish(ctx) assert.Error(t, err) assert.Contains(t, err.Error(), "Bad credentials") @@ -462,7 +468,7 @@ func TestRunPipe_UnparsableErrorResponse(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -482,6 +488,7 @@ func TestRunPipe_UnparsableErrorResponse(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: upload failed: invalid character '.' looking for beginning of value`) } @@ -516,7 +523,7 @@ func TestRunPipe_UnparsableResponse(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -536,6 +543,7 @@ func TestRunPipe_UnparsableResponse(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: upload failed: invalid character 'i' looking for beginning of value`) } @@ -543,7 +551,7 @@ func TestRunPipe_FileNotFound(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: "archivetest/dist", - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -563,6 +571,7 @@ func TestRunPipe_FileNotFound(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `open archivetest/dist/mybin/mybin: no such file or directory`) } @@ -580,7 +589,7 @@ func TestRunPipe_UnparsableTarget(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -600,12 +609,13 @@ func TestRunPipe_UnparsableTarget(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: upload failed: parse ://artifacts.company.com/example-repo-local/mybin/darwin/amd64/mybin: missing protocol scheme`) } func TestRunPipe_SkipWhenPublishFalse(t *testing.T) { var ctx = context.New(config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -619,6 +629,7 @@ func TestRunPipe_SkipWhenPublishFalse(t *testing.T) { } ctx.SkipPublish = true + assert.NoError(t, Pipe{}.Default(ctx)) err := Pipe{}.Publish(ctx) assert.True(t, pipe.IsSkip(err)) assert.EqualError(t, err, pipe.ErrSkipPublishEnabled.Error()) @@ -635,7 +646,7 @@ func TestRunPipe_DirUpload(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "binary", @@ -655,6 +666,7 @@ func TestRunPipe_DirUpload(t *testing.T) { Type: artifact.UploadableBinary, }) + assert.NoError(t, Pipe{}.Default(ctx)) assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: upload failed: the asset to upload can't be a directory`) } @@ -663,7 +675,9 @@ func TestDescription(t *testing.T) { } func TestNoArtifactories(t *testing.T) { - assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{})))) + var ctx = context.New(config.Project{}) + assert.NoError(t, Pipe{}.Default(ctx)) + assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx))) } func TestArtifactoriesWithoutTarget(t *testing.T) { @@ -672,7 +686,7 @@ func TestArtifactoriesWithoutTarget(t *testing.T) { "ARTIFACTORY_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Username: "deployuser", @@ -681,6 +695,7 @@ func TestArtifactoriesWithoutTarget(t *testing.T) { }, } + assert.NoError(t, Pipe{}.Default(ctx)) assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx))) } @@ -690,7 +705,7 @@ func TestArtifactoriesWithoutUsername(t *testing.T) { "ARTIFACTORY_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -699,30 +714,35 @@ func TestArtifactoriesWithoutUsername(t *testing.T) { }, } + assert.NoError(t, Pipe{}.Default(ctx)) assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx))) } func TestArtifactoriesWithoutName(t *testing.T) { - assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{ - Artifactories: []config.Put{ + var ctx = context.New(config.Project{ + Artifactories: []config.Upload{ { Username: "deployuser", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", }, }, - })))) + }) + assert.NoError(t, Pipe{}.Default(ctx)) + assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx))) } func TestArtifactoriesWithoutSecret(t *testing.T) { - assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{ - Artifactories: []config.Put{ + var ctx = context.New(config.Project{ + Artifactories: []config.Upload{ { Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", Username: "deployuser", }, }, - })))) + }) + assert.NoError(t, Pipe{}.Default(ctx)) + assert.True(t, pipe.IsSkip(Pipe{}.Publish(ctx))) } func TestArtifactoriesWithInvalidMode(t *testing.T) { @@ -731,7 +751,7 @@ func TestArtifactoriesWithInvalidMode(t *testing.T) { "ARTIFACTORY_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Mode: "does-not-exists", @@ -741,13 +761,15 @@ func TestArtifactoriesWithInvalidMode(t *testing.T) { }, }, } + + assert.NoError(t, Pipe{}.Default(ctx)) assert.Error(t, Pipe{}.Publish(ctx)) } func TestDefault(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -756,6 +778,7 @@ func TestDefault(t *testing.T) { }, }, } + assert.NoError(t, Pipe{}.Default(ctx)) assert.Len(t, ctx.Config.Artifactories, 1) var artifactory = ctx.Config.Artifactories[0] @@ -765,7 +788,7 @@ func TestDefault(t *testing.T) { func TestDefaultNoArtifactories(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Artifactories: []config.Put{}, + Artifactories: []config.Upload{}, }, } assert.NoError(t, Pipe{}.Default(ctx)) @@ -775,7 +798,7 @@ func TestDefaultNoArtifactories(t *testing.T) { func TestDefaultSet(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Artifactories: []config.Put{ + Artifactories: []config.Upload{ { Mode: "custom", }, diff --git a/internal/pipe/publish/publish.go b/internal/pipe/publish/publish.go index 0d1ee0e43f6..c1e1266d5df 100644 --- a/internal/pipe/publish/publish.go +++ b/internal/pipe/publish/publish.go @@ -10,11 +10,11 @@ import ( "github.com/goreleaser/goreleaser/internal/pipe/blob" "github.com/goreleaser/goreleaser/internal/pipe/brew" "github.com/goreleaser/goreleaser/internal/pipe/docker" - "github.com/goreleaser/goreleaser/internal/pipe/put" "github.com/goreleaser/goreleaser/internal/pipe/release" "github.com/goreleaser/goreleaser/internal/pipe/s3" "github.com/goreleaser/goreleaser/internal/pipe/scoop" "github.com/goreleaser/goreleaser/internal/pipe/snapcraft" + "github.com/goreleaser/goreleaser/internal/pipe/upload" "github.com/goreleaser/goreleaser/pkg/context" "github.com/pkg/errors" ) @@ -38,7 +38,7 @@ type Publisher interface { var publishers = []Publisher{ s3.Pipe{}, blob.Pipe{}, - put.Pipe{}, + upload.Pipe{}, artifactory.Pipe{}, docker.Pipe{}, snapcraft.Pipe{}, diff --git a/internal/pipe/put/put.go b/internal/pipe/upload/upload.go similarity index 56% rename from internal/pipe/put/put.go rename to internal/pipe/upload/upload.go index b24e3edfbb6..cdfb0d4fd09 100644 --- a/internal/pipe/put/put.go +++ b/internal/pipe/upload/upload.go @@ -1,9 +1,11 @@ -// Package put provides a Pipe that push using HTTP PUT -package put +// Package upload provides a Pipe that push using HTTP +package upload import ( h "net/http" + "github.com/goreleaser/goreleaser/internal/deprecate" + "github.com/goreleaser/goreleaser/internal/http" "github.com/goreleaser/goreleaser/internal/pipe" "github.com/goreleaser/goreleaser/pkg/context" @@ -15,30 +17,34 @@ type Pipe struct{} // String returns the description of the pipe func (Pipe) String() string { - return "HTTP PUT" + return "HTTP Upload" } // Default sets the pipe defaults func (Pipe) Default(ctx *context.Context) error { - return http.Defaults(ctx.Config.Puts) + if len(ctx.Config.Puts) > 0 { + deprecate.Notice("puts") + ctx.Config.Uploads = append(ctx.Config.Uploads, ctx.Config.Puts...) + } + return http.Defaults(ctx.Config.Uploads) } // Publish artifacts func (Pipe) Publish(ctx *context.Context) error { - if len(ctx.Config.Puts) == 0 { - return pipe.Skip("put section is not configured") + if len(ctx.Config.Uploads) == 0 { + return pipe.Skip("uploads section is not configured") } // Check requirements for every instance we have configured. // If not fulfilled, we can skip this pipeline - for _, instance := range ctx.Config.Puts { + for _, instance := range ctx.Config.Uploads { instance := instance - if skip := http.CheckConfig(ctx, &instance, "put"); skip != nil { + if skip := http.CheckConfig(ctx, &instance, "upload"); skip != nil { return pipe.Skip(skip.Error()) } } - return http.Upload(ctx, ctx.Config.Puts, "put", func(res *h.Response) error { + return http.Upload(ctx, ctx.Config.Uploads, "upload", func(res *h.Response) error { if c := res.StatusCode; c < 200 || 299 < c { return errors.Errorf("unexpected http response status: %s", res.Status) } diff --git a/internal/pipe/put/put_test.go b/internal/pipe/upload/upload_test.go similarity index 86% rename from internal/pipe/put/put_test.go rename to internal/pipe/upload/upload_test.go index b783b891c7b..b7ce8708aba 100644 --- a/internal/pipe/put/put_test.go +++ b/internal/pipe/upload/upload_test.go @@ -1,9 +1,10 @@ -package put +package upload import ( "fmt" "io/ioutil" "net/http" + h "net/http" "net/http/httptest" "os" "path/filepath" @@ -106,14 +107,16 @@ func TestRunPipe_ModeBinary(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production-us", Mode: "binary", Target: fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL), Username: "deployuser", }, { + Method: h.MethodPut, Name: "production-eu", Mode: "binary", Target: fmt.Sprintf("%s/production-repo-remote/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL), @@ -122,8 +125,8 @@ func TestRunPipe_ModeBinary(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION-US_SECRET": "deployuser-secret", - "PUT_PRODUCTION-EU_SECRET": "productionuser-apikey", + "UPLOAD_PRODUCTION-US_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION-EU_SECRET": "productionuser-apikey", } for _, goos := range []string{"linux", "darwin"} { ctx.Artifacts.Add(&artifact.Artifact{ @@ -152,8 +155,9 @@ func TestRunPipe_ModeArchive(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "goreleaser", Dist: folder, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "archive", Target: fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Version }}/", server.URL), @@ -162,7 +166,7 @@ func TestRunPipe_ModeArchive(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Version = "1.0.0" ctx.Artifacts.Add(&artifact.Artifact{ @@ -214,8 +218,9 @@ func TestRunPipe_ArtifactoryDown(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "goreleaser", Dist: folder, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "archive", Target: "http://localhost:1234/example-repo-local/{{ .ProjectName }}/{{ .Version }}/", @@ -225,7 +230,7 @@ func TestRunPipe_ArtifactoryDown(t *testing.T) { }) ctx.Version = "2.0.0" ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Type: artifact.UploadableArchive, @@ -246,10 +251,11 @@ func TestRunPipe_TargetTemplateError(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Puts: []config.Put{ + Uploads: []config.Upload{ { - Name: "production", - Mode: "binary", + Method: h.MethodPut, + Name: "production", + Mode: "binary", // This template is not correct and should fail Target: "http://storage.company.com/example-repo-local/{{ .ProjectName /{{ .Version }}/", Username: "deployuser", @@ -257,7 +263,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Name: "mybin", @@ -268,7 +274,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) { }) err = Pipe{}.Publish(ctx) assert.Error(t, err) - assert.Contains(t, err.Error(), `put: error while building the target url: template: mybin:1: unexpected "/" in operand`) + assert.Contains(t, err.Error(), `upload: error while building the target url: template: mybin:1: unexpected "/" in operand`) } func TestRunPipe_BadCredentials(t *testing.T) { @@ -298,8 +304,9 @@ func TestRunPipe_BadCredentials(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "binary", Target: fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL), @@ -308,7 +315,7 @@ func TestRunPipe_BadCredentials(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Name: "mybin", @@ -327,8 +334,9 @@ func TestRunPipe_FileNotFound(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: "archivetest/dist", - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "binary", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -337,7 +345,7 @@ func TestRunPipe_FileNotFound(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Name: "mybin", @@ -364,8 +372,9 @@ func TestRunPipe_UnparsableTarget(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "binary", Target: "://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -374,7 +383,7 @@ func TestRunPipe_UnparsableTarget(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Name: "mybin", @@ -384,12 +393,12 @@ func TestRunPipe_UnparsableTarget(t *testing.T) { Type: artifact.UploadableBinary, }) - assert.EqualError(t, Pipe{}.Publish(ctx), `put: upload failed: parse ://artifacts.company.com/example-repo-local/mybin/darwin/amd64/mybin: missing protocol scheme`) + assert.EqualError(t, Pipe{}.Publish(ctx), `upload: upload failed: parse ://artifacts.company.com/example-repo-local/mybin/darwin/amd64/mybin: missing protocol scheme`) } func TestRunPipe_SkipWhenPublishFalse(t *testing.T) { var ctx = context.New(config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { Name: "production", Mode: "binary", @@ -399,7 +408,7 @@ func TestRunPipe_SkipWhenPublishFalse(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.SkipPublish = true @@ -419,8 +428,9 @@ func TestRunPipe_DirUpload(t *testing.T) { var ctx = context.New(config.Project{ ProjectName: "mybin", Dist: dist, - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "binary", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -429,7 +439,7 @@ func TestRunPipe_DirUpload(t *testing.T) { }, }) ctx.Env = map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", } ctx.Artifacts.Add(&artifact.Artifact{ Name: "mybin", @@ -439,7 +449,7 @@ func TestRunPipe_DirUpload(t *testing.T) { Type: artifact.UploadableBinary, }) - assert.EqualError(t, Pipe{}.Publish(ctx), `put: upload failed: the asset to upload can't be a directory`) + assert.EqualError(t, Pipe{}.Publish(ctx), `upload: upload failed: the asset to upload can't be a directory`) } func TestDescription(t *testing.T) { @@ -453,11 +463,12 @@ func TestNoPuts(t *testing.T) { func TestPutsWithoutTarget(t *testing.T) { var ctx = &context.Context{ Env: map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Username: "deployuser", }, @@ -471,11 +482,12 @@ func TestPutsWithoutTarget(t *testing.T) { func TestPutsWithoutUsername(t *testing.T) { var ctx = &context.Context{ Env: map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", }, @@ -488,8 +500,9 @@ func TestPutsWithoutUsername(t *testing.T) { func TestPutsWithoutName(t *testing.T) { assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Username: "deployuser", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", }, @@ -499,8 +512,9 @@ func TestPutsWithoutName(t *testing.T) { func TestPutsWithoutSecret(t *testing.T) { assert.True(t, pipe.IsSkip(Pipe{}.Publish(context.New(config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", Username: "deployuser", @@ -512,11 +526,12 @@ func TestPutsWithoutSecret(t *testing.T) { func TestPutsWithInvalidMode(t *testing.T) { var ctx = &context.Context{ Env: map[string]string{ - "PUT_PRODUCTION_SECRET": "deployuser-secret", + "UPLOAD_PRODUCTION_SECRET": "deployuser-secret", }, Config: config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { + Method: h.MethodPut, Name: "production", Mode: "does-not-exists", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -531,7 +546,7 @@ func TestPutsWithInvalidMode(t *testing.T) { func TestDefault(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { Name: "production", Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", @@ -541,33 +556,36 @@ func TestDefault(t *testing.T) { }, } assert.NoError(t, Pipe{}.Default(ctx)) - assert.Len(t, ctx.Config.Puts, 1) - var put = ctx.Config.Puts[0] - assert.Equal(t, "archive", put.Mode) + assert.Len(t, ctx.Config.Uploads, 1) + var upload = ctx.Config.Uploads[0] + assert.Equal(t, "archive", upload.Mode) + assert.Equal(t, h.MethodPut, upload.Method) } func TestDefaultNoPuts(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Puts: []config.Put{}, + Uploads: []config.Upload{}, }, } assert.NoError(t, Pipe{}.Default(ctx)) - assert.Empty(t, ctx.Config.Puts) + assert.Empty(t, ctx.Config.Uploads) } func TestDefaultSet(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ - Puts: []config.Put{ + Uploads: []config.Upload{ { - Mode: "custom", + Method: h.MethodPost, + Mode: "custom", }, }, }, } assert.NoError(t, Pipe{}.Default(ctx)) - assert.Len(t, ctx.Config.Puts, 1) - var put = ctx.Config.Puts[0] - assert.Equal(t, "custom", put.Mode) + assert.Len(t, ctx.Config.Uploads, 1) + var upload = ctx.Config.Uploads[0] + assert.Equal(t, "custom", upload.Mode) + assert.Equal(t, h.MethodPost, upload.Method) } diff --git a/pkg/config/config.go b/pkg/config/config.go index 210f814f5b2..25a219149ce 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -331,13 +331,14 @@ type Blob struct { IDs []string `yaml:"ids,omitempty"` } -// Put HTTP upload configuration -type Put struct { +// Upload configuration +type Upload struct { Name string `yaml:",omitempty"` IDs []string `yaml:"ids,omitempty"` Target string `yaml:",omitempty"` Username string `yaml:",omitempty"` Mode string `yaml:",omitempty"` + Method string `yaml:",omitempty"` ChecksumHeader string `yaml:"checksum_header,omitempty"` TrustedCerts string `yaml:"trusted_certificates,omitempty"` Checksum bool `yaml:",omitempty"` @@ -362,8 +363,9 @@ type Project struct { Snapshot Snapshot `yaml:",omitempty"` Checksum Checksum `yaml:",omitempty"` Dockers []Docker `yaml:",omitempty"` - Artifactories []Put `yaml:",omitempty"` - Puts []Put `yaml:",omitempty"` + Artifactories []Upload `yaml:",omitempty"` + Uploads []Upload `yaml:",omitempty"` + Puts []Upload `yaml:",omitempty"` // TODO: remove this S3 []S3 `yaml:"s3,omitempty"` Blob []Blob `yaml:"blob,omitempty"` // TODO: remove this Blobs []Blob `yaml:"blobs,omitempty"` diff --git a/www/content/deprecations.md b/www/content/deprecations.md index 3a2be66e23b..3d0b027e758 100644 --- a/www/content/deprecations.md +++ b/www/content/deprecations.md @@ -39,6 +39,31 @@ to this: --> + +### puts + +> since 2019-11-15 + +The HTTP upload support was extended to also accept `POST` as a method, +so the name `puts` kind of lost its meaning. + +Change this: + +```yaml +puts: +- ... +``` + +to this: + +```yaml +uploads: +- ... +``` + +Also note that secrets environment variable name prefixes have changed from +`PUT_` to `UPLOAD_`. + ### nfpms.name_template > since 2019-11-15 diff --git a/www/content/put.md b/www/content/upload.md similarity index 78% rename from www/content/put.md rename to www/content/upload.md index 548d6aedb2c..5ae392a2fd1 100644 --- a/www/content/put.md +++ b/www/content/upload.md @@ -1,22 +1,23 @@ --- -title: HTTP Put +title: HTTP Upload series: customization hideFromIndex: true weight: 120 --- -GoReleaser supports building and pushing artifacts to HTTP servers using simple HTTP PUT requests. +GoReleaser supports building and pushing artifacts to HTTP servers using simple +HTTP requests. ## How it works -You can declare multiple Put instances. -All binaries generated by your `builds` section will be pushed to each configured Put. +You can declare multiple `uploads` instances. All binaries generated by your +`builds` section will be pushed to each configured upload. -If you have only one Put instance, the configuration is as easy as adding the -upload target and a username to your `.goreleaser.yml` file: +If you have only one `uploads` instance, the configuration is as easy as adding +the upload target and a username to your `.goreleaser.yml` file: ```yaml -puts: +uploads: - name: production target: http://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/ username: goreleaser @@ -24,8 +25,8 @@ puts: Prerequisites: -- An HTTP server accepting PUT requests -- A user + password with grants to upload an artifact using PUT requests (if the server requires it) +- An HTTP server accepting HTTP requests +- A user + password with grants to upload an artifact using HTTP requests (if the server requires it) ### Target @@ -63,9 +64,9 @@ This way we support auth for multiple instances. This also means that the `name` per configured instance needs to be unique per goreleaser configuration. -The name of the environment variable will be `PUT_NAME_USERNAME`. +The name of the environment variable will be `UPLOAD_NAME_USERNAME`. If your instance is named `production`, you can store the username in the -environment variable `PUT_PRODUCTION_USERNAME`. +environment variable `UPLOAD_PRODUCTION_USERNAME`. The name will be transformed to uppercase. If a configured username is found in the configuration file, then the @@ -79,24 +80,24 @@ This way we support auth for multiple instances. This also means that the `name` per configured instance needs to be unique per goreleaser configuration. -The name of the environment variable will be `PUT_NAME_SECRET`. +The name of the environment variable will be `UPLOAD_NAME_SECRET`. If your instance is named `production`, you need to store the secret in the -environment variable `PUT_PRODUCTION_SECRET`. +environment variable `UPLOAD_PRODUCTION_SECRET`. The name will be transformed to uppercase. ### Server authentication You can authenticate your TLS server adding a trusted X.509 certificate chain -in your put configuration. +in your upload configuration. The trusted certificate chain will be used to validate the server certificates. You can set the trusted certificate chain using the `trusted_certificates` -setting the put section with PEM encoded certificates on a YAML literal block +setting the upload section with PEM encoded certificates on a YAML literal block like this: ```yaml -puts: +uploads: - name: "some HTTP/TLS server" #...(other settings)... trusted_certificates: | @@ -118,13 +119,17 @@ Of course, you can customize a lot of things: ```yaml # .goreleaser.yml -puts: - # You can have multiple Put instances. +uploads: + # You can have multiple upload instances. - - # Unique name of your Put instance. Used to identify the instance. + # Unique name of your upload instance. Used to identify the instance. name: production - # IDs of the artifacts you want to PUT. + # HTTP method to use. + # Default: PUT + method: POST + + # IDs of the artifacts you want to upload. ids: - foo - bar @@ -135,7 +140,7 @@ puts: # Default is `archive`. mode: archive - # URL to be used as target of the HTTP PUT request + # URL to be used as target of the HTTP request target: https://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/ # User that will be used for the deployment