Skip to content

Commit 196072b

Browse files
committed
Refactor kepval for upcoming PRR approval validator
1 parent 6414967 commit 196072b

File tree

3 files changed

+277
-146
lines changed

3 files changed

+277
-146
lines changed

pkg/kepval/keps/validations/yaml.go

Lines changed: 20 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -17,142 +17,13 @@ limitations under the License.
1717
package validations
1818

1919
import (
20-
"bufio"
21-
"fmt"
22-
"io/ioutil"
23-
"net/http"
24-
"os"
2520
"regexp"
2621
"sort"
2722
"strings"
2823

29-
"sigs.k8s.io/yaml"
24+
"k8s.io/enhancements/pkg/kepval/util"
3025
)
3126

32-
type KeyMustBeSpecified struct {
33-
key interface{}
34-
}
35-
36-
func (k *KeyMustBeSpecified) Error() string {
37-
return fmt.Sprintf("missing key %[1]v", k.key)
38-
}
39-
40-
type KeyMustBeString struct {
41-
key interface{}
42-
}
43-
44-
func (k *KeyMustBeString) Error() string {
45-
return fmt.Sprintf("key %[1]v must be a string but it is a %[1]T", k.key)
46-
}
47-
48-
type ValueMustBeString struct {
49-
key string
50-
value interface{}
51-
}
52-
53-
func (v *ValueMustBeString) Error() string {
54-
return fmt.Sprintf("%q must be a string but it is a %T: %v", v.key, v.value, v.value)
55-
}
56-
57-
type ValueMustBeOneOf struct {
58-
key string
59-
value string
60-
values []string
61-
}
62-
63-
func (v *ValueMustBeOneOf) Error() string {
64-
return fmt.Sprintf("%q must be one of (%s) but it is a %T: %v", v.key, strings.Join(v.values, ","), v.value, v.value)
65-
}
66-
67-
type ValueMustBeListOfStrings struct {
68-
key string
69-
value interface{}
70-
}
71-
72-
func (v *ValueMustBeListOfStrings) Error() string {
73-
return fmt.Sprintf("%q must be a list of strings: %v", v.key, v.value)
74-
}
75-
76-
type MustHaveOneValue struct {
77-
key string
78-
}
79-
80-
func (m *MustHaveOneValue) Error() string {
81-
return fmt.Sprintf("%q must have a value", m.key)
82-
}
83-
84-
type MustHaveAtLeastOneValue struct {
85-
key string
86-
}
87-
88-
func (m *MustHaveAtLeastOneValue) Error() string {
89-
return fmt.Sprintf("%q must have at least one value", m.key)
90-
}
91-
92-
var (
93-
listGroups []string
94-
prrApprovers []string
95-
)
96-
97-
func Sigs() []string {
98-
return listGroups
99-
}
100-
101-
func init() {
102-
resp, err := http.Get("https://raw.githubusercontent.com/kubernetes/community/master/sigs.yaml")
103-
if err != nil {
104-
fmt.Fprintf(os.Stderr, "unable to fetch list of sigs: %v\n", err)
105-
os.Exit(1)
106-
}
107-
defer resp.Body.Close()
108-
if resp.StatusCode != http.StatusOK {
109-
fmt.Fprintf(os.Stderr, "invalid status code when fetching list of sigs: %d\n", resp.StatusCode)
110-
os.Exit(1)
111-
}
112-
re := regexp.MustCompile(`- dir: (.*)$`)
113-
114-
scanner := bufio.NewScanner(resp.Body)
115-
for scanner.Scan() {
116-
match := re.FindStringSubmatch(scanner.Text())
117-
if len(match) > 0 {
118-
listGroups = append(listGroups, match[1])
119-
}
120-
}
121-
if err := scanner.Err(); err != nil {
122-
fmt.Fprintf(os.Stderr, "unable to scan list of sigs: %v\n", err)
123-
os.Exit(1)
124-
}
125-
sort.Strings(listGroups)
126-
127-
resp, err = http.Get("https://raw.githubusercontent.com/kubernetes/enhancements/master/OWNERS_ALIASES")
128-
if err != nil {
129-
fmt.Fprintf(os.Stderr, "unable to fetch list of aliases: %v\n", err)
130-
os.Exit(1)
131-
}
132-
defer resp.Body.Close()
133-
if resp.StatusCode != http.StatusOK {
134-
fmt.Fprintf(os.Stderr, "invalid status code when fetching list of aliases: %d\n", resp.StatusCode)
135-
os.Exit(1)
136-
}
137-
138-
body, err := ioutil.ReadAll(resp.Body)
139-
if err != nil {
140-
fmt.Fprintf(os.Stderr, "unable to read aliases content: %v\n", err)
141-
os.Exit(1)
142-
}
143-
config := &struct {
144-
Data map[string][]string `json:"aliases,omitempty"`
145-
}{}
146-
if err := yaml.Unmarshal(body, config); err != nil {
147-
fmt.Fprintf(os.Stderr, "unable to read parse aliases content: %v\n", err)
148-
os.Exit(1)
149-
}
150-
for _, approver := range config.Data["prod-readiness-approvers"] {
151-
prrApprovers = append(prrApprovers, approver)
152-
}
153-
sort.Strings(listGroups)
154-
}
155-
15627
var (
15728
mandatoryKeys = []string{"title", "owning-sig"}
15829
statuses = []string{"provisional", "implementable", "implemented", "deferred", "rejected", "withdrawn", "replaced"}
@@ -164,15 +35,18 @@ var (
16435
func ValidateStructure(parsed map[interface{}]interface{}) error {
16536
for _, key := range mandatoryKeys {
16637
if _, found := parsed[key]; !found {
167-
return &KeyMustBeSpecified{key}
38+
return util.NewKeyMustBeSpecified(key)
16839
}
16940
}
17041

42+
listGroups := util.Groups()
43+
prrApprovers := util.PRRApprovers()
44+
17145
for key, value := range parsed {
17246
// First off the key has to be a string. fact.
17347
k, ok := key.(string)
17448
if !ok {
175-
return &KeyMustBeString{k}
49+
return util.NewKeyMustBeString(k)
17650
}
17751
empty := value == nil
17852

@@ -181,30 +55,30 @@ func ValidateStructure(parsed map[interface{}]interface{}) error {
18155
case "status":
18256
switch v := value.(type) {
18357
case []interface{}:
184-
return &ValueMustBeString{k, v}
58+
return util.NewValueMustBeString(k, v)
18559
}
18660
v, _ := value.(string)
18761
if !reStatus.Match([]byte(v)) {
188-
return &ValueMustBeOneOf{k, v, statuses}
62+
return util.NewValueMustBeOneOf(k, v, statuses)
18963
}
19064
case "stage":
19165
switch v := value.(type) {
19266
case []interface{}:
193-
return &ValueMustBeString{k, v}
67+
return util.NewValueMustBeString(k, v)
19468
}
19569
v, _ := value.(string)
19670
if !reStages.Match([]byte(v)) {
197-
return &ValueMustBeOneOf{k, v, stages}
71+
return util.NewValueMustBeOneOf(k, v, stages)
19872
}
19973
case "owning-sig":
20074
switch v := value.(type) {
20175
case []interface{}:
202-
return &ValueMustBeString{k, v}
76+
return util.NewValueMustBeString(k, v)
20377
}
20478
v, _ := value.(string)
20579
index := sort.SearchStrings(listGroups, v)
20680
if index >= len(listGroups) || listGroups[index] != v {
207-
return &ValueMustBeOneOf{k, v, listGroups}
81+
return util.NewValueMustBeOneOf(k, v, listGroups)
20882
}
20983
// optional strings
21084
case "editor":
@@ -215,14 +89,14 @@ func ValidateStructure(parsed map[interface{}]interface{}) error {
21589
case "title", "creation-date", "last-updated":
21690
switch v := value.(type) {
21791
case []interface{}:
218-
return &ValueMustBeString{k, v}
92+
return util.NewValueMustBeString(k, v)
21993
}
22094
v, ok := value.(string)
22195
if ok && v == "" {
222-
return &MustHaveOneValue{k}
96+
return util.NewMustHaveOneValue(k)
22397
}
22498
if !ok {
225-
return &ValueMustBeString{k, v}
99+
return util.NewValueMustBeString(k, v)
226100
}
227101
// These are optional lists, so skip if there is no value
228102
case "participating-sigs", "replaces", "superseded-by", "see-also":
@@ -243,19 +117,19 @@ func ValidateStructure(parsed map[interface{}]interface{}) error {
243117
switch values := value.(type) {
244118
case []interface{}:
245119
if len(values) == 0 {
246-
return &MustHaveAtLeastOneValue{k}
120+
return util.NewMustHaveAtLeastOneValue(k)
247121
}
248122
if strings.ToLower(k) == "participating-sigs" {
249123
for _, value := range values {
250124
v := value.(string)
251125
index := sort.SearchStrings(listGroups, v)
252126
if index >= len(listGroups) || listGroups[index] != v {
253-
return &ValueMustBeOneOf{k, v, listGroups}
127+
return util.NewValueMustBeOneOf(k, v, listGroups)
254128
}
255129
}
256130
}
257131
case interface{}:
258-
return &ValueMustBeListOfStrings{k, values}
132+
return util.NewValueMustBeListOfStrings(k, values)
259133
}
260134
case "prr-approvers":
261135
switch values := value.(type) {
@@ -271,11 +145,11 @@ func ValidateStructure(parsed map[interface{}]interface{}) error {
271145

272146
index := sort.SearchStrings(prrApprovers, v)
273147
if index >= len(prrApprovers) || prrApprovers[index] != v {
274-
return &ValueMustBeOneOf{k, v, prrApprovers}
148+
return util.NewValueMustBeOneOf(k, v, prrApprovers)
275149
}
276150
}
277151
case interface{}:
278-
return &ValueMustBeListOfStrings{k, values}
152+
return util.NewValueMustBeListOfStrings(k, values)
279153
}
280154
}
281155
}

0 commit comments

Comments
 (0)