From 2621c48d75e6af251c10ec924cd5874a43aeee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20T=C3=B6lle?= Date: Sun, 22 Sep 2024 14:00:30 +0200 Subject: [PATCH] feat(changelog): omit version heading in forge release notes The forge ui usually shows the release name right above the description, so this removes an unecessary duplicate bit of information. In addition this also cleans up the changelog interface a bit and moves functionality where it belongs. Prepares a bit for custom changelogs in the future. Closes #32 --- internal/changelog/changelog.go | 44 ++++++++++++++++----------- internal/changelog/changelog.md.tpl | 28 +++++++++-------- internal/changelog/changelog_test.go | 3 +- internal/commitparser/commitparser.go | 15 +++++++++ releaserpleaser.go | 15 +++++++-- 5 files changed, 71 insertions(+), 34 deletions(-) diff --git a/internal/changelog/changelog.go b/internal/changelog/changelog.go index 6004829..d6386b8 100644 --- a/internal/changelog/changelog.go +++ b/internal/changelog/changelog.go @@ -26,27 +26,37 @@ func init() { } } -func NewChangelogEntry(logger *slog.Logger, commits []commitparser.AnalyzedCommit, version, link, prefix, suffix string) (string, error) { - features := make([]commitparser.AnalyzedCommit, 0) - fixes := make([]commitparser.AnalyzedCommit, 0) +func DefaultTemplate() *template.Template { + return changelogTemplate +} - for _, commit := range commits { - switch commit.Type { - case "feat": - features = append(features, commit) - case "fix": - fixes = append(fixes, commit) - } +type Data struct { + Commits map[string][]commitparser.AnalyzedCommit + Version string + VersionLink string + Prefix string + Suffix string +} + +func New(commits map[string][]commitparser.AnalyzedCommit, version, versionLink, prefix, suffix string) Data { + return Data{ + Commits: commits, + Version: version, + VersionLink: versionLink, + Prefix: prefix, + Suffix: suffix, } +} +type Formatting struct { + HideVersionTitle bool +} + +func Entry(logger *slog.Logger, tpl *template.Template, data Data, formatting Formatting) (string, error) { var changelog bytes.Buffer - err := changelogTemplate.Execute(&changelog, map[string]any{ - "Features": features, - "Fixes": fixes, - "Version": version, - "VersionLink": link, - "Prefix": prefix, - "Suffix": suffix, + err := tpl.Execute(&changelog, map[string]any{ + "Data": data, + "Formatting": formatting, }) if err != nil { return "", err diff --git a/internal/changelog/changelog.md.tpl b/internal/changelog/changelog.md.tpl index 1f7dd42..50907eb 100644 --- a/internal/changelog/changelog.md.tpl +++ b/internal/changelog/changelog.md.tpl @@ -1,22 +1,24 @@ -## [{{.Version}}]({{.VersionLink}}) -{{- if .Prefix }} -{{ .Prefix }} +{{define "entry" -}} +- {{ if .Scope }}**{{.Scope}}**: {{end}}{{.Description}} +{{ end }} + +{{- if not .Formatting.HideVersionTitle }} +## [{{.Data.Version}}]({{.Data.VersionLink}}) {{ end -}} -{{- if (gt (len .Features) 0) }} +{{- if .Data.Prefix }} +{{ .Data.Prefix }} +{{ end -}} +{{- with .Data.Commits.feat }} ### Features -{{ range .Features -}} -- {{ if .Scope }}**{{.Scope}}**: {{end}}{{.Description}} -{{ end -}} +{{ range . -}}{{template "entry" .}}{{end}} {{- end -}} -{{- if (gt (len .Fixes) 0) }} +{{- with .Data.Commits.fix }} ### Bug Fixes -{{ range .Fixes -}} -- {{ if .Scope }}**{{.Scope}}**: {{end}}{{.Description}} -{{ end -}} +{{ range . -}}{{template "entry" .}}{{end}} {{- end -}} -{{- if .Suffix }} -{{ .Suffix }} +{{- if .Data.Suffix }} +{{ .Data.Suffix }} {{ end }} diff --git a/internal/changelog/changelog_test.go b/internal/changelog/changelog_test.go index e6582c7..a969730 100644 --- a/internal/changelog/changelog_test.go +++ b/internal/changelog/changelog_test.go @@ -168,7 +168,8 @@ This version is compatible with flux-compensator v2.2 - v2.9. for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := NewChangelogEntry(slog.Default(), tt.args.analyzedCommits, tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix) + data := New(commitparser.ByType(tt.args.analyzedCommits), tt.args.version, tt.args.link, tt.args.prefix, tt.args.suffix) + got, err := Entry(slog.Default(), DefaultTemplate(), data, Formatting{}) if !tt.wantErr(t, err) { return } diff --git a/internal/commitparser/commitparser.go b/internal/commitparser/commitparser.go index 484d733..023c6b4 100644 --- a/internal/commitparser/commitparser.go +++ b/internal/commitparser/commitparser.go @@ -15,3 +15,18 @@ type AnalyzedCommit struct { Scope *string BreakingChange bool } + +// ByType groups the Commits by the type field. Used by the Changelog. +func ByType(in []AnalyzedCommit) map[string][]AnalyzedCommit { + out := map[string][]AnalyzedCommit{} + + for _, commit := range in { + if out[commit.Type] == nil { + out[commit.Type] = make([]AnalyzedCommit, 0, 1) + } + + out[commit.Type] = append(out[commit.Type], commit) + } + + return out +} diff --git a/releaserpleaser.go b/releaserpleaser.go index a69ef9e..2b1754f 100644 --- a/releaserpleaser.go +++ b/releaserpleaser.go @@ -243,7 +243,9 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { return err } - changelogEntry, err := changelog.NewChangelogEntry(logger, analyzedCommits, nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) + changelogData := changelog.New(commitparser.ByType(analyzedCommits), nextVersion, rp.forge.ReleaseURL(nextVersion), releaseOverrides.Prefix, releaseOverrides.Suffix) + + changelogEntry, err := changelog.Entry(logger, changelog.DefaultTemplate(), changelogData, changelog.Formatting{}) if err != nil { return fmt.Errorf("failed to build changelog entry: %w", err) } @@ -289,9 +291,16 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { logger.InfoContext(ctx, "file content is already up-to-date in remote branch, skipping push") } + // We do not need the version title here. In the pull request the version is available from the title, and in the + // release on the Forge its usually in a heading somewhere above the text. + changelogEntryPullRequest, err := changelog.Entry(logger, changelog.DefaultTemplate(), changelogData, changelog.Formatting{HideVersionTitle: true}) + if err != nil { + return fmt.Errorf("failed to build pull request changelog entry: %w", err) + } + // Open/Update PR if pr == nil { - pr, err = releasepr.NewReleasePullRequest(rpBranch, rp.targetBranch, nextVersion, changelogEntry) + pr, err = releasepr.NewReleasePullRequest(rpBranch, rp.targetBranch, nextVersion, changelogEntryPullRequest) if err != nil { return err } @@ -308,7 +317,7 @@ func (rp *ReleaserPleaser) runReconcileReleasePR(ctx context.Context) error { if err != nil { return err } - err = pr.SetDescription(changelogEntry, overrides) + err = pr.SetDescription(changelogEntryPullRequest, overrides) if err != nil { return err }