1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-09-16 09:26:52 +02:00

feat: Added new flags to support release notes header and footer. (#1212)

* Added new flags to support release notes header and footer.

Created two flags for release generation.
--release-footer
--release-header
These flags can help you to add custom changelog text before/after changes that are generated by git log.

* Fix changelog.go to avoid lint errors

* Fix test typo

* Added tests for main, fixed bug with no passing options to release ctx

* Add @caarlos0  suggestions
This commit is contained in:
Ivan Novikov
2019-11-15 13:22:11 +00:00
committed by Carlos Alexandro Becker
parent fdfe0487df
commit 16cb4d8277
7 changed files with 186 additions and 39 deletions

View File

@@ -35,6 +35,8 @@ func (Pipe) Run(ctx *context.Context) error {
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
}
if ctx.Config.Changelog.Skip {
@@ -46,9 +48,25 @@ 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
}
ctx.ReleaseHeader = header
}
if ctx.ReleaseFooter != "" {
footer, err := loadFromFile(ctx.ReleaseFooter)
if err != nil {
return err
}
ctx.ReleaseFooter = footer
}
if err := checkSortDirection(ctx.Config.Changelog.Sort); err != nil {
return err
}
entries, err := buildChangelog(ctx)
if err != nil {
return err
@@ -61,7 +79,17 @@ func (Pipe) Run(ctx *context.Context) error {
log.Debug("is gitlab or gitea changelog")
changelogStringJoiner = " \n"
}
ctx.ReleaseNotes = fmt.Sprintf("## Changelog\n\n%v\n", strings.Join(entries, changelogStringJoiner))
ctx.ReleaseNotes = strings.Join(
[]string{
ctx.ReleaseHeader,
"## Changelog",
strings.Join(entries, changelogStringJoiner),
ctx.ReleaseFooter,
},
"\n\n",
)
var path = filepath.Join(ctx.Config.Dist, "CHANGELOG.md")
log.WithField("changelog", path).Info("writing")
return ioutil.WriteFile(path, []byte(ctx.ReleaseNotes), 0644)
@@ -72,8 +100,6 @@ func loadFromFile(file string) (string, error) {
if err != nil {
return "", err
}
log.WithField("file", file).Info("loaded custom release notes")
log.WithField("file", file).Debugf("custom release notes: \n%s", string(bts))
return string(bts), nil
}

View File

@@ -2,6 +2,7 @@ package changelog
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -46,6 +47,18 @@ func TestChangelogSkip(t *testing.T) {
testlib.AssertSkipped(t, Pipe{}.Run(ctx))
}
func TestReleaseHeaderProvidedViaFlagDoesntExist(t *testing.T) {
var ctx = context.New(config.Project{})
ctx.ReleaseHeader = "testdata/header.nope"
require.EqualError(t, Pipe{}.Run(ctx), "open testdata/header.nope: no such file or directory")
}
func TestReleaseFooterProvidedViaFlagDoesntExist(t *testing.T) {
var ctx = context.New(config.Project{})
ctx.ReleaseFooter = "testdata/footer.nope"
require.EqualError(t, Pipe{}.Run(ctx), "open testdata/footer.nope: no such file or directory")
}
func TestSnapshot(t *testing.T) {
var ctx = context.New(config.Project{})
ctx.Snapshot = true
@@ -285,3 +298,55 @@ func TestChangelogOnBranchWithSameNameAsTag(t *testing.T) {
require.Contains(t, ctx.ReleaseNotes, msg)
}
}
func TestChangeLogWithReleaseHeader(t *testing.T) {
current, err := os.Getwd()
require.NoError(t, err)
tmpdir, back := testlib.Mktmp(t)
defer back()
require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata"))
testlib.GitInit(t)
var msgs = []string{
"initial commit",
"another one",
"one more",
"and finally this one",
}
for _, msg := range msgs {
testlib.GitCommit(t, msg)
}
testlib.GitTag(t, "v0.0.1")
testlib.GitCheckoutBranch(t, "v0.0.1")
var ctx = context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseHeader = "testdata/release-header.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test header")
}
func TestChangeLogWithReleaseFooter(t *testing.T) {
current, err := os.Getwd()
require.NoError(t, err)
tmpdir, back := testlib.Mktmp(t)
defer back()
require.NoError(t, os.Symlink(current+"/testdata", tmpdir+"/testdata"))
testlib.GitInit(t)
var msgs = []string{
"initial commit",
"another one",
"one more",
"and finally this one",
}
for _, msg := range msgs {
testlib.GitCommit(t, msg)
}
testlib.GitTag(t, "v0.0.1")
testlib.GitCheckoutBranch(t, "v0.0.1")
var ctx = context.New(config.Project{})
ctx.Git.CurrentTag = "v0.0.1"
ctx.ReleaseFooter = "testdata/release-footer.md"
require.NoError(t, Pipe{}.Run(ctx))
require.Contains(t, ctx.ReleaseNotes, "## Changelog")
require.Contains(t, ctx.ReleaseNotes, "test footer")
}

View File

@@ -0,0 +1 @@
test footer

View File

@@ -0,0 +1 @@
test header

46
main.go
View File

