You've already forked goreleaser
							
							
				mirror of
				https://github.com/goreleaser/goreleaser.git
				synced 2025-10-30 23:58:09 +02:00 
			
		
		
		
	feat: multiple archives (#942)
* feat: multiple archives * fix: several things * test: fixed * fix: several things * fix: archive id on the artifact * fix: deprecated since * docs: deprecations page improvements
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							d8818c2683
						
					
				
				
					commit
					b8f5901265
				
			| @@ -61,17 +61,18 @@ dockers: | ||||
|  | ||||
|   extra_files: | ||||
|   - scripts/entrypoint.sh | ||||
| archive: | ||||
|   name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' | ||||
|   replacements: | ||||
|     darwin: Darwin | ||||
|     linux: Linux | ||||
|     windows: Windows | ||||
|     386: i386 | ||||
|     amd64: x86_64 | ||||
|   format_overrides: | ||||
|   - goos: windows | ||||
|     format: zip | ||||
| archives: | ||||
|   - | ||||
|     name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' | ||||
|     replacements: | ||||
|       darwin: Darwin | ||||
|       linux: Linux | ||||
|       windows: Windows | ||||
|       386: i386 | ||||
|       amd64: x86_64 | ||||
|     format_overrides: | ||||
|     - goos: windows | ||||
|       format: zip | ||||
| brew: | ||||
|   github: | ||||
|     owner: goreleaser | ||||
|   | ||||
| @@ -193,6 +193,18 @@ func ByType(t Type) Filter { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ByIDs filter artifacts by an `ID` extra field. | ||||
| func ByIDs(ids ...string) Filter { | ||||
| 	var filters = make([]Filter, 0, len(ids)) | ||||
| 	for _, id := range ids { | ||||
| 		id := id | ||||
| 		filters = append(filters, func(a Artifact) bool { | ||||
| 			return a.ExtraOr("ID", "") == id | ||||
| 		}) | ||||
| 	} | ||||
| 	return Or(filters...) | ||||
| } | ||||
|  | ||||
| // Or performs an OR between all given filters | ||||
| func Or(filters ...Filter) Filter { | ||||
| 	return func(a Artifact) bool { | ||||
|   | ||||
| @@ -195,3 +195,40 @@ func TestExtraOr(t *testing.T) { | ||||
| 	require.Equal(t, "foo", a.ExtraOr("Foo", "bar")) | ||||
| 	require.Equal(t, "bar", a.ExtraOr("Foobar", "bar")) | ||||
| } | ||||
|  | ||||
| func TestByIDs(t *testing.T) { | ||||
| 	var data = []Artifact{ | ||||
| 		{ | ||||
| 			Name: "foo", | ||||
| 			Extra: map[string]interface{}{ | ||||
| 				"ID": "foo", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "bar", | ||||
| 			Extra: map[string]interface{}{ | ||||
| 				"ID": "bar", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "foobar", | ||||
| 			Extra: map[string]interface{}{ | ||||
| 				"ID": "foo", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Name: "check", | ||||
| 			Extra: map[string]interface{}{ | ||||
| 				"ID": "check", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	var artifacts = New() | ||||
| 	for _, a := range data { | ||||
| 		artifacts.Add(a) | ||||
| 	} | ||||
|  | ||||
| 	require.Len(t, artifacts.Filter(ByIDs("check")).items, 1) | ||||
| 	require.Len(t, artifacts.Filter(ByIDs("foo")).items, 2) | ||||
| 	require.Len(t, artifacts.Filter(ByIDs("foo", "bar")).items, 3) | ||||
| } | ||||
|   | ||||
| @@ -7,19 +7,22 @@ import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/goreleaser/goreleaser/internal/deprecate" | ||||
|  | ||||
| 	"github.com/apex/log" | ||||
| 	"github.com/campoy/unique" | ||||
| 	zglob "github.com/mattn/go-zglob" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
|  | ||||
| 	"github.com/goreleaser/goreleaser/internal/artifact" | ||||
| 	"github.com/goreleaser/goreleaser/internal/semerrgroup" | ||||
| 	"github.com/goreleaser/goreleaser/internal/tmpl" | ||||
| 	"github.com/goreleaser/goreleaser/pkg/archive" | ||||
| 	archivelib "github.com/goreleaser/goreleaser/pkg/archive" | ||||
| 	"github.com/goreleaser/goreleaser/pkg/config" | ||||
| 	"github.com/goreleaser/goreleaser/pkg/context" | ||||
| 	zglob "github.com/mattn/go-zglob" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -39,26 +42,50 @@ func (Pipe) String() string { | ||||
|  | ||||
| // Default sets the pipe defaults | ||||
| func (Pipe) Default(ctx *context.Context) error { | ||||
| 	var archive = &ctx.Config.Archive | ||||
| 	if archive.Format == "" { | ||||
| 		archive.Format = "tar.gz" | ||||
| 	} | ||||
| 	if len(archive.Files) == 0 { | ||||
| 		archive.Files = []string{ | ||||
| 			"licence*", | ||||
| 			"LICENCE*", | ||||
| 			"license*", | ||||
| 			"LICENSE*", | ||||
| 			"readme*", | ||||
| 			"README*", | ||||
| 			"changelog*", | ||||
| 			"CHANGELOG*", | ||||
| 	var ids = map[string]int{} | ||||
| 	if len(ctx.Config.Archives) == 0 { | ||||
| 		ctx.Config.Archives = append(ctx.Config.Archives, ctx.Config.Archive) | ||||
| 		if !reflect.DeepEqual(ctx.Config.Archive, config.Archive{}) { | ||||
| 			deprecate.Notice("archive") | ||||
| 		} | ||||
| 	} | ||||
| 	if archive.NameTemplate == "" { | ||||
| 		archive.NameTemplate = defaultNameTemplate | ||||
| 		if archive.Format == "binary" { | ||||
| 			archive.NameTemplate = defaultBinaryNameTemplate | ||||
| 	for i := range ctx.Config.Archives { | ||||
| 		var archive = &ctx.Config.Archives[i] | ||||
| 		if archive.Format == "" { | ||||
| 			archive.Format = "tar.gz" | ||||
| 		} | ||||
| 		if archive.ID == "" { | ||||
| 			archive.ID = "default" | ||||
| 		} | ||||
| 		if len(archive.Files) == 0 { | ||||
| 			archive.Files = []string{ | ||||
| 				"licence*", | ||||
| 				"LICENCE*", | ||||
| 				"license*", | ||||
| 				"LICENSE*", | ||||
| 				"readme*", | ||||
| 				"README*", | ||||
| 				"changelog*", | ||||
| 				"CHANGELOG*", | ||||
| 			} | ||||
| 		} | ||||
| 		if archive.NameTemplate == "" { | ||||
| 			archive.NameTemplate = defaultNameTemplate | ||||
| 			if archive.Format == "binary" { | ||||
| 				archive.NameTemplate = defaultBinaryNameTemplate | ||||
| 			} | ||||
| 		} | ||||
| 		if len(archive.Builds) == 0 { | ||||
| 			for _, build := range ctx.Config.Builds { | ||||
| 				archive.Builds = append(archive.Builds, build.ID) | ||||
| 			} | ||||
| 		} | ||||
| 		ids[archive.ID]++ | ||||
| 	} | ||||
|  | ||||
| 	for id, cont := range ids { | ||||
| 		if cont > 1 { | ||||
| 			return fmt.Errorf("found %d archives with the ID '%s', please fix your config", cont, id) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| @@ -66,26 +93,34 @@ func (Pipe) Default(ctx *context.Context) error { | ||||
|  | ||||
| // Run the pipe | ||||
| func (Pipe) Run(ctx *context.Context) error { | ||||
| 	var g errgroup.Group // TODO: use semerrgroup here | ||||
| 	var filtered = ctx.Artifacts.Filter(artifact.ByType(artifact.Binary)) | ||||
| 	for group, artifacts := range filtered.GroupByPlatform() { | ||||
| 		log.Debugf("group %s has %d binaries", group, len(artifacts)) | ||||
| 		artifacts := artifacts | ||||
| 		g.Go(func() error { | ||||
| 			if packageFormat(ctx, artifacts[0].Goos) == "binary" { | ||||
| 				return skip(ctx, artifacts) | ||||
| 			} | ||||
| 			return create(ctx, artifacts) | ||||
| 		}) | ||||
| 	var g = semerrgroup.New(ctx.Parallelism) | ||||
| 	for _, archive := range ctx.Config.Archives { | ||||
| 		archive := archive | ||||
| 		var filtered = ctx.Artifacts.Filter( | ||||
| 			artifact.And( | ||||
| 				artifact.ByType(artifact.Binary), | ||||
| 				artifact.ByIDs(archive.Builds...), | ||||
| 			), | ||||
| 		) | ||||
| 		for group, artifacts := range filtered.GroupByPlatform() { | ||||
| 			log.Debugf("group %s has %d binaries", group, len(artifacts)) | ||||
| 			artifacts := artifacts | ||||
| 			g.Go(func() error { | ||||
| 				if packageFormat(archive, artifacts[0].Goos) == "binary" { | ||||
| 					return skip(ctx, archive, artifacts) | ||||
| 				} | ||||
| 				return create(ctx, archive, artifacts) | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return g.Wait() | ||||
| } | ||||
|  | ||||
| func create(ctx *context.Context, binaries []artifact.Artifact) error { | ||||
| 	var format = packageFormat(ctx, binaries[0].Goos) | ||||
| func create(ctx *context.Context, archive config.Archive, binaries []artifact.Artifact) error { | ||||
| 	var format = packageFormat(archive, binaries[0].Goos) | ||||
| 	folder, err := tmpl.New(ctx). | ||||
| 		WithArtifact(binaries[0], ctx.Config.Archive.Replacements). | ||||
| 		Apply(ctx.Config.Archive.NameTemplate) | ||||
| 		WithArtifact(binaries[0], archive.Replacements). | ||||
| 		Apply(archive.NameTemplate) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -107,16 +142,16 @@ func create(ctx *context.Context, binaries []artifact.Artifact) error { | ||||
| 	log.Info("creating") | ||||
|  | ||||
| 	wrap, err := tmpl.New(ctx). | ||||
| 		WithArtifact(binaries[0], ctx.Config.Archive.Replacements). | ||||
| 		Apply(wrapFolder(ctx.Config.Archive)) | ||||
| 		WithArtifact(binaries[0], archive.Replacements). | ||||
| 		Apply(wrapFolder(archive)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var a = NewEnhancedArchive(archive.New(archiveFile), wrap) | ||||
| 	var a = NewEnhancedArchive(archivelib.New(archiveFile), wrap) | ||||
| 	defer a.Close() // nolint: errcheck | ||||
|  | ||||
| 	files, err := findFiles(ctx) | ||||
| 	files, err := findFiles(archive) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to find files to archive: %s", err.Error()) | ||||
| 	} | ||||
| @@ -139,6 +174,7 @@ func create(ctx *context.Context, binaries []artifact.Artifact) error { | ||||
| 		Goarm:  binaries[0].Goarm, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Builds": binaries, | ||||
| 			"ID":     archive.ID, | ||||
| 		}, | ||||
| 	}) | ||||
| 	return nil | ||||
| @@ -155,12 +191,12 @@ func wrapFolder(a config.Archive) string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func skip(ctx *context.Context, binaries []artifact.Artifact) error { | ||||
| func skip(ctx *context.Context, archive config.Archive, binaries []artifact.Artifact) error { | ||||
| 	for _, binary := range binaries { | ||||
| 		log.WithField("binary", binary.Name).Info("skip archiving") | ||||
| 		name, err := tmpl.New(ctx). | ||||
| 			WithArtifact(binary, ctx.Config.Archive.Replacements). | ||||
| 			Apply(ctx.Config.Archive.NameTemplate) | ||||
| 			WithArtifact(binary, archive.Replacements). | ||||
| 			Apply(archive.NameTemplate) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| @@ -173,14 +209,15 @@ func skip(ctx *context.Context, binaries []artifact.Artifact) error { | ||||
| 			Goarm:  binary.Goarm, | ||||
| 			Extra: map[string]interface{}{ | ||||
| 				"Builds": []artifact.Artifact{binary}, | ||||
| 				"ID":     archive.ID, | ||||
| 			}, | ||||
| 		}) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func findFiles(ctx *context.Context) (result []string, err error) { | ||||
| 	for _, glob := range ctx.Config.Archive.Files { | ||||
| func findFiles(archive config.Archive) (result []string, err error) { | ||||
| 	for _, glob := range archive.Files { | ||||
| 		files, err := zglob.Glob(glob) | ||||
| 		if err != nil { | ||||
| 			return result, fmt.Errorf("globbing failed for pattern %s: %s", glob, err.Error()) | ||||
| @@ -194,13 +231,13 @@ func findFiles(ctx *context.Context) (result []string, err error) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func packageFormat(ctx *context.Context, platform string) string { | ||||
| 	for _, override := range ctx.Config.Archive.FormatOverrides { | ||||
| func packageFormat(archive config.Archive, platform string) string { | ||||
| 	for _, override := range archive.FormatOverrides { | ||||
| 		if strings.HasPrefix(platform, override.Goos) { | ||||
| 			return override.Format | ||||
| 		} | ||||
| 	} | ||||
| 	return ctx.Config.Archive.Format | ||||
| 	return archive.Format | ||||
| } | ||||
|  | ||||
| // NewEnhancedArchive enhances a pre-existing archive.Archive instance | ||||
|   | ||||
| @@ -44,16 +44,20 @@ func TestRunPipe(t *testing.T) { | ||||
| 				config.Project{ | ||||
| 					Dist:        dist, | ||||
| 					ProjectName: "foobar", | ||||
| 					Archive: config.Archive{ | ||||
| 						NameTemplate: defaultNameTemplate, | ||||
| 						Files: []string{ | ||||
| 							"README.*", | ||||
| 							"./foo/**/*", | ||||
| 						}, | ||||
| 						FormatOverrides: []config.FormatOverride{ | ||||
| 							{ | ||||
| 								Goos:   "windows", | ||||
| 								Format: "zip", | ||||
| 					Archives: []config.Archive{ | ||||
| 						{ | ||||
| 							ID:           "defaultarch", | ||||
| 							Builds:       []string{"default"}, | ||||
| 							NameTemplate: defaultNameTemplate, | ||||
| 							Files: []string{ | ||||
| 								"README.*", | ||||
| 								"./foo/**/*", | ||||
| 							}, | ||||
| 							FormatOverrides: []config.FormatOverride{ | ||||
| 								{ | ||||
| 									Goos:   "windows", | ||||
| 									Format: "zip", | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| @@ -67,6 +71,7 @@ func TestRunPipe(t *testing.T) { | ||||
| 				Type:   artifact.Binary, | ||||
| 				Extra: map[string]interface{}{ | ||||
| 					"Binary": "mybin", | ||||
| 					"ID":     "default", | ||||
| 				}, | ||||
| 			} | ||||
| 			var windowsBuild = artifact.Artifact{ | ||||
| @@ -78,15 +83,19 @@ func TestRunPipe(t *testing.T) { | ||||
| 				Extra: map[string]interface{}{ | ||||
| 					"Binary":    "mybin", | ||||
| 					"Extension": ".exe", | ||||
| 					"ID":        "default", | ||||
| 				}, | ||||
| 			} | ||||
| 			ctx.Artifacts.Add(darwinBuild) | ||||
| 			ctx.Artifacts.Add(windowsBuild) | ||||
| 			ctx.Version = "0.0.1" | ||||
| 			ctx.Git.CurrentTag = "v0.0.1" | ||||
| 			ctx.Config.Archive.Format = format | ||||
| 			ctx.Config.Archives[0].Format = format | ||||
| 			require.NoError(tt, Pipe{}.Run(ctx)) | ||||
| 			var archives = ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive)) | ||||
| 			for _, arch := range archives.List() { | ||||
| 				require.Equal(t, "defaultarch", arch.Extra["ID"].(string), "all archives should have the archive ID set") | ||||
| 			} | ||||
| 			require.Len(tt, archives.List(), 2) | ||||
| 			darwin := archives.Filter(artifact.ByGoos("darwin")).List()[0] | ||||
| 			windows := archives.Filter(artifact.ByGoos("windows")).List()[0] | ||||
| @@ -175,9 +184,12 @@ func TestRunPipeBinary(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: dist, | ||||
| 			Archive: config.Archive{ | ||||
| 				Format:       "binary", | ||||
| 				NameTemplate: defaultBinaryNameTemplate, | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Format:       "binary", | ||||
| 					NameTemplate: defaultBinaryNameTemplate, | ||||
| 					Builds:       []string{"default"}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| @@ -191,6 +203,7 @@ func TestRunPipeBinary(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	ctx.Artifacts.Add(artifact.Artifact{ | ||||
| @@ -202,6 +215,7 @@ func TestRunPipeBinary(t *testing.T) { | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"Ext":    ".exe", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.NoError(t, Pipe{}.Run(ctx)) | ||||
| @@ -217,9 +231,12 @@ func TestRunPipeDistRemoved(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: "/path/nope", | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate: "nope", | ||||
| 				Format:       "zip", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					NameTemplate: "nope", | ||||
| 					Format:       "zip", | ||||
| 					Builds:       []string{"default"}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| @@ -233,6 +250,7 @@ func TestRunPipeDistRemoved(t *testing.T) { | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary":    "mybin", | ||||
| 			"Extension": ".exe", | ||||
| 			"ID":        "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.EqualError(t, Pipe{}.Run(ctx), `failed to create directory /path/nope/nope.zip: open /path/nope/nope.zip: no such file or directory`) | ||||
| @@ -249,11 +267,14 @@ func TestRunPipeInvalidGlob(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: dist, | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate: "foo", | ||||
| 				Format:       "zip", | ||||
| 				Files: []string{ | ||||
| 					"[x-]", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:       []string{"default"}, | ||||
| 					NameTemplate: "foo", | ||||
| 					Format:       "zip", | ||||
| 					Files: []string{ | ||||
| 						"[x-]", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| @@ -267,6 +288,7 @@ func TestRunPipeInvalidGlob(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.EqualError(t, Pipe{}.Run(ctx), `failed to find files to archive: globbing failed for pattern [x-]: file does not exist`) | ||||
| @@ -283,9 +305,12 @@ func TestRunPipeInvalidNameTemplate(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: dist, | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate: "foo{{ .fff }", | ||||
| 				Format:       "zip", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:       []string{"default"}, | ||||
| 					NameTemplate: "foo{{ .fff }", | ||||
| 					Format:       "zip", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| @@ -298,6 +323,7 @@ func TestRunPipeInvalidNameTemplate(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.EqualError(t, Pipe{}.Run(ctx), `template: tmpl:1: unexpected "}" in operand`) | ||||
| @@ -314,10 +340,13 @@ func TestRunPipeInvalidWrapInDirectoryTemplate(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: dist, | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate:    "foo", | ||||
| 				WrapInDirectory: "foo{{ .fff }", | ||||
| 				Format:          "zip", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:          []string{"default"}, | ||||
| 					NameTemplate:    "foo", | ||||
| 					WrapInDirectory: "foo{{ .fff }", | ||||
| 					Format:          "zip", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| @@ -330,6 +359,7 @@ func TestRunPipeInvalidWrapInDirectoryTemplate(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.EqualError(t, Pipe{}.Run(ctx), `template: tmpl:1: unexpected "}" in operand`) | ||||
| @@ -348,15 +378,18 @@ func TestRunPipeWrap(t *testing.T) { | ||||
| 	var ctx = context.New( | ||||
| 		config.Project{ | ||||
| 			Dist: dist, | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate:    "foo", | ||||
| 				WrapInDirectory: "foo_{{ .Os }}", | ||||
| 				Format:          "tar.gz", | ||||
| 				Replacements: map[string]string{ | ||||
| 					"darwin": "macOS", | ||||
| 				}, | ||||
| 				Files: []string{ | ||||
| 					"README.*", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:          []string{"default"}, | ||||
| 					NameTemplate:    "foo", | ||||
| 					WrapInDirectory: "foo_{{ .Os }}", | ||||
| 					Format:          "tar.gz", | ||||
| 					Replacements: map[string]string{ | ||||
| 						"darwin": "macOS", | ||||
| 					}, | ||||
| 					Files: []string{ | ||||
| 						"README.*", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| @@ -370,6 +403,7 @@ func TestRunPipeWrap(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	require.NoError(t, Pipe{}.Run(ctx)) | ||||
| @@ -395,61 +429,69 @@ func TestRunPipeWrap(t *testing.T) { | ||||
| func TestDefault(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archive: config.Archive{}, | ||||
| 			Archives: []config.Archive{}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.NoError(t, Pipe{}.Default(ctx)) | ||||
| 	require.NotEmpty(t, ctx.Config.Archive.NameTemplate) | ||||
| 	require.Equal(t, "tar.gz", ctx.Config.Archive.Format) | ||||
| 	require.NotEmpty(t, ctx.Config.Archive.Files) | ||||
| 	require.NotEmpty(t, ctx.Config.Archives[0].NameTemplate) | ||||
| 	require.Equal(t, "tar.gz", ctx.Config.Archives[0].Format) | ||||
| 	require.NotEmpty(t, ctx.Config.Archives[0].Files) | ||||
| } | ||||
|  | ||||
| func TestDefaultSet(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate: "foo", | ||||
| 				Format:       "zip", | ||||
| 				Files: []string{ | ||||
| 					"foo", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.NoError(t, Pipe{}.Default(ctx)) | ||||
| 	require.Equal(t, "foo", ctx.Config.Archive.NameTemplate) | ||||
| 	require.Equal(t, "zip", ctx.Config.Archive.Format) | ||||
| 	require.Equal(t, "foo", ctx.Config.Archive.Files[0]) | ||||
| } | ||||
|  | ||||
| func TestDefaultFormatBinary(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archive: config.Archive{ | ||||
| 				Format: "binary", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.NoError(t, Pipe{}.Default(ctx)) | ||||
| 	require.Equal(t, defaultBinaryNameTemplate, ctx.Config.Archive.NameTemplate) | ||||
| } | ||||
|  | ||||
| func TestFormatFor(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archive: config.Archive{ | ||||
| 				Format: "tar.gz", | ||||
| 				FormatOverrides: []config.FormatOverride{ | ||||
| 					{ | ||||
| 						Goos:   "windows", | ||||
| 						Format: "zip", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:       []string{"default"}, | ||||
| 					NameTemplate: "foo", | ||||
| 					Format:       "zip", | ||||
| 					Files: []string{ | ||||
| 						"foo", | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.Equal(t, "zip", packageFormat(ctx, "windows")) | ||||
| 	require.Equal(t, "tar.gz", packageFormat(ctx, "linux")) | ||||
| 	require.NoError(t, Pipe{}.Default(ctx)) | ||||
| 	require.Equal(t, "foo", ctx.Config.Archives[0].NameTemplate) | ||||
| 	require.Equal(t, "zip", ctx.Config.Archives[0].Format) | ||||
| 	require.Equal(t, "foo", ctx.Config.Archives[0].Files[0]) | ||||
| } | ||||
|  | ||||
| func TestDefaultFormatBinary(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Format: "binary", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.NoError(t, Pipe{}.Default(ctx)) | ||||
| 	require.Equal(t, defaultBinaryNameTemplate, ctx.Config.Archives[0].NameTemplate) | ||||
| } | ||||
|  | ||||
| func TestFormatFor(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds: []string{"default"}, | ||||
| 					Format: "tar.gz", | ||||
| 					FormatOverrides: []config.FormatOverride{ | ||||
| 						{ | ||||
| 							Goos:   "windows", | ||||
| 							Format: "zip", | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.Equal(t, "zip", packageFormat(ctx.Config.Archives[0], "windows")) | ||||
| 	require.Equal(t, "tar.gz", packageFormat(ctx.Config.Archives[0], "linux")) | ||||
| } | ||||
|  | ||||
| func TestBinaryOverride(t *testing.T) { | ||||
| @@ -471,15 +513,18 @@ func TestBinaryOverride(t *testing.T) { | ||||
| 				config.Project{ | ||||
| 					Dist:        dist, | ||||
| 					ProjectName: "foobar", | ||||
| 					Archive: config.Archive{ | ||||
| 						NameTemplate: defaultNameTemplate, | ||||
| 						Files: []string{ | ||||
| 							"README.*", | ||||
| 						}, | ||||
| 						FormatOverrides: []config.FormatOverride{ | ||||
| 							{ | ||||
| 								Goos:   "windows", | ||||
| 								Format: "binary", | ||||
| 					Archives: []config.Archive{ | ||||
| 						{ | ||||
| 							Builds:       []string{"default"}, | ||||
| 							NameTemplate: defaultNameTemplate, | ||||
| 							Files: []string{ | ||||
| 								"README.*", | ||||
| 							}, | ||||
| 							FormatOverrides: []config.FormatOverride{ | ||||
| 								{ | ||||
| 									Goos:   "windows", | ||||
| 									Format: "binary", | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| @@ -494,6 +539,7 @@ func TestBinaryOverride(t *testing.T) { | ||||
| 				Type:   artifact.Binary, | ||||
| 				Extra: map[string]interface{}{ | ||||
| 					"Binary": "mybin", | ||||
| 					"ID":     "default", | ||||
| 				}, | ||||
| 			}) | ||||
| 			ctx.Artifacts.Add(artifact.Artifact{ | ||||
| @@ -505,10 +551,11 @@ func TestBinaryOverride(t *testing.T) { | ||||
| 				Extra: map[string]interface{}{ | ||||
| 					"Binary": "mybin", | ||||
| 					"Ext":    ".exe", | ||||
| 					"ID":     "default", | ||||
| 				}, | ||||
| 			}) | ||||
| 			ctx.Version = "0.0.1" | ||||
| 			ctx.Config.Archive.Format = format | ||||
| 			ctx.Config.Archives[0].Format = format | ||||
|  | ||||
| 			require.NoError(tt, Pipe{}.Run(ctx)) | ||||
| 			var archives = ctx.Artifacts.Filter(artifact.ByType(artifact.UploadableArchive)) | ||||
| @@ -537,13 +584,16 @@ func TestRunPipeSameArchiveFilename(t *testing.T) { | ||||
| 		config.Project{ | ||||
| 			Dist:        dist, | ||||
| 			ProjectName: "foobar", | ||||
| 			Archive: config.Archive{ | ||||
| 				NameTemplate: "same-filename", | ||||
| 				Files: []string{ | ||||
| 					"README.*", | ||||
| 					"./foo/**/*", | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					Builds:       []string{"default"}, | ||||
| 					NameTemplate: "same-filename", | ||||
| 					Files: []string{ | ||||
| 						"README.*", | ||||
| 						"./foo/**/*", | ||||
| 					}, | ||||
| 					Format: "tar.gz", | ||||
| 				}, | ||||
| 				Format: "tar.gz", | ||||
| 			}, | ||||
| 		}, | ||||
| 	) | ||||
| @@ -555,6 +605,7 @@ func TestRunPipeSameArchiveFilename(t *testing.T) { | ||||
| 		Type:   artifact.Binary, | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary": "mybin", | ||||
| 			"ID":     "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	ctx.Artifacts.Add(artifact.Artifact{ | ||||
| @@ -566,6 +617,7 @@ func TestRunPipeSameArchiveFilename(t *testing.T) { | ||||
| 		Extra: map[string]interface{}{ | ||||
| 			"Binary":    "mybin", | ||||
| 			"Extension": ".exe", | ||||
| 			"ID":        "default", | ||||
| 		}, | ||||
| 	}) | ||||
| 	ctx.Version = "0.0.1" | ||||
| @@ -610,3 +662,19 @@ func TestWrapInDirectory(t *testing.T) { | ||||
| 		})) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestSeveralArchivesWithTheSameID(t *testing.T) { | ||||
| 	var ctx = &context.Context{ | ||||
| 		Config: config.Project{ | ||||
| 			Archives: []config.Archive{ | ||||
| 				{ | ||||
| 					ID: "a", | ||||
| 				}, | ||||
| 				{ | ||||
| 					ID: "a", | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	require.EqualError(t, Pipe{}.Default(ctx), "found 2 archives with the ID 'a', please fix your config") | ||||
| } | ||||
|   | ||||
| @@ -53,7 +53,7 @@ func (Pipe) Default(ctx *context.Context) error { | ||||
| 	} | ||||
| 	for id, cont := range ids { | ||||
| 		if cont > 1 { | ||||
| 			return fmt.Errorf("there are more than %d builds with the ID '%s', please fix your config", cont, id) | ||||
| 			return fmt.Errorf("found %d builds with the ID '%s', please fix your config", cont, id) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
|   | ||||
| @@ -235,7 +235,7 @@ func TestSeveralBuildsWithTheSameID(t *testing.T) { | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	assert.EqualError(t, Pipe{}.Default(ctx), "there are more than 2 builds with the ID 'a', please fix your config") | ||||
| 	assert.EqualError(t, Pipe{}.Default(ctx), "found 2 builds with the ID 'a', please fix your config") | ||||
| } | ||||
|  | ||||
| func TestDefaultPartialBuilds(t *testing.T) { | ||||
|   | ||||
| @@ -34,13 +34,13 @@ func TestFillBasicData(t *testing.T) { | ||||
| 	assert.Contains(t, ctx.Config.Builds[0].Goos, "linux") | ||||
| 	assert.Contains(t, ctx.Config.Builds[0].Goarch, "386") | ||||
| 	assert.Contains(t, ctx.Config.Builds[0].Goarch, "amd64") | ||||
| 	assert.Equal(t, "tar.gz", ctx.Config.Archive.Format) | ||||
| 	assert.Equal(t, "tar.gz", ctx.Config.Archives[0].Format) | ||||
| 	assert.Contains(t, ctx.Config.Brew.Install, "bin.install \"goreleaser\"") | ||||
| 	assert.Empty(t, ctx.Config.Dockers) | ||||
| 	assert.Equal(t, "https://github.com", ctx.Config.GitHubURLs.Download) | ||||
| 	assert.NotEmpty(t, ctx.Config.Archive.NameTemplate) | ||||
| 	assert.NotEmpty(t, ctx.Config.Archives[0].NameTemplate) | ||||
| 	assert.NotEmpty(t, ctx.Config.Builds[0].Ldflags) | ||||
| 	assert.NotEmpty(t, ctx.Config.Archive.Files) | ||||
| 	assert.NotEmpty(t, ctx.Config.Archives[0].Files) | ||||
| 	assert.NotEmpty(t, ctx.Config.Dist) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -13,8 +13,8 @@ before: | ||||
| builds: | ||||
| - env: | ||||
|   - CGO_ENABLED=0 | ||||
| archive: | ||||
|   replacements: | ||||
| archives: | ||||
| - replacements: | ||||
|     darwin: Darwin | ||||
|     linux: Linux | ||||
|     windows: Windows | ||||
|   | ||||
| @@ -148,13 +148,14 @@ type FormatOverride struct { | ||||
|  | ||||
| // Archive config used for the archive | ||||
| type Archive struct { | ||||
| 	NameTemplate string            `yaml:"name_template,omitempty"` | ||||
| 	Replacements map[string]string `yaml:",omitempty"` | ||||
|  | ||||
| 	Format          string           `yaml:",omitempty"` | ||||
| 	FormatOverrides []FormatOverride `yaml:"format_overrides,omitempty"` | ||||
| 	WrapInDirectory string           `yaml:"wrap_in_directory,omitempty"` | ||||
| 	Files           []string         `yaml:",omitempty"` | ||||
| 	ID              string            `yaml:",omitempty"` | ||||
| 	Builds          []string          `yaml:",omitempty"` | ||||
| 	NameTemplate    string            `yaml:"name_template,omitempty"` | ||||
| 	Replacements    map[string]string `yaml:",omitempty"` | ||||
| 	Format          string            `yaml:",omitempty"` | ||||
| 	FormatOverrides []FormatOverride  `yaml:"format_overrides,omitempty"` | ||||
| 	WrapInDirectory string            `yaml:"wrap_in_directory,omitempty"` | ||||
| 	Files           []string          `yaml:",omitempty"` | ||||
| } | ||||
|  | ||||
| // Release config used for the GitHub release | ||||
| @@ -312,7 +313,8 @@ type Project struct { | ||||
| 	Brew          Homebrew  `yaml:",omitempty"` | ||||
| 	Scoop         Scoop     `yaml:",omitempty"` | ||||
| 	Builds        []Build   `yaml:",omitempty"` | ||||
| 	Archive       Archive   `yaml:",omitempty"` | ||||
| 	Archive       Archive   `yaml:",omitempty"` // TODO: remove this | ||||
| 	Archives      []Archive `yaml:",omitempty"` | ||||
| 	NFPM          NFPM      `yaml:",omitempty"` | ||||
| 	Snapcraft     Snapcraft `yaml:",omitempty"` | ||||
| 	Snapshot      Snapshot  `yaml:",omitempty"` | ||||
|   | ||||
| @@ -39,8 +39,8 @@ var Defaulters = []Defaulter{ | ||||
| 	snapshot.Pipe{}, | ||||
| 	release.Pipe{}, | ||||
| 	project.Pipe{}, | ||||
| 	archive.Pipe{}, | ||||
| 	build.Pipe{}, | ||||
| 	archive.Pipe{}, | ||||
| 	nfpm.Pipe{}, | ||||
| 	snapcraft.Pipe{}, | ||||
| 	checksums.Pipe{}, | ||||
|   | ||||
| @@ -6,63 +6,72 @@ weight: 40 | ||||
| --- | ||||
|  | ||||
| The binaries built will be archived together with the `README` and `LICENSE` files into a | ||||
| `tar.gz` file. In the `archive` section you can customize the archive name, | ||||
| `tar.gz` file. In the `archives` section you can customize the archive name, | ||||
| additional files, and format. | ||||
|  | ||||
| Here is a commented `archive` section with all fields specified: | ||||
| Here is a commented `archives` section with all fields specified: | ||||
|  | ||||
| ```yml | ||||
| # .goreleaser.yml | ||||
| archive: | ||||
|   # Archive name template. | ||||
|   # Defaults: | ||||
|   # - if format is `tar.gz`, `gz` or `zip`: | ||||
|   #   - `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` | ||||
|   # - if format is `binary`: | ||||
|   #   - `{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` | ||||
|   name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" | ||||
| archives: | ||||
|   - | ||||
|     # ID of this archive. | ||||
|     # Defaults to `default`. | ||||
|     id: my-archive | ||||
|  | ||||
|   # Replacements for GOOS and GOARCH in the archive name. | ||||
|   # Keys should be valid GOOSs or GOARCHs. | ||||
|   # Values are the respective replacements. | ||||
|   # Default is empty. | ||||
|   replacements: | ||||
|     amd64: 64-bit | ||||
|     386: 32-bit | ||||
|     darwin: macOS | ||||
|     linux: Tux | ||||
|     # Builds reference which build instances should be archived in this archive. | ||||
|     builds: | ||||
|     - default | ||||
|  | ||||
|   # Set to true, if you want all files in the archive to be in a single directory. | ||||
|   # If set to true and you extract the archive 'goreleaser_Linux_arm64.tar.gz', | ||||
|   # you get a folder 'goreleaser_Linux_arm64'. | ||||
|   # If set to false, all files are extracted separately. | ||||
|   # You can also set it to a custom folder name (templating is supported). | ||||
|   # Default is false. | ||||
|   wrap_in_directory: true | ||||
|     # Archive name template. | ||||
|     # Defaults: | ||||
|     # - if format is `tar.gz`, `gz` or `zip`: | ||||
|     #   - `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` | ||||
|     # - if format is `binary`: | ||||
|     #   - `{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` | ||||
|     name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" | ||||
|  | ||||
|   # Archive format. Valid options are `tar.gz`, `gz`, `zip` and `binary`. | ||||
|   # If format is `binary`, no archives are created and the binaries are instead | ||||
|   # uploaded directly. | ||||
|   # Default is `tar.gz`. | ||||
|   format: zip | ||||
|     # Replacements for GOOS and GOARCH in the archive name. | ||||
|     # Keys should be valid GOOSs or GOARCHs. | ||||
|     # Values are the respective replacements. | ||||
|     # Default is empty. | ||||
|     replacements: | ||||
|       amd64: 64-bit | ||||
|       386: 32-bit | ||||
|       darwin: macOS | ||||
|       linux: Tux | ||||
|  | ||||
|   # Can be used to change the archive formats for specific GOOSs. | ||||
|   # Most common use case is to archive as zip on Windows. | ||||
|   # Default is empty. | ||||
|   format_overrides: | ||||
|     - goos: windows | ||||
|       format: zip | ||||
|     # Set to true, if you want all files in the archive to be in a single directory. | ||||
|     # If set to true and you extract the archive 'goreleaser_Linux_arm64.tar.gz', | ||||
|     # you get a folder 'goreleaser_Linux_arm64'. | ||||
|     # If set to false, all files are extracted separately. | ||||
|     # You can also set it to a custom folder name (templating is supported). | ||||
|     # Default is false. | ||||
|     wrap_in_directory: true | ||||
|  | ||||
|   # Additional files/globs you want to add to the archive. | ||||
|   # Defaults are any files matching `LICENCE*`, `LICENSE*`, | ||||
|   # `README*` and `CHANGELOG*` (case-insensitive). | ||||
|   files: | ||||
|     - LICENSE.txt | ||||
|     - README.md | ||||
|     - CHANGELOG.md | ||||
|     - docs/* | ||||
|     - design/*.png | ||||
|     - templates/**/* | ||||
|     # Archive format. Valid options are `tar.gz`, `gz`, `zip` and `binary`. | ||||
|     # If format is `binary`, no archives are created and the binaries are instead | ||||
|     # uploaded directly. | ||||
|     # Default is `tar.gz`. | ||||
|     format: zip | ||||
|  | ||||
|     # Can be used to change the archive formats for specific GOOSs. | ||||
|     # Most common use case is to archive as zip on Windows. | ||||
|     # Default is empty. | ||||
|     format_overrides: | ||||
|       - goos: windows | ||||
|         format: zip | ||||
|  | ||||
|     # Additional files/globs you want to add to the archive. | ||||
|     # Defaults are any files matching `LICENCE*`, `LICENSE*`, | ||||
|     # `README*` and `CHANGELOG*` (case-insensitive). | ||||
|     files: | ||||
|       - LICENSE.txt | ||||
|       - README.md | ||||
|       - CHANGELOG.md | ||||
|       - docs/* | ||||
|       - design/*.png | ||||
|       - templates/**/* | ||||
| ``` | ||||
|  | ||||
| > Learn more about the [name template engine](/templates). | ||||
| @@ -80,8 +89,8 @@ A working hack is to use something like this: | ||||
|  | ||||
| ```yaml | ||||
| # goreleaser.yml | ||||
| archive: | ||||
|   files: | ||||
| archives: | ||||
| - files: | ||||
|   - none* | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -33,6 +33,27 @@ to this: | ||||
|  | ||||
| --> | ||||
|  | ||||
| ### archive | ||||
|  | ||||
| > since 2019-04-16 | ||||
|  | ||||
| We now allow multiple archives, so the `archive` statement will be removed. | ||||
|  | ||||
| Change this: | ||||
|  | ||||
| ```yaml | ||||
| archive: | ||||
|   format: zip | ||||
| ``` | ||||
|  | ||||
| to this: | ||||
|  | ||||
| ```yaml | ||||
| archives: | ||||
|   - id: foo | ||||
|     format: zip | ||||
| ``` | ||||
|  | ||||
| ### docker.binary | ||||
|  | ||||
| > since 2018-10-01 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user