From b8f590126537beb8f269f424bb63f8326f469152 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 16 Apr 2019 10:19:15 -0300 Subject: [PATCH] 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 --- .goreleaser.yml | 23 ++- internal/artifact/artifact.go | 12 ++ internal/artifact/artifact_test.go | 37 ++++ internal/pipe/archive/archive.go | 133 +++++++----- internal/pipe/archive/archive_test.go | 260 +++++++++++++++--------- internal/pipe/build/build.go | 2 +- internal/pipe/build/build_test.go | 2 +- internal/pipe/defaults/defaults_test.go | 6 +- internal/static/config.go | 4 +- pkg/config/config.go | 18 +- pkg/defaults/defaults.go | 2 +- www/content/archive.md | 107 +++++----- www/content/deprecations.md | 21 ++ 13 files changed, 407 insertions(+), 220 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index b8323fbba..e5bb5e59e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -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 diff --git a/internal/artifact/artifact.go b/internal/artifact/artifact.go index 0ece17bb6..32906934d 100644 --- a/internal/artifact/artifact.go +++ b/internal/artifact/artifact.go @@ -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 { diff --git a/internal/artifact/artifact_test.go b/internal/artifact/artifact_test.go index 09af18852..ab9ce304f 100644 --- a/internal/artifact/artifact_test.go +++ b/internal/artifact/artifact_test.go @@ -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) +} diff --git a/internal/pipe/archive/archive.go b/internal/pipe/archive/archive.go index 2161f53bf..47a74e00e 100644 --- a/internal/pipe/archive/archive.go +++ b/internal/pipe/archive/archive.go @@ -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 diff --git a/internal/pipe/archive/archive_test.go b/internal/pipe/archive/archive_test.go index 71681780e..8639c4306 100644 --- a/internal/pipe/archive/archive_test.go +++ b/internal/pipe/archive/archive_test.go @@ -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") +} diff --git a/internal/pipe/build/build.go b/internal/pipe/build/build.go index b4f993dc3..50177952d 100644 --- a/internal/pipe/build/build.go +++ b/internal/pipe/build/build.go @@ -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 diff --git a/internal/pipe/build/build_test.go b/internal/pipe/build/build_test.go index bb55a11c1..d187dfdcd 100644 --- a/internal/pipe/build/build_test.go +++ b/internal/pipe/build/build_test.go @@ -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) { diff --git a/internal/pipe/defaults/defaults_test.go b/internal/pipe/defaults/defaults_test.go index 43728571f..4484cde11 100644 --- a/internal/pipe/defaults/defaults_test.go +++ b/internal/pipe/defaults/defaults_test.go @@ -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) } diff --git a/internal/static/config.go b/internal/static/config.go index d70e38728..66637d561 100644 --- a/internal/static/config.go +++ b/internal/static/config.go @@ -13,8 +13,8 @@ before: builds: - env: - CGO_ENABLED=0 -archive: - replacements: +archives: +- replacements: darwin: Darwin linux: Linux windows: Windows diff --git a/pkg/config/config.go b/pkg/config/config.go index f3510bc96..232d9f40a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -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"` diff --git a/pkg/defaults/defaults.go b/pkg/defaults/defaults.go index 8946675e0..6bb3e3ab2 100644 --- a/pkg/defaults/defaults.go +++ b/pkg/defaults/defaults.go @@ -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{}, diff --git a/www/content/archive.md b/www/content/archive.md index 72ff18e91..72c40c061 100644 --- a/www/content/archive.md +++ b/www/content/archive.md @@ -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* ``` diff --git a/www/content/deprecations.md b/www/content/deprecations.md index 9562e152c..a31fc6406 100644 --- a/www/content/deprecations.md +++ b/www/content/deprecations.md @@ -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