@@ -16,7 +16,7 @@ import (
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
"github.com/goreleaser/goreleaser/pkg/defaults"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"gopkg.in/alecthomas/kingpin.v2"
)
// nolint: gochecknoglobals
@@ -28,15 +28,17 @@ var (
)
type releaseOptions struct {
Config string
ReleaseNotes string
Snapshot bool
SkipPublish bool
SkipSign bool
SkipValidate bool
RmDist bool
Parallelism int
Timeout time.Duration
Config string
ReleaseNotes string
ReleaseHeader string
ReleaseFooter string
Snapshot bool
SkipPublish bool
SkipSign bool
SkipValidate bool
RmDist bool
Parallelism int
Timeout time.Duration
}
func main() {
@@ -56,6 +58,8 @@ func main() {
var checkCmd = app.Command("check", "Checks if configuration is valid").Alias("c")
var releaseCmd = app.Command("release", "Releases the current project").Alias("r").Default()
var releaseNotes = releaseCmd.Flag("release-notes", "Load custom release notes from a markdown file").PlaceHolder("notes.md").String()
var releaseHeader = releaseCmd.Flag("release-header", "Load custom release notes header from a markdown file").PlaceHolder("notes-header.md").String()
var releaseFooter = releaseCmd.Flag("release-footer", "Load custom release notes footer from a markdown file").PlaceHolder("notes-footer.md").String()
var snapshot = releaseCmd.Flag("snapshot", "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts").Bool()
var skipPublish = releaseCmd.Flag("skip-publish", "Skips publishing artifacts").Bool()
var skipSign = releaseCmd.Flag("skip-sign", "Skips signing the artifacts").Bool()
@@ -96,15 +100,17 @@ func main() {
start := time.Now()
log.Infof(color.New(color.Bold).Sprintf("releasing using goreleaser %s...", version))
var options = releaseOptions{
Config: *config,
ReleaseNotes: *releaseNotes,
Snapshot: *snapshot,
SkipPublish: *skipPublish,
SkipValidate: *skipValidate,
SkipSign: *skipSign,
RmDist: *rmDist,
Parallelism: *parallelism,
Timeout: *timeout,
Config: *config,
ReleaseNotes: *releaseNotes,
ReleaseHeader: *releaseHeader,
ReleaseFooter: *releaseFooter,
Snapshot: *snapshot,
SkipPublish: *skipPublish,
SkipValidate: *skipValidate,
SkipSign: *skipSign,
RmDist: *rmDist,
Parallelism: *parallelism,
Timeout: *timeout,
}
if err := releaseProject(options); err != nil {
log.WithError(err).Errorf(color.New(color.Bold).Sprintf("release failed after %0.2fs", time.Since(start).Seconds()))
@@ -141,6 +147,8 @@ func releaseProject(options releaseOptions) error {
ctx.Parallelism = options.Parallelism
log.Debugf("parallelism: %v", ctx.Parallelism)
ctx.ReleaseNotes = options.ReleaseNotes
ctx.ReleaseHeader = options.ReleaseHeader
ctx.ReleaseFooter = options.ReleaseFooter
ctx.Snapshot = options.Snapshot
ctx.SkipPublish = ctx.Snapshot || options.SkipPublish
ctx.SkipValidate = ctx.Snapshot || options.SkipValidate

View File

@@ -11,7 +11,7 @@ import (
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
yaml "gopkg.in/yaml.v2"
"gopkg.in/yaml.v2"
)
func init() {
@@ -107,6 +107,50 @@ func TestCustomReleaseNotesFile(t *testing.T) {
assert.NoError(t, releaseProject(params))
}
func TestCustomReleaseHeaderFileDontExist(t *testing.T) {
_, back := setup(t)
defer back()
params := testParams()
params.ReleaseHeader = "/header/that/dont/exist"
params.Snapshot = false
assert.Error(t, releaseProject(params))
}
func TestCustomReleaseHeaderFile(t *testing.T) {
_, back := setup(t)
defer back()
releaseHeader, err := ioutil.TempFile("", "")
assert.NoError(t, err)
createFile(t, releaseHeader.Name(), "some release header")
params := testParams()
params.ReleaseHeader = releaseHeader.Name()
params.Snapshot = false
params.SkipPublish = true
assert.NoError(t, releaseProject(params))
}
func TestCustomReleaseFooterFileDontExist(t *testing.T) {
_, back := setup(t)
defer back()
params := testParams()
params.ReleaseFooter = "/footer/that/dont/exist"
params.Snapshot = false
assert.Error(t, releaseProject(params))
}
func TestCustomReleaseFooterFile(t *testing.T) {
_, back := setup(t)
defer back()
releaseFooter, err := ioutil.TempFile("", "")
assert.NoError(t, err)
createFile(t, releaseFooter.Name(), "some release footer")
params := testParams()
params.ReleaseFooter = releaseFooter.Name()
params.Snapshot = false
params.SkipPublish = true
assert.NoError(t, releaseProject(params))
}
func TestBrokenPipe(t *testing.T) {
_, back := setup(t)
defer back()

View File

@@ -53,22 +53,24 @@ const (
// Context carries along some data through the pipes
type Context struct {
ctx.Context
Config config.Project
Env Env
Token string
TokenType TokenType
Git GitInfo
Artifacts artifact.Artifacts
ReleaseNotes string
Version string
Snapshot bool
SkipPublish bool
SkipSign bool
SkipValidate bool
RmDist bool
PreRelease bool
Parallelism int
Semver Semver
Config config.Project
Env Env
Token string
TokenType TokenType
Git GitInfo
Artifacts artifact.Artifacts
ReleaseNotes string
ReleaseHeader string
ReleaseFooter string
Version string
Snapshot bool
SkipPublish bool
SkipSign bool
SkipValidate bool
RmDist bool
PreRelease bool
Parallelism int
Semver Semver
}
// Semver represents a semantic version