You've already forked goreleaser
							
							
				mirror of
				https://github.com/goreleaser/goreleaser.git
				synced 2025-10-30 23:58:09 +02:00 
			
		
		
		
	feat: http POST (#1246)
* feat: http POST Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * feat: http POST Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: deprecate Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: upload tests Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: artifactory Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: http username validation Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com> * fix: renames Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							173edbac54
						
					
				
				
					commit
					b0481a14e0
				
			
							
								
								
									
										1
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								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= | ||||
|   | ||||
| @@ -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 put.TrustedCerts != "" && !x509.NewCertPool().AppendCertsFromPEM([]byte(put.TrustedCerts)) { | ||||
| 		return misconfigured(kind, put, "no certificate could be added from the specified trusted_certificates configuration") | ||||
| 	if _, err := getPassword(ctx, upload, kind); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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", | ||||
| 				}, | ||||
|   | ||||
| @@ -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{}, | ||||
|   | ||||
| @@ -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) | ||||
| 		} | ||||
| @@ -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) | ||||
| } | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
		Reference in New Issue
	
	Block a user