@@ -12,11 +12,17 @@ import (
1212
1313var version = "dev"
1414
15- type ChangelogEntry struct {
16- Version string `json:"version "`
15+ type Section struct {
16+ Name string `json:"name "`
1717 Changes []string `json:"changes"`
1818}
1919
20+ type ChangelogEntry struct {
21+ Version string `json:"version"`
22+ Sections []Section `json:"sections,omitempty"`
23+ Changes []string `json:"changes,omitempty"`
24+ }
25+
2026type Source struct {
2127 Name string
2228 DisplayName string
@@ -233,31 +239,65 @@ func fetchGitHubReleases(owner, repo string) ([]ChangelogEntry, error) {
233239 ver = strings .TrimPrefix (ver , "v" )
234240 ver = strings .TrimPrefix (ver , "rust-v" )
235241
236- changes := parseReleaseBody (rel .Body )
242+ sections , ungroupedChanges := parseReleaseBody (rel .Body )
237243
238244 entries = append (entries , ChangelogEntry {
239- Version : ver ,
240- Changes : changes ,
245+ Version : ver ,
246+ Sections : sections ,
247+ Changes : ungroupedChanges ,
241248 })
242249 }
243250
244251 return entries , nil
245252}
246253
247- func parseReleaseBody (body string ) []string {
248- var changes []string
254+ func parseReleaseBody (body string ) ([]Section , []string ) {
255+ var sections []Section
256+ var ungroupedChanges []string
257+
258+ headerRegex := regexp .MustCompile (`^#{1,3}\s+(.+)$` )
249259 lines := strings .Split (body , "\n " )
260+
261+ var currentSection * Section
262+
250263 for _ , line := range lines {
251264 trimmed := strings .TrimSpace (line )
265+
266+ // Check for section header (# ## or ###)
267+ if match := headerRegex .FindStringSubmatch (trimmed ); match != nil {
268+ headerName := strings .TrimSpace (match [1 ])
269+ // Skip "What's Changed" as it's just a wrapper, not a real category
270+ if headerName == "What's Changed" {
271+ continue
272+ }
273+ // Save previous section if exists
274+ if currentSection != nil && len (currentSection .Changes ) > 0 {
275+ sections = append (sections , * currentSection )
276+ }
277+ currentSection = & Section {Name : headerName }
278+ continue
279+ }
280+
281+ // Check for list item
252282 if strings .HasPrefix (trimmed , "- " ) || strings .HasPrefix (trimmed , "* " ) {
253283 change := strings .TrimPrefix (trimmed , "- " )
254284 change = strings .TrimPrefix (change , "* " )
255285 if change != "" && ! strings .HasPrefix (change , "@" ) {
256- changes = append (changes , change )
286+ if currentSection != nil {
287+ currentSection .Changes = append (currentSection .Changes , change )
288+ } else {
289+ ungroupedChanges = append (ungroupedChanges , change )
290+ }
257291 }
258292 }
259293 }
260- return changes
294+
295+ // Don't forget the last section
296+ if currentSection != nil && len (currentSection .Changes ) > 0 {
297+ sections = append (sections , * currentSection )
298+ }
299+
300+ return sections , ungroupedChanges
261301}
262302
263303func parseMarkdownChangelog (content , versionPattern string ) []ChangelogEntry {
@@ -332,6 +372,17 @@ func outputJSON(entry *ChangelogEntry) {
332372
333373func outputMarkdown (entry * ChangelogEntry ) {
334374 fmt .Printf ("## %s\n \n " , entry .Version )
375+
376+ // Output sectioned changes
377+ for _ , section := range entry .Sections {
378+ fmt .Printf ("### %s\n \n " , section .Name )
379+ for _ , change := range section .Changes {
380+ fmt .Printf ("- %s\n " , change )
381+ }
382+ fmt .Println ()
383+ }
384+
385+ // Output ungrouped changes
335386 for _ , change := range entry .Changes {
336387 fmt .Printf ("- %s\n " , change )
337388 }
@@ -340,6 +391,19 @@ func outputMarkdown(entry *ChangelogEntry) {
340391func outputPlainText (displayName string , entry * ChangelogEntry ) {
341392 fmt .Printf ("%s %s\n " , displayName , entry .Version )
342393 fmt .Println (strings .Repeat ("-" , 40 ))
394+
395+ // Output sectioned changes
396+ for _ , section := range entry .Sections {
397+ fmt .Printf ("\n [%s]\n " , section .Name )
398+ for _ , change := range section .Changes {
399+ fmt .Printf (" * %s\n " , change )
400+ }
401+ }
402+
403+ // Output ungrouped changes
404+ if len (entry .Sections ) > 0 && len (entry .Changes ) > 0 {
405+ fmt .Println ()
406+ }
343407 for _ , change := range entry .Changes {
344408 fmt .Printf (" * %s\n " , change )
345409 }
0 commit comments