Skip to content

Commit 685eecf

Browse files
committed
api: Validate KEPs by field
Signed-off-by: Stephen Augustus <[email protected]>
1 parent 8ffe0d2 commit 685eecf

File tree

3 files changed

+115
-31
lines changed

3 files changed

+115
-31
lines changed

api/approval.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (prr *PRRApproval) ApproverForStage(stage string) string {
6666

6767
// TODO(api): Can we refactor the proposal `Milestone` to retrieve this?
6868
type PRRMilestone struct {
69-
Approver string `json:"approver" yaml:"approver" validate:"required"`
69+
Approver string `json:"approver" yaml:"approver"`
7070
}
7171

7272
type PRRHandler Parser

api/proposal.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ limitations under the License.
1616

1717
package api
1818

19+
import (
20+
"bufio"
21+
"bytes"
22+
"crypto/md5"
23+
"fmt"
24+
"io"
25+
"strings"
26+
27+
"github.com/go-playground/validator/v10"
28+
"github.com/pkg/errors"
29+
"gopkg.in/yaml.v3"
30+
)
31+
1932
type Proposals []*Proposal
2033

2134
func (p *Proposals) AddProposal(proposal *Proposal) {
@@ -56,6 +69,65 @@ type Proposal struct {
5669
Contents string `json:"markdown" yaml:"-"`
5770
}
5871

72+
func (p *Proposal) Validate() error {
73+
v := validator.New()
74+
if err := v.Struct(p); err != nil {
75+
return errors.Wrap(err, "running validation")
76+
}
77+
78+
return nil
79+
}
80+
81+
type KEPHandler Parser
82+
83+
// TODO(api): Make this a generic parser for all `Document` types
84+
func (k *KEPHandler) Parse(in io.Reader) (*Proposal, error) {
85+
scanner := bufio.NewScanner(in)
86+
count := 0
87+
metadata := []byte{}
88+
var body bytes.Buffer
89+
for scanner.Scan() {
90+
line := scanner.Text() + "\n"
91+
if strings.Contains(line, "---") {
92+
count++
93+
continue
94+
}
95+
if count == 1 {
96+
metadata = append(metadata, []byte(line)...)
97+
} else {
98+
body.WriteString(line)
99+
}
100+
}
101+
102+
kep := &Proposal{
103+
Contents: body.String(),
104+
}
105+
106+
if err := scanner.Err(); err != nil {
107+
return kep, errors.Wrap(err, "reading file")
108+
}
109+
110+
// this file is just the KEP metadata
111+
if count == 0 {
112+
metadata = body.Bytes()
113+
kep.Contents = ""
114+
}
115+
116+
if err := yaml.Unmarshal(metadata, &kep); err != nil {
117+
k.Errors = append(k.Errors, errors.Wrap(err, "error unmarshalling YAML"))
118+
return kep, errors.Wrap(err, "unmarshalling YAML")
119+
}
120+
121+
if valErr := kep.Validate(); valErr != nil {
122+
k.Errors = append(k.Errors, errors.Wrap(valErr, "validating KEP"))
123+
return kep, errors.Wrap(valErr, "validating KEP")
124+
}
125+
126+
kep.ID = hash(kep.OwningSIG + ":" + kep.Title)
127+
128+
return kep, nil
129+
}
130+
59131
type Milestone struct {
60132
Alpha string `json:"alpha" yaml:"alpha"`
61133
Beta string `json:"beta" yaml:"beta"`
@@ -66,3 +138,7 @@ type FeatureGate struct {
66138
Name string `json:"name" yaml:"name"`
67139
Components []string `json:"components" yaml:"components"`
68140
}
141+
142+
func hash(s string) string {
143+
return fmt.Sprintf("%x", md5.Sum([]byte(s)))
144+
}

test/metadata_test.go

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/stretchr/testify/require"
2626

2727
"k8s.io/enhancements/api"
28-
"k8s.io/enhancements/pkg/legacy/keps"
2928
)
3029

3130
const (
@@ -34,37 +33,14 @@ const (
3433
kepMetadata = "kep.yaml"
3534
)
3635

37-
// This is the actual validation check of all keps in this repo
36+
var files = []string{}
37+
38+
// This is the actual validation check of all KEPs in this repo
3839
func TestValidation(t *testing.T) {
3940
// Find all the keps
40-
files := []string{}
4141
err := filepath.Walk(
4242
filepath.Join("..", kepsDir),
43-
func(path string, info os.FileInfo, err error) error {
44-
if err != nil {
45-
return err
46-
}
47-
if info.IsDir() {
48-
return nil
49-
}
50-
51-
dir := filepath.Dir(path)
52-
// true if the file is a symlink
53-
if info.Mode()&os.ModeSymlink != 0 {
54-
// assume symlink from old KEP location to new
55-
newLocation, err := os.Readlink(path)
56-
if err != nil {
57-
return err
58-
}
59-
files = append(files, filepath.Join(dir, filepath.Dir(newLocation), kepMetadata))
60-
return nil
61-
}
62-
if ignore(dir, info.Name()) {
63-
return nil
64-
}
65-
files = append(files, path)
66-
return nil
67-
},
43+
walkFn,
6844
)
6945
// This indicates a problem walking the filepath, not a validation error.
7046
if err != nil {
@@ -75,7 +51,7 @@ func TestValidation(t *testing.T) {
7551
t.Fatal("must find more than 0 keps")
7652
}
7753

78-
kepParser := &keps.Parser{}
54+
kepHandler := &api.KEPHandler{}
7955
prrHandler := &api.PRRHandler{}
8056
prrsDir := filepath.Join("..", prrsDir)
8157

@@ -88,7 +64,9 @@ func TestValidation(t *testing.T) {
8864

8965
defer kepFile.Close()
9066

91-
kep := kepParser.Parse(kepFile)
67+
kep, kepParseErr := kepHandler.Parse(kepFile)
68+
require.Nil(t, kepParseErr)
69+
9270
if kep.Error != nil {
9371
t.Errorf("%v has an error: %v", filename, kep.Error)
9472
}
@@ -152,6 +130,36 @@ func TestValidation(t *testing.T) {
152130
}
153131
}
154132

133+
var walkFn = func(path string, info os.FileInfo, err error) error {
134+
if err != nil {
135+
return err
136+
}
137+
138+
if info.IsDir() {
139+
return nil
140+
}
141+
142+
dir := filepath.Dir(path)
143+
// true if the file is a symlink
144+
if info.Mode()&os.ModeSymlink != 0 {
145+
// assume symlink from old KEP location to new
146+
newLocation, err := os.Readlink(path)
147+
if err != nil {
148+
return err
149+
}
150+
151+
files = append(files, filepath.Join(dir, filepath.Dir(newLocation), kepMetadata))
152+
return nil
153+
}
154+
155+
if ignore(dir, info.Name()) {
156+
return nil
157+
}
158+
159+
files = append(files, path)
160+
return nil
161+
}
162+
155163
// TODO: Consider replacing with a .kepignore file
156164
// TODO: Is this a duplicate of the package function?
157165
// ignore certain files in the keps/ subdirectory

0 commit comments

Comments
 (0)