@@ -31,6 +31,7 @@ import (
3131 "regexp"
3232 "sort"
3333 "strings"
34+ "sync"
3435 "time"
3536)
3637
6465
6566 fromTag = flag .String ("from" , "" , "The tag or commit to start from." )
6667
67- since = flag .String ("since" , "" , "Include commits starting from and including this date. Accepts format: YYYY-MM-DD" )
68- until = flag .String ("until" , "" , "Include commits up to and including this date. Accepts format: YYYY-MM-DD" )
68+ since = flag .String ("since" , "" , "Include commits starting from and including this date. Accepts format: YYYY-MM-DD" )
69+ until = flag .String ("until" , "" , "Include commits up to and including this date. Accepts format: YYYY-MM-DD" )
70+ numWorkers = flag .Int ("workers" , 10 , "Number of concurrent routines to process PR entries. If running into GitHub rate limiting, use 1." )
6971
7072 tagRegex = regexp .MustCompile (`^\[release-[\w-\.]*\]` )
7173)
@@ -129,7 +131,7 @@ func getAreaLabel(merge string) (string, error) {
129131
130132 out , err := cmd .CombinedOutput ()
131133 if err != nil {
132- return "" , err
134+ return "" , fmt . Errorf ( "%s: %v" , string ( out ), err )
133135 }
134136
135137 pr := & githubPullRequest {}
@@ -223,53 +225,49 @@ func run() int {
223225 }
224226 }
225227
226- for _ , c := range commits {
227- body := trimTitle (c .body )
228- var key , prNumber , fork string
229- prefix , err := getAreaLabel (c .merge )
230- if err != nil {
231- fmt .Println (err )
232- os .Exit (1 )
233- }
234- switch {
235- case strings .HasPrefix (body , ":sparkles:" ), strings .HasPrefix (body , "✨" ):
236- key = features
237- body = strings .TrimPrefix (body , ":sparkles:" )
238- body = strings .TrimPrefix (body , "✨" )
239- case strings .HasPrefix (body , ":bug:" ), strings .HasPrefix (body , "🐛" ):
240- key = bugs
241- body = strings .TrimPrefix (body , ":bug:" )
242- body = strings .TrimPrefix (body , "🐛" )
243- case strings .HasPrefix (body , ":book:" ), strings .HasPrefix (body , "📖" ):
244- key = documentation
245- body = strings .TrimPrefix (body , ":book:" )
246- body = strings .TrimPrefix (body , "📖" )
247- if strings .Contains (body , "CAEP" ) || strings .Contains (body , "proposal" ) {
248- key = proposals
228+ results := make (chan releaseNoteEntryResult )
229+ commitCh := make (chan * commit )
230+ var wg sync.WaitGroup
231+
232+ wg .Add (* numWorkers )
233+ for i := 0 ; i < * numWorkers ; i ++ {
234+ go func () {
235+ for commit := range commitCh {
236+ processed := releaseNoteEntryResult {}
237+ processed .prEntry , processed .err = generateReleaseNoteEntry (commit )
238+ results <- processed
249239 }
250- case strings .HasPrefix (body , ":seedling:" ), strings .HasPrefix (body , "🌱" ):
251- key = other
252- body = strings .TrimPrefix (body , ":seedling:" )
253- body = strings .TrimPrefix (body , "🌱" )
254- case strings .HasPrefix (body , ":warning:" ), strings .HasPrefix (body , "⚠️" ):
255- key = warning
256- body = strings .TrimPrefix (body , ":warning:" )
257- body = strings .TrimPrefix (body , "⚠️" )
258- default :
259- key = unknown
240+ wg .Done ()
241+ }()
242+ }
243+
244+ go func () {
245+ for _ , c := range commits {
246+ commitCh <- c
247+ }
248+ close (commitCh )
249+ }()
250+
251+ go func () {
252+ wg .Wait ()
253+ close (results )
254+ }()
255+
256+ for result := range results {
257+ if result .err != nil {
258+ fmt .Println (result .err )
259+ os .Exit (0 )
260260 }
261261
262- body = strings .TrimSpace (body )
263- if body == "" {
262+ if result .prEntry .title == "" {
264263 continue
265264 }
266- body = fmt . Sprintf ( "- %s: %s" , prefix , body )
267- _ , _ = fmt . Sscanf ( c . merge , "Merge pull request %s from %s" , & prNumber , & fork )
268- if key == documentation {
269- merges [ key ] = append ( merges [ key ], prNumber )
270- continue
265+
266+ if result . prEntry . section == documentation {
267+ merges [ result . prEntry . section ] = append ( merges [ result . prEntry . section ], result . prEntry . prNumber )
268+ } else {
269+ merges [ result . prEntry . section ] = append ( merges [ result . prEntry . section ], result . prEntry . title )
271270 }
272- merges [key ] = append (merges [key ], formatMerge (body , prNumber ))
273271 }
274272
275273 // TODO Turn this into a link (requires knowing the project name + organization)
@@ -346,3 +344,66 @@ func commandExists(cmd string) bool {
346344 _ , err := exec .LookPath (cmd )
347345 return err == nil
348346}
347+
348+ // releaseNoteEntryResult is the result of processing a PR to create a release note item.
349+ // Used to aggregate the line item and error when processing concurrently.
350+ type releaseNoteEntryResult struct {
351+ prEntry * releaseNoteEntry
352+ err error
353+ }
354+
355+ // releaseNoteEntry represents a line item in the release notes.
356+ type releaseNoteEntry struct {
357+ title string
358+ section string
359+ prNumber string
360+ }
361+
362+ // generateReleaseNoteEntry processes a commit into a PR line item for the release notes.
363+ func generateReleaseNoteEntry (c * commit ) (* releaseNoteEntry , error ) {
364+ entry := & releaseNoteEntry {}
365+ entry .title = trimTitle (c .body )
366+ var fork string
367+ prefix , err := getAreaLabel (c .merge )
368+ if err != nil {
369+ return nil , err
370+ }
371+
372+ switch {
373+ case strings .HasPrefix (entry .title , ":sparkles:" ), strings .HasPrefix (entry .title , "✨" ):
374+ entry .section = features
375+ entry .title = strings .TrimPrefix (entry .title , ":sparkles:" )
376+ entry .title = strings .TrimPrefix (entry .title , "✨" )
377+ case strings .HasPrefix (entry .title , ":bug:" ), strings .HasPrefix (entry .title , "🐛" ):
378+ entry .section = bugs
379+ entry .title = strings .TrimPrefix (entry .title , ":bug:" )
380+ entry .title = strings .TrimPrefix (entry .title , "🐛" )
381+ case strings .HasPrefix (entry .title , ":book:" ), strings .HasPrefix (entry .title , "📖" ):
382+ entry .section = documentation
383+ entry .title = strings .TrimPrefix (entry .title , ":book:" )
384+ entry .title = strings .TrimPrefix (entry .title , "📖" )
385+ if strings .Contains (entry .title , "CAEP" ) || strings .Contains (entry .title , "proposal" ) {
386+ entry .section = proposals
387+ }
388+ case strings .HasPrefix (entry .title , ":seedling:" ), strings .HasPrefix (entry .title , "🌱" ):
389+ entry .section = other
390+ entry .title = strings .TrimPrefix (entry .title , ":seedling:" )
391+ entry .title = strings .TrimPrefix (entry .title , "🌱" )
392+ case strings .HasPrefix (entry .title , ":warning:" ), strings .HasPrefix (entry .title , "⚠️" ):
393+ entry .section = warning
394+ entry .title = strings .TrimPrefix (entry .title , ":warning:" )
395+ entry .title = strings .TrimPrefix (entry .title , "⚠️" )
396+ default :
397+ entry .section = unknown
398+ }
399+
400+ entry .title = strings .TrimSpace (entry .title )
401+ if entry .title == "" {
402+ return entry , nil
403+ }
404+ entry .title = fmt .Sprintf ("- %s: %s" , prefix , entry .title )
405+ _ , _ = fmt .Sscanf (c .merge , "Merge pull request %s from %s" , & entry .prNumber , & fork )
406+ entry .title = formatMerge (entry .title , entry .prNumber )
407+
408+ return entry , nil
409+ }
0 commit comments