Skip to content

Commit eebb5fe

Browse files
authored
feat: add release notes in release pull request (#1905)
Fixes #1899
1 parent a8bfc16 commit eebb5fe

File tree

4 files changed

+104
-66
lines changed

4 files changed

+104
-66
lines changed

internal/librarian/command_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ func TestCommitAndPush(t *testing.T) {
11351135
commit: true,
11361136
},
11371137
{
1138-
name: "create a pull request",
1138+
name: "create a generate pull request",
11391139
setupMockRepo: func(t *testing.T) gitrepo.Repository {
11401140
remote := git.NewRemote(memory.NewStorage(), &gogitConfig.RemoteConfig{
11411141
Name: "origin",
@@ -1158,6 +1158,30 @@ func TestCommitAndPush(t *testing.T) {
11581158
prType: "generate",
11591159
push: true,
11601160
},
1161+
{
1162+
name: "create a release pull request",
1163+
setupMockRepo: func(t *testing.T) gitrepo.Repository {
1164+
remote := git.NewRemote(memory.NewStorage(), &gogitConfig.RemoteConfig{
1165+
Name: "origin",
1166+
URLs: []string{"https://github.com/googleapis/librarian.git"},
1167+
})
1168+
status := make(git.Status)
1169+
status["file.txt"] = &git.FileStatus{Worktree: git.Modified}
1170+
return &MockRepository{
1171+
Dir: t.TempDir(),
1172+
AddAllStatus: status,
1173+
RemotesValue: []*git.Remote{remote},
1174+
}
1175+
},
1176+
setupMockClient: func(t *testing.T) GitHubClient {
1177+
return &mockGitHubClient{
1178+
createdPR: &github.PullRequestMetadata{Number: 123, Repo: &github.Repository{Owner: "test-owner", Name: "test-repo"}},
1179+
}
1180+
},
1181+
state: &config.LibrarianState{},
1182+
prType: "release",
1183+
push: true,
1184+
},
11611185
{
11621186
name: "No GitHub Remote",
11631187
setupMockRepo: func(t *testing.T) gitrepo.Repository {
@@ -1360,6 +1384,7 @@ func TestCommitAndPush(t *testing.T) {
13601384
commitMessage: "",
13611385
prType: test.prType,
13621386
}
1387+
13631388
err := commitAndPush(context.Background(), commitInfo)
13641389

13651390
if test.wantErr {

internal/librarian/release_init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (r *initRunner) run(ctx context.Context) error {
110110
state: r.state,
111111
repo: r.repo,
112112
ghClient: r.ghClient,
113-
commitMessage: "",
113+
commitMessage: "chore: create a release",
114114
prType: release,
115115
}
116116
if err := commitAndPush(ctx, commitInfo); err != nil {

internal/librarian/release_notes.go

Lines changed: 71 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,29 @@ var (
6464

6565
releaseNotesTemplate = template.Must(template.New("releaseNotes").Funcs(template.FuncMap{
6666
"shortSHA": shortSHA,
67-
}).Parse(`## [{{.NewVersion}}]({{"https://github.com/"}}{{.Repo.Owner}}/{{.Repo.Name}}/compare/{{.PreviousTag}}...{{.NewTag}}) ({{.Date}})
68-
{{- range .Sections -}}
67+
}).Parse(`Librarian Version: {{.LibrarianVersion}}
68+
Language Image: {{.ImageVersion}}
69+
70+
{{- range .NoteSections -}}
71+
{{ $noteSection := . }}
72+
<details><summary>{{.LibraryID}}: {{.NewVersion}}</summary>
73+
74+
## [{{.NewVersion}}]({{"https://github.com/"}}{{.RepoOwner}}/{{.RepoName}}/compare/{{.PreviousTag}}...{{.NewTag}}) ({{.Date}})
75+
{{- range .CommitSections -}}
6976
{{- if .Commits -}}
70-
{{- if .Heading}}
77+
{{- if .Heading }}
7178
7279
### {{.Heading}}
73-
{{end}}
74-
80+
{{ end }}
7581
{{- range .Commits -}}
76-
* {{.Description}} ([{{shortSHA .SHA}}]({{"https://github.com/"}}{{$.Repo.Owner}}/{{$.Repo.Name}}/commit/{{.SHA}}))
77-
{{- end -}}
78-
{{- end -}}
79-
{{- end -}}`))
82+
* {{.Description}} ([{{shortSHA .SHA}}]({{"https://github.com/"}}{{$noteSection.RepoOwner}}/{{$noteSection.RepoName}}/commit/{{.SHA}}))
83+
{{- end }}
84+
{{- end }}
85+
{{- end }}
86+
</details>
87+
88+
{{ end }}
89+
`))
8090

8191
genBodyTemplate = template.Must(template.New("genBody").Funcs(template.FuncMap{
8292
"shortSHA": shortSHA,
@@ -121,6 +131,28 @@ type generationPRBody struct {
121131
FailedLibraries []string
122132
}
123133

134+
type releaseNote struct {
135+
LibrarianVersion string
136+
ImageVersion string
137+
NoteSections []*releaseNoteSection
138+
}
139+
140+
type releaseNoteSection struct {
141+
RepoOwner string
142+
RepoName string
143+
LibraryID string
144+
PreviousTag string
145+
NewTag string
146+
NewVersion string
147+
Date string
148+
CommitSections []*commitSection
149+
}
150+
151+
type commitSection struct {
152+
Heading string
153+
Commits []*conventionalcommits.ConventionalCommit
154+
}
155+
124156
// formatGenerationPRBody creates the body of a generation pull request.
125157
// Only consider libraries whose ID appears in idToCommits.
126158
func formatGenerationPRBody(repo gitrepo.Repository, state *config.LibrarianState, idToCommits map[string]string, failedLibraries []string) (string, error) {
@@ -207,46 +239,49 @@ func findLatestGenerationCommit(repo gitrepo.Repository, state *config.Librarian
207239

208240
// formatReleaseNotes generates the body for a release pull request.
209241
func formatReleaseNotes(repo gitrepo.Repository, state *config.LibrarianState) (string, error) {
210-
var body bytes.Buffer
211-
212242
librarianVersion := cli.Version()
213-
fmt.Fprintf(&body, "Librarian Version: %s\n", librarianVersion)
214-
fmt.Fprintf(&body, "Language Image: %s\n\n", state.Image)
215-
243+
var releaseSections []*releaseNoteSection
216244
for _, library := range state.Libraries {
217245
if !library.ReleaseTriggered {
218246
continue
219247
}
220248

221-
notes, newVersion, err := formatLibraryReleaseNotes(repo, library)
249+
section, err := formatLibraryReleaseNotes(repo, library)
222250
if err != nil {
223251
return "", fmt.Errorf("failed to format release notes for library %s: %w", library.ID, err)
224252
}
225-
fmt.Fprintf(&body, "<details><summary>%s: %s</summary>\n\n", library.ID, newVersion)
253+
releaseSections = append(releaseSections, section)
254+
}
226255

227-
body.WriteString(notes)
228-
body.WriteString("\n\n</details>")
256+
data := &releaseNote{
257+
LibrarianVersion: librarianVersion,
258+
ImageVersion: state.Image,
259+
NoteSections: releaseSections,
260+
}
229261

230-
body.WriteString("\n")
262+
var out bytes.Buffer
263+
if err := releaseNotesTemplate.Execute(&out, data); err != nil {
264+
return "", fmt.Errorf("error executing template: %w", err)
231265
}
232-
return body.String(), nil
266+
267+
return strings.TrimSpace(out.String()), nil
233268
}
234269

235270
// formatLibraryReleaseNotes generates release notes in Markdown format for a single library.
236271
// It returns the generated release notes and the new version string.
237-
func formatLibraryReleaseNotes(repo gitrepo.Repository, library *config.LibraryState) (string, string, error) {
272+
func formatLibraryReleaseNotes(repo gitrepo.Repository, library *config.LibraryState) (*releaseNoteSection, error) {
238273
ghRepo, err := github.FetchGitHubRepoFromRemote(repo)
239274
if err != nil {
240-
return "", "", fmt.Errorf("failed to fetch github repo from remote: %w", err)
275+
return nil, fmt.Errorf("failed to fetch github repo from remote: %w", err)
241276
}
242277
previousTag := formatTag(library, "")
243278
commits, err := GetConventionalCommitsSinceLastRelease(repo, library)
244279
if err != nil {
245-
return "", "", fmt.Errorf("failed to get conventional commits for library %s: %w", library.ID, err)
280+
return nil, fmt.Errorf("failed to get conventional commits for library %s: %w", library.ID, err)
246281
}
247282
newVersion, err := NextVersion(commits, library.Version, "")
248283
if err != nil {
249-
return "", "", fmt.Errorf("failed to get next version for library %s: %w", library.ID, err)
284+
return nil, fmt.Errorf("failed to get next version for library %s: %w", library.ID, err)
250285
}
251286
newTag := formatTag(library, newVersion)
252287

@@ -255,43 +290,29 @@ func formatLibraryReleaseNotes(repo gitrepo.Repository, library *config.LibraryS
255290
commitsByType[commit.Type] = append(commitsByType[commit.Type], commit)
256291
}
257292

258-
type releaseNoteSection struct {
259-
Heading string
260-
Commits []*conventionalcommits.ConventionalCommit
261-
}
262-
var sections []releaseNoteSection
293+
var sections []*commitSection
263294
// Group commits by type, according to commitTypeOrder, to be used in the release notes.
264295
for _, ct := range commitTypeOrder {
265296
displayName, headingOK := commitTypeToHeading[ct]
266297
typedCommits, commitsOK := commitsByType[ct]
267298
if headingOK && commitsOK {
268-
sections = append(sections, releaseNoteSection{
299+
sections = append(sections, &commitSection{
269300
Heading: displayName,
270301
Commits: typedCommits,
271302
})
272303
}
273304
}
274305

275-
var out bytes.Buffer
276-
data := struct {
277-
NewVersion string
278-
PreviousTag string
279-
NewTag string
280-
Repo *github.Repository
281-
Date string
282-
Sections []releaseNoteSection
283-
}{
284-
NewVersion: newVersion,
285-
PreviousTag: previousTag,
286-
NewTag: newTag,
287-
Repo: ghRepo,
288-
Date: time.Now().Format("2006-01-02"),
289-
Sections: sections,
290-
}
291-
if err := releaseNotesTemplate.Execute(&out, data); err != nil {
292-
// This should not happen, as the template is valid and the data is structured correctly.
293-
return "", "", fmt.Errorf("error executing template: %v", err)
306+
section := &releaseNoteSection{
307+
RepoOwner: ghRepo.Owner,
308+
RepoName: ghRepo.Name,
309+
LibraryID: library.ID,
310+
NewVersion: newVersion,
311+
PreviousTag: previousTag,
312+
NewTag: newTag,
313+
Date: time.Now().Format("2006-01-02"),
314+
CommitSections: sections,
294315
}
295316

296-
return strings.TrimSpace(out.String()), newVersion, nil
317+
return section, nil
297318
}

internal/librarian/release_notes_test.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,6 @@ func TestFormatReleaseNotes(t *testing.T) {
523523
},
524524
wantReleaseNote: fmt.Sprintf(`Librarian Version: %s
525525
Language Image: go:1.21
526-
527526
<details><summary>my-library: 1.1.0</summary>
528527
529528
## [1.1.0](https://github.com/owner/repo/compare/my-library-1.0.0...my-library-1.1.0) (%s)
@@ -533,9 +532,7 @@ Language Image: go:1.21
533532
534533
### Bug Fixes
535534
* a bug fix ([fedcba0](https://github.com/owner/repo/commit/fedcba0987654321000000000000000000000000))
536-
537-
</details>
538-
`,
535+
</details>`,
539536
librarianVersion, today),
540537
},
541538
{
@@ -572,24 +569,22 @@ Language Image: go:1.21
572569
},
573570
wantReleaseNote: fmt.Sprintf(`Librarian Version: %s
574571
Language Image: go:1.21
575-
576572
<details><summary>lib-a: 1.1.0</summary>
577573
578574
## [1.1.0](https://github.com/owner/repo/compare/lib-a-1.0.0...lib-a-1.1.0) (%s)
579575
580576
### Features
581577
* feature for a ([1234567](https://github.com/owner/repo/commit/1234567890abcdef000000000000000000000000))
582-
583578
</details>
579+
580+
584581
<details><summary>lib-b: 2.0.1</summary>
585582
586583
## [2.0.1](https://github.com/owner/repo/compare/lib-b-2.0.0...lib-b-2.0.1) (%s)
587584
588585
### Bug Fixes
589586
* fix for b ([fedcba0](https://github.com/owner/repo/commit/fedcba0987654321000000000000000000000000))
590-
591-
</details>
592-
`,
587+
</details>`,
593588
librarianVersion, today, today),
594589
},
595590
{
@@ -619,16 +614,13 @@ Language Image: go:1.21
619614
},
620615
wantReleaseNote: fmt.Sprintf(`Librarian Version: %s
621616
Language Image: go:1.21
622-
623617
<details><summary>my-library: 1.1.0</summary>
624618
625619
## [1.1.0](https://github.com/owner/repo/compare/my-library-1.0.0...my-library-1.1.0) (%s)
626620
627621
### Features
628622
* new feature ([1234567](https://github.com/owner/repo/commit/1234567890abcdef000000000000000000000000))
629-
630-
</details>
631-
`,
623+
</details>`,
632624
librarianVersion, today),
633625
},
634626
{
@@ -638,7 +630,7 @@ Language Image: go:1.21
638630
Libraries: []*config.LibraryState{},
639631
},
640632
repo: &MockRepository{},
641-
wantReleaseNote: fmt.Sprintf("Librarian Version: %s\nLanguage Image: go:1.21\n\n", librarianVersion),
633+
wantReleaseNote: fmt.Sprintf("Librarian Version: %s\nLanguage Image: go:1.21", librarianVersion),
642634
},
643635
{
644636
name: "error getting commits",

0 commit comments

Comments
 (0)