@@ -18,13 +18,16 @@ package kepctl
18
18
19
19
import (
20
20
"bytes"
21
+ "context"
21
22
"fmt"
22
23
"io"
23
24
"io/ioutil"
24
25
"os"
25
26
"path/filepath"
26
27
"regexp"
28
+ "strings"
27
29
30
+ "github.com/google/go-github/v32/github"
28
31
"gopkg.in/yaml.v2"
29
32
"k8s.io/enhancements/pkg/kepval/keps"
30
33
)
@@ -139,23 +142,102 @@ func validateKEP(p *keps.Proposal) error {
139
142
return nil
140
143
}
141
144
145
+ func findLocalKEPs (repoPath string , sig string ) ([]string , error ) {
146
+ rootPath := filepath .Join (
147
+ repoPath ,
148
+ "keps" ,
149
+ sig )
150
+
151
+ keps := []string {}
152
+ err := filepath .Walk (rootPath , func (path string , info os.FileInfo , err error ) error {
153
+ if err != nil {
154
+ return err
155
+ }
156
+ if ! info .Mode ().IsRegular () {
157
+ return nil
158
+ }
159
+ if info .Name () == "kep.yaml" {
160
+ keps = append (keps , filepath .Base (filepath .Dir (path )))
161
+ return filepath .SkipDir
162
+ }
163
+ if filepath .Ext (path ) != ".md" {
164
+ return nil
165
+ }
166
+ if info .Name () == "README.md" {
167
+ return nil
168
+ }
169
+ keps = append (keps , info .Name ()[0 :len (info .Name ())- 3 ])
170
+ return nil
171
+ })
172
+
173
+ return keps , err
174
+ }
175
+
176
+ func (c * Client ) findPRKEPs (sig string ) (* keps.Proposal , error ) {
177
+ gh := github .NewClient (nil )
178
+ pulls , _ , err := gh .PullRequests .List (context .Background (), "kubernetes" , "enhancements" , & github.PullRequestListOptions {})
179
+ if err != nil {
180
+ return nil , err
181
+ }
182
+
183
+ for _ , pr := range pulls {
184
+ foundKind , foundSIG := false , false
185
+ sigLabel := strings .Replace (sig , "-" , "/" , 1 )
186
+ for _ , l := range pr .Labels {
187
+ if * l .Name == "kind/kep" {
188
+ foundKind = true
189
+ }
190
+ if * l .Name == sigLabel {
191
+ foundSIG = true
192
+ }
193
+ }
194
+ if ! foundKind || ! foundSIG {
195
+ continue
196
+ }
197
+ }
198
+
199
+ return nil , nil
200
+ }
201
+
142
202
func (c * Client ) readKEP (repoPath string , sig , name string ) (* keps.Proposal , error ) {
143
203
kepPath := filepath .Join (
144
204
repoPath ,
145
205
"keps" ,
146
206
sig ,
147
207
name ,
148
208
"kep.yaml" )
149
- b , err := ioutil .ReadFile (kepPath )
150
- if err != nil {
151
- return nil , fmt .Errorf ("unable to read KEP metadata: %s" , err )
209
+ _ , err := os .Stat (kepPath )
210
+ if err == nil {
211
+ b , err := ioutil .ReadFile (kepPath )
212
+ if err != nil {
213
+ return nil , fmt .Errorf ("unable to read KEP metadata: %s" , err )
214
+ }
215
+ var p keps.Proposal
216
+ err = yaml .Unmarshal (b , & p )
217
+ if err != nil {
218
+ return nil , fmt .Errorf ("unable to load KEP metadata: %s" , err )
219
+ }
220
+ return & p , nil
152
221
}
153
- var p keps.Proposal
154
- err = yaml .Unmarshal (b , & p )
222
+
223
+ // No kep.yaml, treat as old-style KEP
224
+ kepPath = filepath .Join (
225
+ repoPath ,
226
+ "keps" ,
227
+ sig ,
228
+ name ) + ".md"
229
+ b , err := ioutil .ReadFile (kepPath )
155
230
if err != nil {
156
231
return nil , fmt .Errorf ("unable to load KEP metadata: %s" , err )
157
232
}
158
- return & p , nil
233
+ r := bytes .NewReader (b )
234
+ parser := & keps.Parser {}
235
+
236
+ kep := parser .Parse (r )
237
+ if kep .Error != nil {
238
+ return nil , fmt .Errorf ("kep is invalid: %s" , kep .Error )
239
+ }
240
+ return kep , nil
159
241
}
160
242
161
243
func (c * Client ) writeKEP (kep * keps.Proposal , opts CommonArgs ) error {
@@ -181,3 +263,73 @@ func (c *Client) writeKEP(kep *keps.Proposal, opts CommonArgs) error {
181
263
fmt .Fprintf (c .Out , "writing KEP to %s\n " , newPath )
182
264
return ioutil .WriteFile (newPath , b , os .ModePerm )
183
265
}
266
+
267
+ type PrintConfig interface {
268
+ Title () string
269
+ Format () string
270
+ Value (* keps.Proposal ) string
271
+ }
272
+
273
+ type printConfig struct {
274
+ title string
275
+ format string
276
+ valueFunc func (* keps.Proposal ) string
277
+ }
278
+
279
+ func (p * printConfig ) Title () string { return p .title }
280
+ func (p * printConfig ) Format () string { return p .format }
281
+ func (p * printConfig ) Value (k * keps.Proposal ) string {
282
+ return p .valueFunc (k )
283
+ }
284
+
285
+ var dfltConfig = map [string ]printConfig {
286
+ "Authors" : {"Authors" , "%-30s" , func (k * keps.Proposal ) string { return strings .Join (k .Authors , ", " ) }},
287
+ "LastUpdated" : {"Updated" , "%-10s" , func (k * keps.Proposal ) string { return k .LastUpdated }},
288
+ "SIG" : {"SIG" , "%-12s" , func (k * keps.Proposal ) string {
289
+ if strings .HasPrefix (k .OwningSIG , "sig-" ) {
290
+ return k .OwningSIG [4 :]
291
+ } else {
292
+ return k .OwningSIG
293
+ }
294
+ }},
295
+ "Stage" : {"Stage" , "%-6s" , func (k * keps.Proposal ) string { return k .Stage }},
296
+ "Status" : {"Status" , "%-16s" , func (k * keps.Proposal ) string { return k .Status }},
297
+ "Title" : {"Title" , "%-30s" , func (k * keps.Proposal ) string { return k .Title }},
298
+ }
299
+
300
+ func DefaultPrintConfigs (names ... string ) []PrintConfig {
301
+ var configs []PrintConfig
302
+ for _ , n := range names {
303
+ // copy to allow it to be tweaked by the caller
304
+ c := dfltConfig [n ]
305
+ configs = append (configs , & c )
306
+ }
307
+ return configs
308
+ }
309
+
310
+ func (c * Client ) PrintTable (configs []PrintConfig , proposals []* keps.Proposal ) {
311
+ if len (configs ) == 0 {
312
+ return
313
+ }
314
+
315
+ fstr := configs [0 ].Format ()
316
+ for _ , c := range configs [1 :] {
317
+ fstr += " " + c .Format ()
318
+ }
319
+ fstr += "\n "
320
+
321
+ fmt .Fprintf (c .Out , fstr , mapPrintConfigs (configs , func (p PrintConfig ) string { return p .Title () })... )
322
+ fmt .Fprintf (c .Out , fstr , mapPrintConfigs (configs , func (p PrintConfig ) string { return strings .Repeat ("-" , len (p .Title ())) })... )
323
+
324
+ for _ , k := range proposals {
325
+ fmt .Fprintf (c .Out , fstr , mapPrintConfigs (configs , func (p PrintConfig ) string { return p .Value (k ) })... )
326
+ }
327
+ }
328
+
329
+ func mapPrintConfigs (configs []PrintConfig , mapFunc func (p PrintConfig ) string ) []interface {} {
330
+ var s []interface {}
331
+ for _ , c := range configs {
332
+ s = append (s , mapFunc (c ))
333
+ }
334
+ return s
335
+ }
0 commit comments