From 9c17553ad90549c04c2a58b0422ab2d66137780e Mon Sep 17 00:00:00 2001 From: Thomas Vilte Date: Thu, 30 Jul 2026 17:05:43 -0300 Subject: [PATCH] feat(release): include merged PRs and contributors in changelog --- internal/services/release_changelog.go | 24 ++++++++++++++ .../release_service_improvements_test.go | 32 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/internal/services/release_changelog.go b/internal/services/release_changelog.go index 9d4d971..196f6ad 100644 --- a/internal/services/release_changelog.go +++ b/internal/services/release_changelog.go @@ -498,6 +498,30 @@ func (s *ReleaseService) buildChangelogFromNotes(ctx context.Context, release *m sb.WriteString("\n") } + if len(release.MergedPRs) > 0 { + sb.WriteString("### Pull Requests\n\n") + for _, pr := range release.MergedPRs { + if pr.URL != "" { + sb.WriteString(fmt.Sprintf("- [#%d](%s) %s (by @%s)\n", pr.Number, pr.URL, pr.Title, pr.Author)) + } else { + sb.WriteString(fmt.Sprintf("- #%d %s (by @%s)\n", pr.Number, pr.Title, pr.Author)) + } + } + sb.WriteString("\n") + } + + if len(release.Contributors) > 0 { + sb.WriteString("### Contributors\n\n") + sb.WriteString("Thanks to ") + for i, contributor := range release.Contributors { + sb.WriteString(fmt.Sprintf("@%s", contributor)) + if i < len(release.Contributors)-1 { + sb.WriteString(", ") + } + } + sb.WriteString("\n\n") + } + return sb.String() } diff --git a/internal/services/release_service_improvements_test.go b/internal/services/release_service_improvements_test.go index b845a2d..1f6788e 100644 --- a/internal/services/release_service_improvements_test.go +++ b/internal/services/release_service_improvements_test.go @@ -151,6 +151,38 @@ func TestBuildChangelogFromNotes_WithBreakingChanges(t *testing.T) { assert.Contains(t, result, "- Changed configuration format") } +// TestBuildChangelogFromNotes_WithMergedPRsAndContributors tests that the +// checked-in CHANGELOG.md lists real merged PRs and contributors, not just +// the fragile per-commit "### References" match. +func TestBuildChangelogFromNotes_WithMergedPRsAndContributors(t *testing.T) { + mockGit := &mockGitService{owner: "test", repo: "repo", provider: "github"} + service := &ReleaseService{git: mockGit} + ctx := context.Background() + + release := &models.Release{ + Version: "v2.0.0", + PreviousVersion: "v1.7.0", + MergedPRs: []models.PullRequest{ + {Number: 90, Title: "Add feature X", Author: "thomas-vilte", URL: "https://github.com/test/repo/pull/90"}, + {Number: 91, Title: "Fix bug Y", Author: "dependabot[bot]", URL: "https://github.com/test/repo/pull/91"}, + }, + Contributors: []string{"thomas-vilte", "dependabot[bot]"}, + } + + notes := &models.ReleaseNotes{ + Summary: "Minor release", + Highlights: []string{"New feature"}, + } + + result := service.buildChangelogFromNotes(ctx, release, notes) + + assert.Contains(t, result, "### Pull Requests") + assert.Contains(t, result, "[#90](https://github.com/test/repo/pull/90) Add feature X (by @thomas-vilte)") + assert.Contains(t, result, "[#91](https://github.com/test/repo/pull/91) Fix bug Y (by @dependabot[bot])") + assert.Contains(t, result, "### Contributors") + assert.Contains(t, result, "Thanks to @thomas-vilte, @dependabot[bot]") +} + func TestBuildChangelogFromNotes_WithReferences(t *testing.T) { mockGit := &mockGitService{owner: "test", repo: "repo", provider: "github"} service := &ReleaseService{git: mockGit}