diff --git a/internal/builders/golang/build.go b/internal/builders/golang/build.go index 2237fadacfc..bfa1d62a853 100644 --- a/internal/builders/golang/build.go +++ b/internal/builders/golang/build.go @@ -1,7 +1,6 @@ package golang import ( - "bytes" "fmt" "go/ast" "go/parser" @@ -9,14 +8,13 @@ import ( "os" "os/exec" "strings" - "text/template" - "time" "github.com/apex/log" api "github.com/goreleaser/goreleaser/build" "github.com/goreleaser/goreleaser/config" "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" + "github.com/goreleaser/goreleaser/internal/tmpl" "github.com/pkg/errors" ) @@ -108,7 +106,7 @@ func (*Builder) Build(ctx *context.Context, build config.Build, options api.Opti func processFlags(ctx *context.Context, flags []string, flagName string, flagPrefix string) ([]string, error) { processed := make([]string, 0, len(flags)) for _, rawFlag := range flags { - flag, err := processField(ctx, rawFlag, flagName) + flag, err := tmpl.New(ctx).Apply(rawFlag) if err != nil { return nil, err } @@ -117,36 +115,6 @@ func processFlags(ctx *context.Context, flags []string, flagName string, flagPre return processed, nil } -func processField(ctx *context.Context, field string, fieldName string) (string, error) { - var data = struct { - Commit string - Tag string - Version string - Date string - Env map[string]string - }{ - Commit: ctx.Git.Commit, - Tag: ctx.Git.CurrentTag, - Version: ctx.Version, - Date: time.Now().UTC().Format(time.RFC3339), - Env: ctx.Env, - } - var out bytes.Buffer - t, err := template.New(fieldName). - Funcs(template.FuncMap{ - "time": func(s string) string { - return time.Now().UTC().Format(s) - }, - }). - Option("missingkey=error"). - Parse(field) - if err != nil { - return "", err - } - err = t.Execute(&out, data) - return out.String(), err -} - func run(ctx *context.Context, command, env []string) error { /* #nosec */ var cmd = exec.CommandContext(ctx, command[0], command[1:]...) diff --git a/internal/builders/golang/build_test.go b/internal/builders/golang/build_test.go index dd963aa74b3..527a7aafe85 100644 --- a/internal/builders/golang/build_test.go +++ b/internal/builders/golang/build_test.go @@ -12,6 +12,7 @@ import ( "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/testlib" + "github.com/goreleaser/goreleaser/internal/tmpl" "github.com/stretchr/testify/assert" ) @@ -64,6 +65,7 @@ func TestWithDefaults(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var build = Default.WithDefaults(ctx.Config.Builds[0]) assert.ElementsMatch(t, build.Targets, testcase.targets) }) @@ -90,6 +92,7 @@ func TestBuild(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var build = ctx.Config.Builds[0] for _, target := range build.Targets { var ext string @@ -168,6 +171,7 @@ func TestBuildFailed(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ Target: "darwin_amd64", }) @@ -189,6 +193,7 @@ func TestBuildInvalidTarget(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var build = ctx.Config.Builds[0] var err = Default.Build(ctx, build, api.Options{ Target: target, @@ -215,10 +220,11 @@ func TestRunInvalidAsmflags(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ Target: runtimeTarget, }) - assert.EqualError(t, err, `template: asmflags:1: unexpected "}" in operand`) + assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`) } func TestRunInvalidGcflags(t *testing.T) { @@ -237,10 +243,11 @@ func TestRunInvalidGcflags(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ Target: runtimeTarget, }) - assert.EqualError(t, err, `template: gcflags:1: unexpected "}" in operand`) + assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`) } func TestRunInvalidLdflags(t *testing.T) { @@ -260,10 +267,11 @@ func TestRunInvalidLdflags(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" var err = Default.Build(ctx, ctx.Config.Builds[0], api.Options{ Target: runtimeTarget, }) - assert.EqualError(t, err, `template: ldflags:1: unexpected "}" in operand`) + assert.EqualError(t, err, `template: tmpl:1: unexpected "}" in operand`) } func TestRunPipeWithoutMainFunc(t *testing.T) { @@ -282,6 +290,7 @@ func TestRunPipeWithoutMainFunc(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" t.Run("empty", func(t *testing.T) { ctx.Config.Builds[0].Main = "" assert.EqualError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ @@ -328,6 +337,7 @@ func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "5.6.7" t.Run("empty", func(t *testing.T) { ctx.Config.Builds[0].Main = "" assert.NoError(t, Default.Build(ctx, ctx.Config.Builds[0], api.Options{ @@ -349,25 +359,16 @@ func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) { } func TestLdFlagsFullTemplate(t *testing.T) { - var config = config.Project{ - Builds: []config.Build{ - { - Ldflags: []string{ - `-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}" -X main.time={{ time "20060102" }}`, - }, - }, - }, - } var ctx = &context.Context{ Git: context.GitInfo{ CurrentTag: "v1.2.3", Commit: "123", }, Version: "1.2.3", - Config: config, Env: map[string]string{"FOO": "123"}, } - flags, err := processField(ctx, ctx.Config.Builds[0].Ldflags[0], "ldflags") + flags, err := tmpl.New(ctx). + Apply(`-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}" -X main.time={{ time "20060102" }}`) assert.NoError(t, err) assert.Contains(t, flags, "-s -w") assert.Contains(t, flags, "-X main.version=1.2.3") @@ -381,19 +382,13 @@ func TestLdFlagsFullTemplate(t *testing.T) { func TestInvalidTemplate(t *testing.T) { for template, eerr := range map[string]string{ - "{{ .Nope }": `template: ldflags:1: unexpected "}" in operand`, - "{{.Env.NOPE}}": `template: ldflags:1:6: executing "ldflags" at <.Env.NOPE>: map has no entry for key "NOPE"`, + "{{ .Nope }": `template: tmpl:1: unexpected "}" in operand`, + "{{.Env.NOPE}}": `template: tmpl:1:6: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`, } { t.Run(template, func(tt *testing.T) { - var config = config.Project{ - Builds: []config.Build{ - {Ldflags: []string{template}}, - }, - } - var ctx = &context.Context{ - Config: config, - } - flags, err := processField(ctx, template, "ldflags") + var ctx = context.New(config.Project{}) + ctx.Git.CurrentTag = "3.4.1" + flags, err := tmpl.New(ctx).Apply(template) assert.EqualError(tt, err, eerr) assert.Empty(tt, flags) }) @@ -404,6 +399,7 @@ func TestProcessFlags(t *testing.T) { var ctx = &context.Context{ Version: "1.2.3", } + ctx.Git.CurrentTag = "5.6.7" var source = []string{ "{{.Version}}", @@ -428,7 +424,7 @@ func TestProcessFlagsInvalid(t *testing.T) { "{{.Version}", } - var expected = `template: testflag:1: unexpected "}" in operand` + var expected = `template: tmpl:1: unexpected "}" in operand` flags, err := processFlags(ctx, source, "testflag", "-testflag=") assert.EqualError(t, err, expected) diff --git a/internal/tmpl/tmpl.go b/internal/tmpl/tmpl.go index 5fcc8cd3e02..7fd48c76b34 100644 --- a/internal/tmpl/tmpl.go +++ b/internal/tmpl/tmpl.go @@ -29,6 +29,8 @@ const ( kMinor = "Minor" kPatch = "Patch" kEnv = "Env" + kDate = "Date" + kTimestamp = "Timestamp" // artifact-only keys kOs = "Os" @@ -46,6 +48,8 @@ func New(ctx *context.Context) *Template { kTag: ctx.Git.CurrentTag, kCommit: ctx.Git.Commit, kEnv: ctx.Env, + kDate: time.Now().UTC().Format(time.RFC3339), + kTimestamp: time.Now().UTC().Unix(), }, } } diff --git a/pipeline/build/build.go b/pipeline/build/build.go index d35c598ff79..9e73e428bbf 100644 --- a/pipeline/build/build.go +++ b/pipeline/build/build.go @@ -3,13 +3,10 @@ package build import ( - "bytes" "os" "os/exec" "path/filepath" "strings" - "text/template" - "time" "github.com/apex/log" "github.com/pkg/errors" @@ -21,6 +18,7 @@ import ( // langs to init _ "github.com/goreleaser/goreleaser/internal/builders/golang" + "github.com/goreleaser/goreleaser/internal/tmpl" ) // Pipe for build @@ -102,7 +100,7 @@ func runHook(ctx *context.Context, env []string, hook string) error { func doBuild(ctx *context.Context, build config.Build, target string) error { var ext = extFor(target) - binary, err := binary(ctx, build) + binary, err := tmpl.New(ctx).Apply(build.Binary) if err != nil { return err } @@ -119,31 +117,6 @@ func doBuild(ctx *context.Context, build config.Build, target string) error { }) } -func binary(ctx *context.Context, build config.Build) (string, error) { - var data = struct { - Commit string - Tag string - Version string - Date string - Env map[string]string - }{ - Commit: ctx.Git.Commit, - Tag: ctx.Git.CurrentTag, - Version: ctx.Version, - Date: time.Now().UTC().Format(time.RFC3339), - Env: ctx.Env, - } - var out bytes.Buffer - t, err := template.New("binary"). - Option("missingkey=error"). - Parse(build.Binary) - if err != nil { - return "", err - } - err = t.Execute(&out, data) - return out.String(), err -} - func extFor(target string) string { if strings.Contains(target, "windows") { return ".exe" diff --git a/pipeline/build/build_test.go b/pipeline/build/build_test.go index 7bdca1e87a3..6057f4fa762 100644 --- a/pipeline/build/build_test.go +++ b/pipeline/build/build_test.go @@ -11,6 +11,7 @@ import ( "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/artifact" "github.com/goreleaser/goreleaser/internal/testlib" + "github.com/goreleaser/goreleaser/internal/tmpl" "github.com/stretchr/testify/assert" ) @@ -84,6 +85,7 @@ func TestRunPipe(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "2.4.5" assert.NoError(t, Pipe{}.Run(ctx)) assert.Equal(t, ctx.Artifacts.List(), []artifact.Artifact{fakeArtifact}) } @@ -109,6 +111,7 @@ func TestRunFullPipe(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "2.4.5" assert.NoError(t, Pipe{}.Run(ctx)) assert.Equal(t, ctx.Artifacts.List(), []artifact.Artifact{fakeArtifact}) assert.True(t, exists(pre), pre) @@ -136,6 +139,7 @@ func TestRunFullPipeFail(t *testing.T) { }, } var ctx = context.New(config) + ctx.Git.CurrentTag = "2.4.5" assert.EqualError(t, Pipe{}.Run(ctx), errFailedBuild.Error()) assert.Empty(t, ctx.Artifacts.List()) assert.True(t, exists(pre), pre) @@ -155,12 +159,14 @@ func TestRunPipeFailingHooks(t *testing.T) { } t.Run("pre-hook", func(t *testing.T) { var ctx = context.New(config) + ctx.Git.CurrentTag = "2.3.4" ctx.Config.Builds[0].Hooks.Pre = "exit 1" ctx.Config.Builds[0].Hooks.Post = "echo post" assert.EqualError(t, Pipe{}.Run(ctx), `pre hook failed: `) }) t.Run("post-hook", func(t *testing.T) { var ctx = context.New(config) + ctx.Git.CurrentTag = "2.3.4" ctx.Config.Builds[0].Hooks.Pre = "echo pre" ctx.Config.Builds[0].Hooks.Post = "exit 1" assert.EqualError(t, Pipe{}.Run(ctx), `post hook failed: `) @@ -288,24 +294,16 @@ func TestExtOthers(t *testing.T) { assert.Empty(t, "", extFor("winasdasd_sad")) } -func TestBinaryFullTemplate(t *testing.T) { - var config = config.Project{ - Builds: []config.Build{ - { - Binary: `-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}"`, - }, - }, - } - var ctx = &context.Context{ - Git: context.GitInfo{ - CurrentTag: "v1.2.3", - Commit: "123", - }, - Version: "1.2.3", - Config: config, - Env: map[string]string{"FOO": "123"}, +func TestTemplate(t *testing.T) { + var ctx = context.New(config.Project{}) + ctx.Git = context.GitInfo{ + CurrentTag: "v1.2.3", + Commit: "123", } - binary, err := binary(ctx, ctx.Config.Builds[0]) + ctx.Version = "1.2.3" + ctx.Env = map[string]string{"FOO": "123"} + binary, err := tmpl.New(ctx). + Apply(`-s -w -X main.version={{.Version}} -X main.tag={{.Tag}} -X main.date={{.Date}} -X main.commit={{.Commit}} -X "main.foo={{.Env.FOO}}"`) assert.NoError(t, err) assert.Contains(t, binary, "-s -w") assert.Contains(t, binary, "-X main.version=1.2.3") diff --git a/pipeline/git/git.go b/pipeline/git/git.go index d06479d78f6..61d1d456688 100644 --- a/pipeline/git/git.go +++ b/pipeline/git/git.go @@ -1,16 +1,14 @@ package git import ( - "bytes" "fmt" "regexp" "strings" - "text/template" - "time" "github.com/apex/log" "github.com/goreleaser/goreleaser/context" "github.com/goreleaser/goreleaser/internal/git" + "github.com/goreleaser/goreleaser/internal/tmpl" "github.com/goreleaser/goreleaser/pipeline" "github.com/pkg/errors" ) @@ -80,7 +78,7 @@ func getGitInfo(ctx *context.Context) (context.GitInfo, error) { func setVersion(ctx *context.Context) error { if ctx.Snapshot { - snapshotName, err := getSnapshotName(ctx) + snapshotName, err := tmpl.New(ctx).Apply(ctx.Config.Snapshot.NameTemplate) if err != nil { return errors.Wrap(err, "failed to generate snapshot name") } @@ -92,27 +90,6 @@ func setVersion(ctx *context.Context) error { return nil } -type snapshotNameData struct { - Commit string - Tag string - Timestamp int64 -} - -func getSnapshotName(ctx *context.Context) (string, error) { - tmpl, err := template.New("snapshot").Parse(ctx.Config.Snapshot.NameTemplate) - var out bytes.Buffer - if err != nil { - return "", err - } - var data = snapshotNameData{ - Commit: ctx.Git.Commit, - Tag: ctx.Git.CurrentTag, - Timestamp: time.Now().Unix(), - } - err = tmpl.Execute(&out, data) - return out.String(), err -} - func validate(ctx *context.Context) error { if ctx.Snapshot { return pipeline.ErrSnapshotEnabled diff --git a/pipeline/git/git_test.go b/pipeline/git/git_test.go index ee1a155ceb1..8fba1e186b0 100644 --- a/pipeline/git/git_test.go +++ b/pipeline/git/git_test.go @@ -75,7 +75,7 @@ func TestNoTagsSnapshotInvalidTemplate(t *testing.T) { }, }) ctx.Snapshot = true - assert.EqualError(t, Pipe{}.Run(ctx), `failed to generate snapshot name: template: snapshot:1: unexpected unclosed action in command`) + assert.EqualError(t, Pipe{}.Run(ctx), `failed to generate snapshot name: template: tmpl:1: unexpected unclosed action in command`) } // TestNoTagsNoSnapshot covers the situation where a repository