1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-10-30 23:58:09 +02:00

feat: template release notes (#2242)

Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
This commit is contained in:
Carlos Alexandro Becker
2021-05-21 21:07:47 -03:00
committed by GitHub
parent 2d136c4c90
commit 9913fe7db6
6 changed files with 114 additions and 86 deletions

View File

@@ -19,18 +19,21 @@ type releaseCmd struct {
}
type releaseOpts struct {
config string
releaseNotes string
releaseHeader string
releaseFooter string
snapshot bool
skipPublish bool
skipSign bool
skipValidate bool
rmDist bool
deprecated bool
parallelism int
timeout time.Duration
config string
releaseNotesFile string
releaseNotesTmpl string
releaseHeaderFile string
releaseHeaderTmpl string
releaseFooterFile string
releaseFooterTmpl string
snapshot bool
skipPublish bool
skipSign bool
skipValidate bool
rmDist bool
deprecated bool
parallelism int
timeout time.Duration
}
func newReleaseCmd() *releaseCmd {
@@ -63,9 +66,12 @@ func newReleaseCmd() *releaseCmd {
}
cmd.Flags().StringVarP(&root.opts.config, "config", "f", "", "Load configuration from file")
cmd.Flags().StringVar(&root.opts.releaseNotes, "release-notes", "", "Load custom release notes from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseHeader, "release-header", "", "Load custom release notes header from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseFooter, "release-footer", "", "Load custom release notes footer from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseNotesFile, "release-notes", "", "Load custom release notes from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseHeaderFile, "release-header", "", "Load custom release notes header from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseFooterFile, "release-footer", "", "Load custom release notes footer from a markdown file")
cmd.Flags().StringVar(&root.opts.releaseNotesTmpl, "release-notes-tmpl", "", "Load custom release notes from a templated markdown file (overrides --release-notes)")
cmd.Flags().StringVar(&root.opts.releaseHeaderTmpl, "release-header-tmpl", "", "Load custom release notes header from a templated markdown file (overrides --release-header)")
cmd.Flags().StringVar(&root.opts.releaseFooterTmpl, "release-footer-tmpl", "", "Load custom release notes footer from a templated markdown file (overrides --release-footer)")
cmd.Flags().BoolVar(&root.opts.snapshot, "snapshot", false, "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts")
cmd.Flags().BoolVar(&root.opts.skipPublish, "skip-publish", false, "Skips publishing artifacts")
cmd.Flags().BoolVar(&root.opts.skipSign, "skip-sign", false, "Skips signing the artifacts")
@@ -108,9 +114,12 @@ func setupReleaseContext(ctx *context.Context, options releaseOpts) *context.Con
ctx.Parallelism = options.parallelism
}
log.Debugf("parallelism: %v", ctx.Parallelism)
ctx.ReleaseNotes = options.releaseNotes
ctx.ReleaseHeader = options.releaseHeader
ctx.ReleaseFooter = options.releaseFooter
ctx.ReleaseNotesFile = options.releaseNotesFile
ctx.ReleaseNotesTmpl = options.releaseNotesTmpl
ctx.ReleaseHeaderFile = options.releaseHeaderFile
ctx.ReleaseHeaderTmpl = options.releaseHeaderTmpl
ctx.ReleaseFooterFile = options.releaseFooterFile
ctx.ReleaseFooterTmpl = options.releaseFooterTmpl
ctx.Snapshot = options.snapshot
ctx.SkipPublish = ctx.Snapshot || options.skipPublish
ctx.SkipValidate = ctx.Snapshot || options.skipValidate

View File

@@ -67,13 +67,27 @@ func TestReleaseFlags(t *testing.T) {
header := "header.md"
footer := "footer.md"
ctx := setup(releaseOpts{
releaseNotes: notes,
releaseHeader: header,
releaseFooter: footer,
releaseNotesFile: notes,
releaseHeaderFile: header,
releaseFooterFile: footer,
})
require.Equal(t, notes, ctx.ReleaseNotes)
require.Equal(t, header, ctx.ReleaseHeader)
require.Equal(t, footer, ctx.ReleaseFooter)
require.Equal(t, notes, ctx.ReleaseNotesFile)
require.Equal(t, header, ctx.ReleaseHeaderFile)
require.Equal(t, footer, ctx.ReleaseFooterFile)
})
t.Run("templated notes", func(t *testing.T) {
notes := "foo.md"
header := "header.md"
footer := "footer.md"
ctx := setup(releaseOpts{
releaseNotesTmpl: notes,
releaseHeaderTmpl: header,
releaseFooterTmpl: footer,
})
require.Equal(t, notes, ctx.ReleaseNotesTmpl)
require.Equal(t, header, ctx.ReleaseHeaderTmpl)
require.Equal(t, footer, ctx.ReleaseFooterTmpl)
})
t.Run("rm dist", func(t *testing.T) {

View File

@@ -29,21 +29,12 @@ func (Pipe) String() string {
// Run the pipe.
func (Pipe) Run(ctx *context.Context) error {
// TODO: should probably have a different field for the filename and its
// contents.
if ctx.ReleaseNotes != "" {
notes, err := loadFromFile(ctx.ReleaseNotes)
if err != nil {
return err
}
notes, err = tmpl.New(ctx).Apply(notes)
if err != nil {
return err
}
log.WithField("file", ctx.ReleaseNotes).Info("loaded custom release notes")
log.WithField("file", ctx.ReleaseNotes).Debugf("custom release notes: \n%s", notes)
ctx.ReleaseNotes = notes
notes, err := loadContent(ctx, ctx.ReleaseNotesFile, ctx.ReleaseNotesTmpl)
if err != nil {
return err
}
ctx.ReleaseNotes = notes
if ctx.Config.Changelog.Skip {
return pipe.ErrSkipDisabledPipe
}
@@ -53,27 +44,15 @@ func (Pipe) Run(ctx *context.Context) error {
if ctx.ReleaseNotes != "" {
return nil
}
if ctx.ReleaseHeader != "" {
header, err := loadFromFile(ctx.ReleaseHeader)
if err != nil {
return err
}
header, err = tmpl.New(ctx).Apply(header)
if err != nil {
return err
}
ctx.ReleaseHeader = header
footer, err := loadContent(ctx, ctx.ReleaseFooterFile, ctx.ReleaseFooterTmpl)
if err != nil {
return err
}
if ctx.ReleaseFooter != "" {
footer, err := loadFromFile(ctx.ReleaseFooter)
if err != nil {
return err
}
footer, err = tmpl.New(ctx).Apply(footer)
if err != nil {
return err
}
ctx.ReleaseFooter = footer
header, err := loadContent(ctx, ctx.ReleaseHeaderFile, ctx.ReleaseHeaderTmpl)
if err != nil {
return err
}
if err := checkSortDirection(ctx.Config.Changelog.Sort); err != nil {
@@ -97,11 +76,11 @@ func (Pipe) Run(ctx *context.Context) error {
"## Changelog",
strings.Join(entries, changelogStringJoiner),
}
if len(ctx.ReleaseHeader) > 0 {
changelogElements = append([]string{ctx.ReleaseHeader}, changelogElements...)
if header != "" {
changelogElements = append([]string{header}, changelogElements...)
}
if len(ctx.ReleaseFooter) > 0 {
changelogElements = append(changelogElements, ctx.ReleaseFooter)
if footer != "" {
changelogElements = append(changelogElements, footer)
}
ctx.ReleaseNotes = strings.Join(changelogElements, "\n\n")
@@ -225,3 +204,21 @@ var validSHA1 = regexp.MustCompile(`^[a-fA-F0-9]{40}$`)
func isSHA1(ref string) bool {
return validSHA1.MatchString(ref)
}
func loadContent(ctx *context.Context, fileName, tmplName string) (string, error) {
if tmplName != "" {
log.Debugf("loading template %s", tmplName)
content, err := loadFromFile(tmplName)
if err != nil {
return "", err
}
return tmpl.New(ctx).Apply(content)
}
if fileName != "" {
log.Debugf("loading file %s", fileName)
return loadFromFile(fileName)
}
return "", nil
}

View File

@@ -18,14 +18,15 @@ func TestDescription(t *testing.T) {
func TestChangelogProvidedViaFlag(t *testing.T) {
ctx := context.New(config.Project{})
ctx.ReleaseNotes = "testdata/changes.md"
ctx.ReleaseNotesFile = "testdata/changes.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "c0ff33 coffeee\n", ctx.ReleaseNotes)
}
func TestTemplatedChangelogProvidedViaFlag(t *testing.T) {
ctx := context.New(config.Project{})
ctx.ReleaseNotes = "testdata/changes-templated.md"
ctx.ReleaseNotesFile = "testdata/changes.md"
ctx.ReleaseNotesTmpl = "testdata/changes-templated.md"
ctx.Git.CurrentTag = "v0.0.1"
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "c0ff33 coffeee v0.0.1\n", ctx.ReleaseNotes)
@@ -37,14 +38,14 @@ func TestChangelogProvidedViaFlagAndSkipEnabled(t *testing.T) {
Skip: true,
},
})
ctx.ReleaseNotes = "testdata/changes.md"
ctx.ReleaseNotesFile = "testdata/changes.md"
testlib.AssertSkipped(t, Pipe{}.Run(ctx))
require.Equal(t, "c0ff33 coffeee\n", ctx.ReleaseNotes)
}
func TestChangelogProvidedViaFlagDoesntExist(t *testing.T) {
ctx := context.New(config.Project{})
ctx.ReleaseNotes = "testdata/changes.nope"
ctx.ReleaseNotesFile = "testdata/changes.nope"
require.EqualError(t, Pipe{}.Run(ctx), "open testdata/changes.nope: no such file or directory")
}
@@ -56,13 +57,13 @@ func TestChangelogSkip(t *testing.T) {
func TestReleaseHeaderProvidedViaFlagDoesntExist(t *testing.T) {
ctx := context.New(config.Project{})
ctx.ReleaseHeader = "testdata/header.nope"
ctx.ReleaseHeaderFile = "testdata/header.nope"
require.EqualError(t, Pipe{}.Run(ctx), "open testdata/header.nope: no such file or directory")
}
func TestReleaseFooterProvidedViaFlagDoesntExist(t *testing.T) {
ctx := context.New(config.Project{})
ctx.ReleaseFooter = "testdata/footer.nope"
ctx.ReleaseFooterFile = "testdata/footer.nope"
require.EqualError(t, Pipe{}.Run(ctx), "open testdata/footer.nope: no such file or directory")
}
@@ -341,7 +342,7 @@ func TestChangeLogWithReleaseHeader(t *testing.T) {
testlib.GitCheckoutBranch(t, "v0.0.1")
ctx := context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseHeader = "testdata/release-header.md"
ctx.ReleaseHeaderFile = "testdata/release-header.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test header")
@@ -366,7 +367,7 @@ func TestChangeLogWithTemplatedReleaseHeader(t *testing.T) {
testlib.GitCheckoutBranch(t, "v0.0.1")
ctx := context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseHeader = "testdata/release-header-templated.md"
ctx.ReleaseHeaderTmpl = "testdata/release-header-templated.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test header with tag v0.0.1")
@@ -391,7 +392,7 @@ func TestChangeLogWithReleaseFooter(t *testing.T) {
testlib.GitCheckoutBranch(t, "v0.0.1")
ctx := context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseFooter = "testdata/release-footer.md"
ctx.ReleaseFooterFile = "testdata/release-footer.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test footer")
@@ -417,7 +418,7 @@ func TestChangeLogWithTemplatedReleaseFooter(t *testing.T) {
testlib.GitCheckoutBranch(t, "v0.0.1")
ctx := context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseFooter = "testdata/release-footer-templated.md"
ctx.ReleaseFooterTmpl = "testdata/release-footer-templated.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test footer with tag v0.0.1")

View File

@@ -73,8 +73,12 @@ type Context struct {
Date time.Time
Artifacts artifact.Artifacts
ReleaseNotes string
ReleaseHeader string
ReleaseFooter string
ReleaseNotesFile string
ReleaseNotesTmpl string
ReleaseHeaderFile string
ReleaseHeaderTmpl string
ReleaseFooterFile string
ReleaseFooterTmpl string
Version string
ModulePath string
Snapshot bool

View File

@@ -9,18 +9,21 @@ goreleaser release [flags]
## Options
```
-f, --config string Load configuration from file
-h, --help help for release
-p, --parallelism int Amount tasks to run concurrently (default: number of CPUs)
--release-footer string Load custom release notes footer from a markdown file
--release-header string Load custom release notes header from a markdown file
--release-notes string Load custom release notes from a markdown file
--rm-dist Remove the dist folder before building
--skip-publish Skips publishing artifacts
--skip-sign Skips signing the artifacts
--skip-validate Skips several sanity checks
--snapshot Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts
--timeout duration Timeout to the entire release process (default 30m0s)
-f, --config string Load configuration from file
-h, --help help for release
-p, --parallelism int Amount tasks to run concurrently (default: number of CPUs)
--release-footer string Load custom release notes footer from a markdown file
--release-footer-tmpl string Load custom release notes footer from a templated markdown file (overrides --release-footer)
--release-header string Load custom release notes header from a markdown file
--release-header-tmpl string Load custom release notes header from a templated markdown file (overrides --release-header)
--release-notes string Load custom release notes from a markdown file
--release-notes-tmpl string Load custom release notes from a templated markdown file (overrides --release-notes)
--rm-dist Remove the dist folder before building
--skip-publish Skips publishing artifacts
--skip-sign Skips signing the artifacts
--skip-validate Skips several sanity checks
--snapshot Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts
--timeout duration Timeout to the entire release process (default 30m0s)
```
## Options inherited from parent commands