From fc4d9363bc1d349367c8a7f644facc78f9d393a6 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 21:10:37 -0200 Subject: [PATCH 1/8] refactor: name templates --- internal/nametemplate/name.go | 49 ------------------ internal/nametemplate/name_test.go | 83 ------------------------------ internal/template/template.go | 51 ++++++++++++++++++ internal/template/template_test.go | 56 ++++++++++++++++++++ 4 files changed, 107 insertions(+), 132 deletions(-) delete mode 100644 internal/nametemplate/name.go delete mode 100644 internal/nametemplate/name_test.go create mode 100644 internal/template/template.go create mode 100644 internal/template/template_test.go diff --git a/internal/nametemplate/name.go b/internal/nametemplate/name.go deleted file mode 100644 index 8028862e3..000000000 --- a/internal/nametemplate/name.go +++ /dev/null @@ -1,49 +0,0 @@ -package nametemplate - -import ( - "bytes" - "regexp" - "text/template" - - "github.com/apex/log" - "github.com/goreleaser/goreleaser/context" - "github.com/goreleaser/goreleaser/internal/artifact" -) - -var deprecatedBinary = regexp.MustCompile(`\{\{ ?\.Binary ?\}\}`) - -// Apply applies the name template to the given artifact and name -// TODO: this should be refactored alongside with other name template related todos -func Apply(ctx *context.Context, a artifact.Artifact, name string) (string, error) { - if deprecatedBinary.MatchString(ctx.Config.Archive.NameTemplate) { - log.WithField("field", "{{.Binary}}").Warn("you are using a deprecated field on your template, please check the documentation") - } - var out bytes.Buffer - t, err := template.New("archive_name").Parse(ctx.Config.Archive.NameTemplate) - if err != nil { - return "", err - } - data := struct { - Os, Arch, Arm, Version, Tag, Binary, ProjectName string - Env map[string]string - }{ - Os: replace(ctx.Config.Archive.Replacements, a.Goos), - Arch: replace(ctx.Config.Archive.Replacements, a.Goarch), - Arm: replace(ctx.Config.Archive.Replacements, a.Goarm), - Version: ctx.Version, - Tag: ctx.Git.CurrentTag, - ProjectName: name, - Binary: name, // TODO: deprecated, remove soon - Env: ctx.Env, - } - err = t.Execute(&out, data) - return out.String(), err -} - -func replace(replacements map[string]string, original string) string { - result := replacements[original] - if result == "" { - return original - } - return result -} diff --git a/internal/nametemplate/name_test.go b/internal/nametemplate/name_test.go deleted file mode 100644 index e166164c2..000000000 --- a/internal/nametemplate/name_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package nametemplate - -import ( - "bytes" - "testing" - - "github.com/apex/log" - "github.com/apex/log/handlers/cli" - "github.com/goreleaser/goreleaser/config" - "github.com/goreleaser/goreleaser/context" - "github.com/goreleaser/goreleaser/internal/artifact" - "github.com/stretchr/testify/assert" -) - -func TestNameTemplate(t *testing.T) { - var ctx = context.New(config.Project{ - ProjectName: "proj", - Archive: config.Archive{ - NameTemplate: "{{.Binary}}_{{.ProjectName}}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", - Replacements: map[string]string{ - "windows": "windao", - }, - }, - }) - s, err := Apply(ctx, artifact.Artifact{ - Goos: "windows", - Goarch: "amd64", - Name: "winbin", - }, "bin") - assert.NoError(t, err) - assert.Equal(t, "bin_bin_windao_amd64", s) - s, err = Apply(ctx, artifact.Artifact{ - Goos: "darwin", - Goarch: "amd64", - Name: "winbin", - }, "bin") - assert.NoError(t, err) - assert.Equal(t, "bin_bin_darwin_amd64", s) -} - -func TestInvalidNameTemplate(t *testing.T) { - var ctx = context.New(config.Project{ - ProjectName: "proj", - Archive: config.Archive{ - NameTemplate: "{{.Binary}", - }, - }) - s, err := Apply(ctx, artifact.Artifact{ - Goos: "windows", - Goarch: "amd64", - Name: "winbin", - }, "bin") - assert.EqualError(t, err, `template: archive_name:1: unexpected "}" in operand`) - assert.Empty(t, s) -} - -func TestDeprecatedFieldOnNameTemplate(t *testing.T) { - for _, temp := range []string{ - "{{.Binary}}", - "{{ .Binary}}", - "{{.Binary }}", - "{{ .Binary }}", - } { - t.Run(temp, func(tt *testing.T) { - var out bytes.Buffer - log.SetHandler(cli.New(&out)) - var ctx = context.New(config.Project{ - ProjectName: "proj", - Archive: config.Archive{ - NameTemplate: temp, - }, - }) - s, err := Apply(ctx, artifact.Artifact{ - Goos: "windows", - Goarch: "amd64", - Name: "winbin", - }, "bin") - assert.NoError(tt, err) - assert.Equal(tt, "bin", s) - assert.Contains(tt, out.String(), "you are using a deprecated field on your template") - }) - } -} diff --git a/internal/template/template.go b/internal/template/template.go new file mode 100644 index 000000000..bf6304b5b --- /dev/null +++ b/internal/template/template.go @@ -0,0 +1,51 @@ +package template + +import ( + "bytes" + gotemplate "text/template" + + "github.com/goreleaser/goreleaser/context" + "github.com/goreleaser/goreleaser/internal/artifact" +) + +type Fields struct { + Version string + Tag string + ProjectName string + Env map[string]string + Os string + Arch string + Arm string + Binary string +} + +func NewFields(ctx *context.Context, a artifact.Artifact, replacements map[string]string) Fields { + return Fields{ + Env: ctx.Env, + Version: ctx.Version, + Tag: ctx.Git.CurrentTag, + ProjectName: ctx.Config.ProjectName, + Binary: a.Name, + Os: replace(replacements, a.Goos), + Arch: replace(replacements, a.Goarch), + Arm: replace(replacements, a.Goarm), + } +} + +func Apply(tmpl string, fields Fields) (string, error) { + t, err := gotemplate.New(tmpl).Parse(tmpl) + if err != nil { + return "", err + } + var out bytes.Buffer + err = t.Execute(&out, fields) + return out.String(), err +} + +func replace(replacements map[string]string, original string) string { + result := replacements[original] + if result == "" { + return original + } + return result +} diff --git a/internal/template/template_test.go b/internal/template/template_test.go new file mode 100644 index 000000000..c046dfff2 --- /dev/null +++ b/internal/template/template_test.go @@ -0,0 +1,56 @@ +package template + +import ( + "testing" + + "github.com/goreleaser/goreleaser/config" + "github.com/goreleaser/goreleaser/context" + "github.com/goreleaser/goreleaser/internal/artifact" + "github.com/stretchr/testify/assert" +) + +func TestTemplate(t *testing.T) { + var ctx = context.New(config.Project{ + ProjectName: "proj", + }) + ctx.Env = map[string]string{ + "FOO": "bar", + } + ctx.Version = "1.0.0" + ctx.Git.CurrentTag = "v1.0.0" + var fields = NewFields(ctx, artifact.Artifact{ + Name: "binary", + Goarch: "amd64", + Goos: "linux", + Goarm: "6", + }, map[string]string{ + "linux": "Linux", + }) + for expect, tmpl := range map[string]string{ + "bar": "{{.Env.FOO}}", + "Linux": "{{.Os}}", + "amd64": "{{.Arch}}", + "6": "{{.Arm}}", + "1.0.0": "{{.Version}}", + "v1.0.0": "{{.Tag}}", + "binary": "{{.Binary}}", + "proj": "{{.ProjectName}}", + } { + tmpl := tmpl + expect := expect + t.Run(expect, func(tt *testing.T) { + tt.Parallel() + result, err := Apply(tmpl, fields) + assert.NoError(tt, err) + assert.Equal(tt, expect, result) + }) + } +} + +func TestInvalidTemplate(t *testing.T) { + var ctx = context.New(config.Project{}) + var fields = NewFields(ctx, artifact.Artifact{}, map[string]string{}) + result, err := Apply("{{.Foo}", fields) + assert.Empty(t, result) + assert.EqualError(t, err, `template: {{.Foo}:1: unexpected "}" in operand`) +} From 4ce13bc7c3a62422f25e21313ecc358f1a73f2a9 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 21:19:58 -0200 Subject: [PATCH 2/8] refactor: name templates for archive pipe --- docs/060-archive.md | 27 +++++++------ internal/template/template.go | 2 +- pipeline/archive/archive.go | 66 +++++++++++++++++++------------- pipeline/archive/archive_test.go | 17 ++++++-- 4 files changed, 70 insertions(+), 42 deletions(-) diff --git a/docs/060-archive.md b/docs/060-archive.md index 8f9d314be..e5d7cfb53 100644 --- a/docs/060-archive.md +++ b/docs/060-archive.md @@ -15,15 +15,30 @@ archive: # This is parsed with the Go template engine and the following variables # are available: # - ProjectName + # - Binary (Name of the binary if the packaging format is binary) # - Tag # - Version (Git tag without `v` prefix) # - Os # - Arch # - Arm (ARM version) # - Env (environment variables) - # Default is `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}`. + # Defaults: + # - if format is `tar.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 }}" + # 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 + # 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'. @@ -44,16 +59,6 @@ archive: - goos: windows 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 - # Additional files/globs you want to add to the archive. # Defaults are any files matching `LICENCE*`, `LICENSE*`, # `README*` and `CHANGELOG*` (case-insensitive). diff --git a/internal/template/template.go b/internal/template/template.go index bf6304b5b..5f98363ff 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -25,7 +25,7 @@ func NewFields(ctx *context.Context, a artifact.Artifact, replacements map[strin Version: ctx.Version, Tag: ctx.Git.CurrentTag, ProjectName: ctx.Config.ProjectName, - Binary: a.Name, + Binary: a.Extra["Binary"], Os: replace(replacements, a.Goos), Arch: replace(replacements, a.Goarch), Arm: replace(replacements, a.Goarm), diff --git a/pipeline/archive/archive.go b/pipeline/archive/archive.go index 0b8c0f57f..edb069292 100644 --- a/pipeline/archive/archive.go +++ b/pipeline/archive/archive.go @@ -16,10 +16,13 @@ import ( "github.com/goreleaser/archive" "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" - "github.com/goreleaser/goreleaser/internal/nametemplate" + "github.com/goreleaser/goreleaser/internal/template" ) -const defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" +const ( + defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + defaultBinaryNameTemplate = "{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" +) // Pipe for archive type Pipe struct{} @@ -28,6 +31,34 @@ func (Pipe) String() string { return "creating archives" } +// 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*", + } + } + if archive.NameTemplate == "" { + if archive.Format == "binary" { + archive.NameTemplate = defaultBinaryNameTemplate + } else { + archive.NameTemplate = defaultNameTemplate + } + } + return nil +} + // Run the pipe func (Pipe) Run(ctx *context.Context) error { var g errgroup.Group @@ -44,32 +75,12 @@ func (Pipe) Run(ctx *context.Context) error { return g.Wait() } -// Default sets the pipe defaults -func (Pipe) Default(ctx *context.Context) error { - if ctx.Config.Archive.NameTemplate == "" { - ctx.Config.Archive.NameTemplate = defaultNameTemplate - } - if ctx.Config.Archive.Format == "" { - ctx.Config.Archive.Format = "tar.gz" - } - if len(ctx.Config.Archive.Files) == 0 { - ctx.Config.Archive.Files = []string{ - "licence*", - "LICENCE*", - "license*", - "LICENSE*", - "readme*", - "README*", - "changelog*", - "CHANGELOG*", - } - } - return nil -} - func create(ctx *context.Context, artifacts []artifact.Artifact) error { var format = packageFormat(ctx, artifacts[0].Goos) - folder, err := nametemplate.Apply(ctx, artifacts[0], ctx.Config.ProjectName) + folder, err := template.Apply( + ctx.Config.Archive.NameTemplate, + template.NewFields(ctx, artifacts[0], ctx.Config.Archive.Replacements), + ) if err != nil { return err } @@ -111,7 +122,8 @@ func create(ctx *context.Context, artifacts []artifact.Artifact) error { func skip(ctx *context.Context, artifacts []artifact.Artifact) error { for _, a := range artifacts { log.WithField("binary", a.Name).Info("skip archiving") - name, err := nametemplate.Apply(ctx, a, a.Extra["Binary"]) + var fields = template.NewFields(ctx, a, ctx.Config.Archive.Replacements) + name, err := template.Apply(ctx.Config.Archive.NameTemplate, fields) if err != nil { return err } diff --git a/pipeline/archive/archive_test.go b/pipeline/archive/archive_test.go index 52ef857ff..35ddeea23 100644 --- a/pipeline/archive/archive_test.go +++ b/pipeline/archive/archive_test.go @@ -8,12 +8,11 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" - "github.com/goreleaser/goreleaser/config" "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/testlib" + "github.com/stretchr/testify/assert" ) func TestDescription(t *testing.T) { @@ -122,7 +121,7 @@ func TestRunPipeBinary(t *testing.T) { Dist: dist, Archive: config.Archive{ Format: "binary", - NameTemplate: defaultNameTemplate, + NameTemplate: defaultBinaryNameTemplate, }, }, ) @@ -297,6 +296,18 @@ func TestDefaultSet(t *testing.T) { assert.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", + }, + }, + } + assert.NoError(t, Pipe{}.Default(ctx)) + assert.Equal(t, defaultBinaryNameTemplate, ctx.Config.Archive.NameTemplate) +} + func TestFormatFor(t *testing.T) { var ctx = &context.Context{ Config: config.Project{ From 5dba7fbfdf5bbc8d780620ab11858d2ffd220382 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 21:36:17 -0200 Subject: [PATCH 3/8] feat: name_template support for fpm packages closes #409 --- config/config.go | 2 ++ docs/100-fpm.md | 23 +++++++++++++++++++++++ pipeline/fpm/fpm.go | 22 +++++++++++++++------- pipeline/fpm/fpm_test.go | 31 ++++++++++++++++++++++++++----- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/config/config.go b/config/config.go index 11348abd1..cc6cf36ab 100644 --- a/config/config.go +++ b/config/config.go @@ -129,6 +129,8 @@ type Release struct { // FPM config type FPM struct { + NameTemplate string `yaml:"name_template,omitempty"` + Replacements map[string]string `yaml:",omitempty"` Formats []string `yaml:",omitempty"` Dependencies []string `yaml:",omitempty"` Conflicts []string `yaml:",omitempty"` diff --git a/docs/100-fpm.md b/docs/100-fpm.md index cbb09f060..1df336d13 100644 --- a/docs/100-fpm.md +++ b/docs/100-fpm.md @@ -9,6 +9,29 @@ generate `.deb`, `.rpm` and other archives. Check its ```yml # .goreleaser.yml fpm: + # You can change the name of the package. + # This is parsed with the Go template engine and the following variables + # are available: + # - ProjectName + # - Tag + # - Version (Git tag without `v` prefix) + # - Os + # - Arch + # - Arm (ARM version) + # - Env (environment variables) + # Default: `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + + # Replacements for GOOS and GOARCH in the package 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 + # Your app's vendor. # Default is empty. vendor: Drum Roll Inc. diff --git a/pipeline/fpm/fpm.go b/pipeline/fpm/fpm.go index 2e7618442..db831c852 100644 --- a/pipeline/fpm/fpm.go +++ b/pipeline/fpm/fpm.go @@ -14,13 +14,15 @@ import ( "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/linux" - "github.com/goreleaser/goreleaser/internal/nametemplate" + "github.com/goreleaser/goreleaser/internal/template" "github.com/goreleaser/goreleaser/pipeline" ) // ErrNoFPM is shown when fpm cannot be found in $PATH var ErrNoFPM = errors.New("fpm not present in $PATH") +const defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + // Pipe for fpm packaging type Pipe struct{} @@ -30,8 +32,12 @@ func (Pipe) String() string { // Default sets the pipe defaults func (Pipe) Default(ctx *context.Context) error { - if ctx.Config.FPM.Bindir == "" { - ctx.Config.FPM.Bindir = "/usr/local/bin" + var fpm = &ctx.Config.FPM + if fpm.Bindir == "" { + fpm.Bindir = "/usr/local/bin" + } + if fpm.NameTemplate == "" { + fpm.NameTemplate = defaultNameTemplate } return nil } @@ -74,12 +80,14 @@ func doRun(ctx *context.Context) error { } func create(ctx *context.Context, format, arch string, binaries []artifact.Artifact) error { - // TODO: should add template support here probably... for now, let's use archive's template - folder, err := nametemplate.Apply(ctx, binaries[0], ctx.Config.ProjectName) + name, err := template.Apply( + ctx.Config.FPM.NameTemplate, + template.NewFields(ctx, binaries[0], ctx.Config.FPM.Replacements), + ) if err != nil { return err } - var path = filepath.Join(ctx.Config.Dist, folder) + var path = filepath.Join(ctx.Config.Dist, name) var file = path + "." + format var log = log.WithField("format", format).WithField("arch", arch) dir, err := ioutil.TempDir("", "fpm") @@ -120,7 +128,7 @@ func create(ctx *context.Context, format, arch string, binaries []artifact.Artif } ctx.Artifacts.Add(artifact.Artifact{ Type: artifact.LinuxPackage, - Name: folder + "." + format, + Name: name + "." + format, Path: file, Goos: binaries[0].Goos, Goarch: binaries[0].Goarch, diff --git a/pipeline/fpm/fpm_test.go b/pipeline/fpm/fpm_test.go index 8d1e35654..b7c77f5b2 100644 --- a/pipeline/fpm/fpm_test.go +++ b/pipeline/fpm/fpm_test.go @@ -44,11 +44,8 @@ func TestRunPipe(t *testing.T) { Config: config.Project{ ProjectName: "mybin", Dist: dist, - // TODO: remove this when fpm have its own name template - Archive: config.Archive{ - NameTemplate: "foo", - }, FPM: config.FPM{ + NameTemplate: defaultNameTemplate, Formats: []string{"deb", "rpm"}, Dependencies: []string{"make"}, Conflicts: []string{"git"}, @@ -92,6 +89,27 @@ func TestNoFPMInPath(t *testing.T) { assert.EqualError(t, Pipe{}.Run(ctx), ErrNoFPM.Error()) } +func TestInvalidNameTemplate(t *testing.T) { + var ctx = &context.Context{ + Parallelism: runtime.NumCPU(), + Artifacts: artifact.New(), + Config: config.Project{ + FPM: config.FPM{ + NameTemplate: "{{.Foo}", + Formats: []string{"deb"}, + }, + }, + } + ctx.Artifacts.Add(artifact.Artifact{ + Name: "mybin", + Goos: "linux", + Goarch: "amd64", + Type: artifact.Binary, + }) + assert.Contains(t, Pipe{}.Run(ctx).Error(), `template: {{.Foo}:1: unexpected "}" in operand`) +} + + func TestCreateFileDoesntExist(t *testing.T) { folder, err := ioutil.TempDir("", "archivetest") assert.NoError(t, err) @@ -119,7 +137,7 @@ func TestCreateFileDoesntExist(t *testing.T) { Goarch: "amd64", Type: artifact.Binary, }) - assert.Error(t, Pipe{}.Run(ctx)) + assert.Contains(t, Pipe{}.Run(ctx).Error(), `dist/mybin/mybin', does it exist?`) } func TestDefault(t *testing.T) { @@ -130,6 +148,7 @@ func TestDefault(t *testing.T) { } assert.NoError(t, Pipe{}.Default(ctx)) assert.Equal(t, "/usr/local/bin", ctx.Config.FPM.Bindir) + assert.Equal(t, defaultNameTemplate, ctx.Config.FPM.NameTemplate) } func TestDefaultSet(t *testing.T) { @@ -137,9 +156,11 @@ func TestDefaultSet(t *testing.T) { Config: config.Project{ FPM: config.FPM{ Bindir: "/bin", + NameTemplate: "foo", }, }, } assert.NoError(t, Pipe{}.Default(ctx)) assert.Equal(t, "/bin", ctx.Config.FPM.Bindir) + assert.Equal(t, "foo", ctx.Config.FPM.NameTemplate) } From 6270aa9cb27317a8af6d5333f7cf178cfa893d45 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 21:44:11 -0200 Subject: [PATCH 4/8] feat: name template on snapcraft packages closes #470 --- config/config.go | 14 ++++---- docs/110-snapcraft.md | 22 ++++++++++++ pipeline/snapcraft/snapcraft.go | 19 ++++++++-- pipeline/snapcraft/snapcraft_test.go | 54 +++++++++++++++++++++------- pipeline/snapshot/snapshot.go | 2 +- 5 files changed, 89 insertions(+), 22 deletions(-) diff --git a/config/config.go b/config/config.go index cc6cf36ab..2cc559f3d 100644 --- a/config/config.go +++ b/config/config.go @@ -162,12 +162,14 @@ type SnapcraftAppMetadata struct { // Snapcraft config type Snapcraft struct { - Name string `yaml:",omitempty"` - Summary string `yaml:",omitempty"` - Description string `yaml:",omitempty"` - Grade string `yaml:",omitempty"` - Confinement string `yaml:",omitempty"` - Apps map[string]SnapcraftAppMetadata `yaml:",omitempty"` + NameTemplate string `yaml:"name_template,omitempty"` + Replacements map[string]string `yaml:",omitempty"` + Name string `yaml:",omitempty"` + Summary string `yaml:",omitempty"` + Description string `yaml:",omitempty"` + Grade string `yaml:",omitempty"` + Confinement string `yaml:",omitempty"` + Apps map[string]SnapcraftAppMetadata `yaml:",omitempty"` // Capture all undefined fields and should be empty after loading XXX map[string]interface{} `yaml:",inline"` diff --git a/docs/110-snapcraft.md b/docs/110-snapcraft.md index d7f323c61..1a175ea3b 100644 --- a/docs/110-snapcraft.md +++ b/docs/110-snapcraft.md @@ -13,6 +13,28 @@ You can read more about it in the [snapcraft docs](https://snapcraft.io/docs/). ```yml # .goreleaser.yml snapcraft: + # You can change the name of the package. + # This is parsed with the Go template engine and the following variables + # are available: + # - ProjectName + # - Tag + # - Version (Git tag without `v` prefix) + # - Os + # - Arch + # - Arm (ARM version) + # - Env (environment variables) + # Default: `{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}` + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + + # Replacements for GOOS and GOARCH in the package 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 # The name of the snap. This is optional. # Default is project name. diff --git a/pipeline/snapcraft/snapcraft.go b/pipeline/snapcraft/snapcraft.go index 6bb29c239..a5561a301 100644 --- a/pipeline/snapcraft/snapcraft.go +++ b/pipeline/snapcraft/snapcraft.go @@ -16,7 +16,7 @@ import ( "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/linux" - "github.com/goreleaser/goreleaser/internal/nametemplate" + "github.com/goreleaser/goreleaser/internal/template" "github.com/goreleaser/goreleaser/pipeline" ) @@ -48,6 +48,8 @@ type AppMetadata struct { Daemon string `yaml:",omitempty"` } +const defaultNameTemplate = "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + // Pipe for snapcraft packaging type Pipe struct{} @@ -55,6 +57,15 @@ func (Pipe) String() string { return "creating Linux packages with snapcraft" } +// Default sets the pipe defaults +func (Pipe) Default(ctx *context.Context) error { + var snap = &ctx.Config.Snapcraft + if snap.NameTemplate == "" { + snap.NameTemplate = defaultNameTemplate + } + return nil +} + // Run the pipe func (Pipe) Run(ctx *context.Context) error { if ctx.Config.Snapcraft.Summary == "" && ctx.Config.Snapcraft.Description == "" { @@ -89,8 +100,10 @@ func (Pipe) Run(ctx *context.Context) error { func create(ctx *context.Context, arch string, binaries []artifact.Artifact) error { var log = log.WithField("arch", arch) - // TODO: should add template support here probably... for now, let's use archive's template - folder, err := nametemplate.Apply(ctx, binaries[0], ctx.Config.ProjectName) + folder, err := template.Apply( + ctx.Config.Snapcraft.NameTemplate, + template.NewFields(ctx, binaries[0], ctx.Config.Snapcraft.Replacements), + ) if err != nil { return err } diff --git a/pipeline/snapcraft/snapcraft_test.go b/pipeline/snapcraft/snapcraft_test.go index ff596d03f..6c56f46ca 100644 --- a/pipeline/snapcraft/snapcraft_test.go +++ b/pipeline/snapcraft/snapcraft_test.go @@ -52,11 +52,8 @@ func TestRunPipe(t *testing.T) { Config: config.Project{ ProjectName: "mybin", Dist: dist, - // TODO: remove this when we start using our own name template - Archive: config.Archive{ - NameTemplate: "foo_{{.Arch}}", - }, Snapcraft: config.Snapcraft{ + NameTemplate: "foo_{{.Arch}}", Summary: "test summary", Description: "test description", }, @@ -66,6 +63,29 @@ func TestRunPipe(t *testing.T) { assert.NoError(t, Pipe{}.Run(ctx)) } +func TestRunPipeInvalidNameTemplate(t *testing.T) { + folder, err := ioutil.TempDir("", "archivetest") + assert.NoError(t, err) + var dist = filepath.Join(folder, "dist") + assert.NoError(t, os.Mkdir(dist, 0755)) + assert.NoError(t, err) + var ctx = &context.Context{ + Version: "testversion", + Artifacts: artifact.New(), + Config: config.Project{ + ProjectName: "mybin", + Dist: dist, + Snapcraft: config.Snapcraft{ + NameTemplate: "foo_{{.Arch}", + Summary: "test summary", + Description: "test description", + }, + }, + } + addBinaries(t, ctx, "mybin", dist) + assert.EqualError(t, Pipe{}.Run(ctx), `template: foo_{{.Arch}:1: unexpected "}" in operand`) +} + func TestRunPipeWithName(t *testing.T) { folder, err := ioutil.TempDir("", "archivetest") assert.NoError(t, err) @@ -78,11 +98,8 @@ func TestRunPipeWithName(t *testing.T) { Config: config.Project{ ProjectName: "testprojectname", Dist: dist, - // TODO: remove this when we start using our own name template - Archive: config.Archive{ - NameTemplate: "foo_{{.Arch}}", - }, Snapcraft: config.Snapcraft{ + NameTemplate: "foo_{{.Arch}}", Name: "testsnapname", Summary: "test summary", Description: "test description", @@ -111,11 +128,8 @@ func TestRunPipeWithPlugsAndDaemon(t *testing.T) { Config: config.Project{ ProjectName: "mybin", Dist: dist, - // TODO: remove this when we start using our own name template - Archive: config.Archive{ - NameTemplate: "foo_{{.Arch}}", - }, Snapcraft: config.Snapcraft{ + NameTemplate: "foo_{{.Arch}}", Summary: "test summary", Description: "test description", Apps: map[string]config.SnapcraftAppMetadata{ @@ -155,6 +169,22 @@ func TestNoSnapcraftInPath(t *testing.T) { assert.EqualError(t, Pipe{}.Run(ctx), ErrNoSnapcraft.Error()) } +func TestDefault(t *testing.T) { + var ctx = context.New(config.Project{}) + assert.NoError(t,Pipe{}.Default(ctx)) + assert.Equal(t, defaultNameTemplate, ctx.Config.Snapcraft.NameTemplate) +} + +func TestDefaultSet(t *testing.T) { + var ctx = context.New(config.Project{ + Snapcraft: config.Snapcraft{ + NameTemplate: "foo", + }, + }) + assert.NoError(t,Pipe{}.Default(ctx)) + assert.Equal(t, "foo", ctx.Config.Snapcraft.NameTemplate) +} + func addBinaries(t *testing.T, ctx *context.Context, name, dist string) { for _, goos := range []string{"linux", "darwin"} { for _, goarch := range []string{"amd64", "386"} { diff --git a/pipeline/snapshot/snapshot.go b/pipeline/snapshot/snapshot.go index c3fc1d6af..6e77a7167 100644 --- a/pipeline/snapshot/snapshot.go +++ b/pipeline/snapshot/snapshot.go @@ -7,7 +7,7 @@ import "github.com/goreleaser/goreleaser/context" type Pipe struct{} func (Pipe) String() string { - return "generating changelog" + return "snapshoting" } // Default sets the pipe defaults From 2af71694845fa0aaf032c3f051e5c85363c03d05 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 21:45:53 -0200 Subject: [PATCH 5/8] feat: defaulter on snap pipe --- pipeline/defaults/defaults.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pipeline/defaults/defaults.go b/pipeline/defaults/defaults.go index 51968d29e..6e50d4ac9 100644 --- a/pipeline/defaults/defaults.go +++ b/pipeline/defaults/defaults.go @@ -15,6 +15,7 @@ import ( "github.com/goreleaser/goreleaser/pipeline/fpm" "github.com/goreleaser/goreleaser/pipeline/release" "github.com/goreleaser/goreleaser/pipeline/sign" + "github.com/goreleaser/goreleaser/pipeline/snapcraft" "github.com/goreleaser/goreleaser/pipeline/snapshot" ) @@ -31,6 +32,7 @@ var defaulters = []pipeline.Defaulter{ archive.Pipe{}, build.Pipe{}, fpm.Pipe{}, + snapcraft.Pipe{}, checksums.Pipe{}, sign.Pipe{}, docker.Pipe{}, From 915e40462982079d30226f17f5806395fe7f0ce2 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 22:20:48 -0200 Subject: [PATCH 6/8] test: fixed broken template test --- internal/template/template_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/template/template_test.go b/internal/template/template_test.go index c046dfff2..161ddb8f5 100644 --- a/internal/template/template_test.go +++ b/internal/template/template_test.go @@ -19,10 +19,13 @@ func TestTemplate(t *testing.T) { ctx.Version = "1.0.0" ctx.Git.CurrentTag = "v1.0.0" var fields = NewFields(ctx, artifact.Artifact{ - Name: "binary", + Name: "not-this-binary", Goarch: "amd64", Goos: "linux", Goarm: "6", + Extra: map[string]string{ + "Binary": "binary", + }, }, map[string]string{ "linux": "Linux", }) From 9b0441cbe481eb80bacd76e391d63d331c4fff6c Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 26 Dec 2017 22:51:28 -0200 Subject: [PATCH 7/8] docs: godoc of template pkg --- internal/template/template.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/template/template.go b/internal/template/template.go index 5f98363ff..43c4941c6 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -1,3 +1,5 @@ +// Package template contains the code used to template names of goreleaser's +// packages and archives. package template import ( @@ -8,6 +10,7 @@ import ( "github.com/goreleaser/goreleaser/internal/artifact" ) +// Fields contains all accepted fields in the template string type Fields struct { Version string Tag string @@ -19,6 +22,7 @@ type Fields struct { Binary string } +// NewFields returns a Fields instances filled with the data provided func NewFields(ctx *context.Context, a artifact.Artifact, replacements map[string]string) Fields { return Fields{ Env: ctx.Env, @@ -32,6 +36,8 @@ func NewFields(ctx *context.Context, a artifact.Artifact, replacements map[strin } } +// Apply applies the given fields to the given template and returns the +// evaluation and any error that might occur. func Apply(tmpl string, fields Fields) (string, error) { t, err := gotemplate.New(tmpl).Parse(tmpl) if err != nil { From 7d22ffd969b523162d99a5c7da914aae53595ee3 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Wed, 27 Dec 2017 09:16:00 -0200 Subject: [PATCH 8/8] style: better struct format --- config/config.go | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/config/config.go b/config/config.go index 2cc559f3d..1ba942284 100644 --- a/config/config.go +++ b/config/config.go @@ -106,12 +106,13 @@ type FormatOverride struct { // Archive config used for the archive type Archive struct { - Format string `yaml:",omitempty"` - FormatOverrides []FormatOverride `yaml:"format_overrides,omitempty"` - NameTemplate string `yaml:"name_template,omitempty"` - WrapInDirectory bool `yaml:"wrap_in_directory,omitempty"` - Replacements map[string]string `yaml:",omitempty"` - Files []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 bool `yaml:"wrap_in_directory,omitempty"` + Files []string `yaml:",omitempty"` // Capture all undefined fields and should be empty after loading XXX map[string]interface{} `yaml:",inline"` @@ -131,6 +132,7 @@ type Release struct { type FPM struct { NameTemplate string `yaml:"name_template,omitempty"` Replacements map[string]string `yaml:",omitempty"` + Formats []string `yaml:",omitempty"` Dependencies []string `yaml:",omitempty"` Conflicts []string `yaml:",omitempty"` @@ -162,14 +164,15 @@ type SnapcraftAppMetadata struct { // Snapcraft config type Snapcraft struct { - NameTemplate string `yaml:"name_template,omitempty"` - Replacements map[string]string `yaml:",omitempty"` - Name string `yaml:",omitempty"` - Summary string `yaml:",omitempty"` - Description string `yaml:",omitempty"` - Grade string `yaml:",omitempty"` - Confinement string `yaml:",omitempty"` - Apps map[string]SnapcraftAppMetadata `yaml:",omitempty"` + NameTemplate string `yaml:"name_template,omitempty"` + Replacements map[string]string `yaml:",omitempty"` + + Name string `yaml:",omitempty"` + Summary string `yaml:",omitempty"` + Description string `yaml:",omitempty"` + Grade string `yaml:",omitempty"` + Confinement string `yaml:",omitempty"` + Apps map[string]SnapcraftAppMetadata `yaml:",omitempty"` // Capture all undefined fields and should be empty after loading XXX map[string]interface{} `yaml:",inline"`