@@ -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.
126158func 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.
209241func 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}
0 commit comments