@@ -22,11 +22,14 @@ package main
22
22
23
23
import (
24
24
"bytes"
25
+ "encoding/json"
26
+ "errors"
25
27
"flag"
26
28
"fmt"
27
29
"os"
28
30
"os/exec"
29
31
"regexp"
32
+ "sort"
30
33
"strings"
31
34
"time"
32
35
)
@@ -104,7 +107,70 @@ func increaseDateByOneDay(date string) (string, error) {
104
107
return datetime .Format (layout ), nil
105
108
}
106
109
110
+ const (
111
+ missingAreaLabelPrefix = "MISSING_AREA"
112
+ areaLabelPrefix = "area/"
113
+ multipleAreaLabelsPrefix = "MULTIPLE_AREAS["
114
+ )
115
+
116
+ type githubPullRequest struct {
117
+ Labels []githubLabel `json:"labels"`
118
+ }
119
+
120
+ type githubLabel struct {
121
+ Name string `json:"name"`
122
+ }
123
+
124
+ func getAreaLabel (merge string ) (string , error ) {
125
+ // Get pr id from merge commit
126
+ prID := strings .Replace (strings .TrimSpace (strings .Split (merge , " " )[3 ]), "#" , "" , - 1 )
127
+
128
+ cmd := exec .Command ("gh" , "api" , "repos/kubernetes-sigs/cluster-api/pulls/" + prID ) //nolint:gosec
129
+
130
+ out , err := cmd .CombinedOutput ()
131
+ if err != nil {
132
+ return "" , err
133
+ }
134
+
135
+ pr := & githubPullRequest {}
136
+ if err := json .Unmarshal (out , pr ); err != nil {
137
+ return "" , err
138
+ }
139
+
140
+ var areaLabels []string
141
+ for _ , label := range pr .Labels {
142
+ if area , ok := trimAreaLabel (label .Name ); ok {
143
+ areaLabels = append (areaLabels , area )
144
+ }
145
+ }
146
+
147
+ switch len (areaLabels ) {
148
+ case 0 :
149
+ return missingAreaLabelPrefix , nil
150
+ case 1 :
151
+ return areaLabels [0 ], nil
152
+ default :
153
+ return multipleAreaLabelsPrefix + strings .Join (areaLabels , "|" ) + "]" , nil
154
+ }
155
+ }
156
+
157
+ // trimAreaLabel removes the "area/" prefix from area labels and returns it.
158
+ // If the label is an area label, the second return value is true, otherwise false.
159
+ func trimAreaLabel (label string ) (string , bool ) {
160
+ trimmed := strings .TrimPrefix (label , areaLabelPrefix )
161
+ if len (trimmed ) < len (label ) {
162
+ return trimmed , true
163
+ }
164
+
165
+ return label , false
166
+ }
167
+
107
168
func run () int {
169
+ if err := ensureInstalledDependencies (); err != nil {
170
+ fmt .Println (err )
171
+ return 1
172
+ }
173
+
108
174
var commitRange string
109
175
var cmd * exec.Cmd
110
176
@@ -160,6 +226,11 @@ func run() int {
160
226
for _ , c := range commits {
161
227
body := trimTitle (c .body )
162
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
+ }
163
234
switch {
164
235
case strings .HasPrefix (body , ":sparkles:" ), strings .HasPrefix (body , "✨" ):
165
236
key = features
@@ -192,7 +263,7 @@ func run() int {
192
263
if body == "" {
193
264
continue
194
265
}
195
- body = fmt .Sprintf ("- %s" , body )
266
+ body = fmt .Sprintf ("- %s: %s" , prefix , body )
196
267
_ , _ = fmt .Sscanf (c .merge , "Merge pull request %s from %s" , & prNumber , & fork )
197
268
if key == documentation {
198
269
merges [key ] = append (merges [key ], prNumber )
@@ -226,6 +297,7 @@ func run() int {
226
297
)
227
298
default :
228
299
fmt .Println ("## " + key )
300
+ sort .Strings (mergeslice )
229
301
for _ , merge := range mergeslice {
230
302
fmt .Println (merge )
231
303
}
@@ -257,3 +329,20 @@ func formatMerge(line, prNumber string) string {
257
329
}
258
330
return fmt .Sprintf ("%s (%s)" , line , prNumber )
259
331
}
332
+
333
+ func ensureInstalledDependencies () error {
334
+ if ! commandExists ("git" ) {
335
+ return errors .New ("git not available. Git is required to be present in the PATH" )
336
+ }
337
+
338
+ if ! commandExists ("gh" ) {
339
+ return errors .New ("gh GitHub CLI not available. GitHub CLI is required to be present in the PATH. Refer to https://cli.github.com/ for installation" )
340
+ }
341
+
342
+ return nil
343
+ }
344
+
345
+ func commandExists (cmd string ) bool {
346
+ _ , err := exec .LookPath (cmd )
347
+ return err == nil
348
+ }
0 commit comments