Skip to content

Commit 221c057

Browse files
vdemeestertekton-robot
authored andcommitted
Enhance v1beta1 validation code for taskrun 🍸
This make a better use of knative.dev/pkg apis errors package in order to make the code simpler, *and* the report better. - This allows reporting multiple validation error at once — so, one failure message (webhook error) would be more useful to the user. - This reduce `if err != nil` path, simplifying the code. This commit tackles `TaskRun` 🙃 Signed-off-by: Vincent Demeester <[email protected]>
1 parent de8d72c commit 221c057

File tree

2 files changed

+34
-52
lines changed

2 files changed

+34
-52
lines changed

pkg/apis/pipeline/v1beta1/taskrun_validation.go

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"strings"
2323

2424
"github.com/tektoncd/pipeline/pkg/apis/validate"
25-
"k8s.io/apimachinery/pkg/api/equality"
2625
"k8s.io/apimachinery/pkg/util/sets"
2726
"knative.dev/pkg/apis"
2827
)
@@ -31,89 +30,69 @@ var _ apis.Validatable = (*TaskRun)(nil)
3130

3231
// Validate taskrun
3332
func (tr *TaskRun) Validate(ctx context.Context) *apis.FieldError {
34-
if err := validate.ObjectMetadata(tr.GetObjectMeta()).ViaField("metadata"); err != nil {
35-
return err
36-
}
37-
return tr.Spec.Validate(ctx)
33+
errs := validate.ObjectMetadata(tr.GetObjectMeta()).ViaField("metadata")
34+
return errs.Also(tr.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec"))
3835
}
3936

4037
// Validate taskrun spec
41-
func (ts *TaskRunSpec) Validate(ctx context.Context) *apis.FieldError {
42-
if equality.Semantic.DeepEqual(ts, &TaskRunSpec{}) {
43-
return apis.ErrMissingField("spec")
44-
}
45-
38+
func (ts *TaskRunSpec) Validate(ctx context.Context) (errs *apis.FieldError) {
4639
// can't have both taskRef and taskSpec at the same time
4740
if (ts.TaskRef != nil && ts.TaskRef.Name != "") && ts.TaskSpec != nil {
48-
return apis.ErrDisallowedFields("spec.taskref", "spec.taskspec")
41+
errs = errs.Also(apis.ErrDisallowedFields("taskref", "taskspec"))
4942
}
5043

5144
// Check that one of TaskRef and TaskSpec is present
5245
if (ts.TaskRef == nil || (ts.TaskRef != nil && ts.TaskRef.Name == "")) && ts.TaskSpec == nil {
53-
return apis.ErrMissingField("spec.taskref.name", "spec.taskspec")
46+
errs = errs.Also(apis.ErrMissingField("taskref.name", "taskspec"))
5447
}
5548

5649
// Validate TaskSpec if it's present
5750
if ts.TaskSpec != nil {
58-
if err := ts.TaskSpec.Validate(ctx).ViaField("taskspec"); err != nil {
59-
return err
60-
}
51+
errs = errs.Also(ts.TaskSpec.Validate(ctx).ViaField("taskspec"))
6152
}
6253

63-
if err := validateParameters(ts.Params); err != nil {
64-
return err
65-
}
66-
67-
if err := validateWorkspaceBindings(ctx, ts.Workspaces); err != nil {
68-
return err
69-
}
70-
71-
// Validate Resources declaration
72-
if err := ts.Resources.Validate(ctx); err != nil {
73-
return err
74-
}
54+
errs = errs.Also(validateParameters(ts.Params).ViaField("params"))
55+
errs = errs.Also(validateWorkspaceBindings(ctx, ts.Workspaces).ViaField("workspaces"))
56+
errs = errs.Also(ts.Resources.Validate(ctx).ViaField("resources"))
7557

7658
if ts.Status != "" {
7759
if ts.Status != TaskRunSpecStatusCancelled {
78-
return apis.ErrInvalidValue(fmt.Sprintf("%s should be %s", ts.Status, TaskRunSpecStatusCancelled), "spec.status")
60+
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("%s should be %s", ts.Status, TaskRunSpecStatusCancelled), "status"))
7961
}
8062
}
81-
8263
if ts.Timeout != nil {
8364
// timeout should be a valid duration of at least 0.
8465
if ts.Timeout.Duration < 0 {
85-
return apis.ErrInvalidValue(fmt.Sprintf("%s should be >= 0", ts.Timeout.Duration.String()), "spec.timeout")
66+
errs = errs.Also(apis.ErrInvalidValue(fmt.Sprintf("%s should be >= 0", ts.Timeout.Duration.String()), "timeout"))
8667
}
8768
}
8869

89-
return nil
70+
return errs
9071
}
9172

9273
// validateWorkspaceBindings makes sure the volumes provided for the Task's declared workspaces make sense.
93-
func validateWorkspaceBindings(ctx context.Context, wb []WorkspaceBinding) *apis.FieldError {
74+
func validateWorkspaceBindings(ctx context.Context, wb []WorkspaceBinding) (errs *apis.FieldError) {
9475
seen := sets.NewString()
95-
for _, w := range wb {
76+
for idx, w := range wb {
9677
if seen.Has(w.Name) {
97-
return apis.ErrMultipleOneOf("spec.workspaces.name")
78+
errs = errs.Also(apis.ErrMultipleOneOf("name").ViaIndex(idx))
9879
}
9980
seen.Insert(w.Name)
10081

101-
if err := w.Validate(ctx).ViaField("workspace"); err != nil {
102-
return err
103-
}
82+
errs = errs.Also(w.Validate(ctx).ViaIndex(idx))
10483
}
10584

106-
return nil
85+
return errs
10786
}
10887

109-
func validateParameters(params []Param) *apis.FieldError {
88+
func validateParameters(params []Param) (errs *apis.FieldError) {
11089
// Template must not duplicate parameter names.
11190
seen := sets.NewString()
11291
for _, p := range params {
11392
if seen.Has(strings.ToLower(p.Name)) {
114-
return apis.ErrMultipleOneOf("spec.params.name")
93+
errs = errs.Also(apis.ErrMultipleOneOf("name").ViaKey(p.Name))
11594
}
11695
seen.Insert(p.Name)
11796
}
118-
return nil
97+
return errs
11998
}

pkg/apis/pipeline/v1beta1/taskrun_validation_test.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,16 @@ func TestTaskRun_Invalidate(t *testing.T) {
3838
}{{
3939
name: "invalid taskspec",
4040
task: &v1beta1.TaskRun{},
41-
want: apis.ErrMissingField("spec"),
41+
want: apis.ErrMissingField("spec.taskref.name", "spec.taskspec"),
4242
}, {
4343
name: "invalid taskrun metadata",
4444
task: &v1beta1.TaskRun{
4545
ObjectMeta: metav1.ObjectMeta{
4646
Name: "task.name",
4747
},
48+
Spec: v1beta1.TaskRunSpec{
49+
TaskRef: &v1beta1.TaskRef{Name: "task"},
50+
},
4851
},
4952
want: &apis.FieldError{
5053
Message: "Invalid resource name: special character . must not be present",
@@ -92,7 +95,7 @@ func TestTaskRun_Workspaces_Invalid(t *testing.T) {
9295
}},
9396
},
9497
},
95-
wantErr: apis.ErrMissingField("workspace.persistentvolumeclaim.claimname"),
98+
wantErr: apis.ErrMissingField("spec.workspaces[0].persistentvolumeclaim.claimname"),
9699
}, {
97100
name: "bind same workspace twice",
98101
tr: &v1beta1.TaskRun{
@@ -108,7 +111,7 @@ func TestTaskRun_Workspaces_Invalid(t *testing.T) {
108111
}},
109112
},
110113
},
111-
wantErr: apis.ErrMultipleOneOf("spec.workspaces.name"),
114+
wantErr: apis.ErrMultipleOneOf("spec.workspaces[1].name"),
112115
}}
113116
for _, ts := range tests {
114117
t.Run(ts.name, func(t *testing.T) {
@@ -131,13 +134,13 @@ func TestTaskRunSpec_Invalidate(t *testing.T) {
131134
}{{
132135
name: "invalid taskspec",
133136
spec: v1beta1.TaskRunSpec{},
134-
wantErr: apis.ErrMissingField("spec"),
137+
wantErr: apis.ErrMissingField("taskref.name", "taskspec"),
135138
}, {
136139
name: "invalid taskref name",
137140
spec: v1beta1.TaskRunSpec{
138141
TaskRef: &v1beta1.TaskRef{},
139142
},
140-
wantErr: apis.ErrMissingField("spec.taskref.name, spec.taskspec"),
143+
wantErr: apis.ErrMissingField("taskref.name, taskspec"),
141144
}, {
142145
name: "invalid taskref and taskspec together",
143146
spec: v1beta1.TaskRunSpec{
@@ -151,7 +154,7 @@ func TestTaskRunSpec_Invalidate(t *testing.T) {
151154
}}},
152155
},
153156
},
154-
wantErr: apis.ErrDisallowedFields("spec.taskspec", "spec.taskref"),
157+
wantErr: apis.ErrDisallowedFields("taskspec", "taskref"),
155158
}, {
156159
name: "negative pipeline timeout",
157160
spec: v1beta1.TaskRunSpec{
@@ -160,7 +163,7 @@ func TestTaskRunSpec_Invalidate(t *testing.T) {
160163
},
161164
Timeout: &metav1.Duration{Duration: -48 * time.Hour},
162165
},
163-
wantErr: apis.ErrInvalidValue("-48h0m0s should be >= 0", "spec.timeout"),
166+
wantErr: apis.ErrInvalidValue("-48h0m0s should be >= 0", "timeout"),
164167
}, {
165168
name: "wrong taskrun cancel",
166169
spec: v1beta1.TaskRunSpec{
@@ -169,7 +172,7 @@ func TestTaskRunSpec_Invalidate(t *testing.T) {
169172
},
170173
Status: "TaskRunCancell",
171174
},
172-
wantErr: apis.ErrInvalidValue("TaskRunCancell should be TaskRunCancelled", "spec.status"),
175+
wantErr: apis.ErrInvalidValue("TaskRunCancell should be TaskRunCancelled", "status"),
173176
}, {
174177
name: "invalid taskspec",
175178
spec: v1beta1.TaskRunSpec{
@@ -189,15 +192,15 @@ func TestTaskRunSpec_Invalidate(t *testing.T) {
189192
name: "invalid params",
190193
spec: v1beta1.TaskRunSpec{
191194
Params: []v1beta1.Param{{
192-
Name: "name",
195+
Name: "myname",
193196
Value: *v1beta1.NewArrayOrString("value"),
194197
}, {
195-
Name: "name",
198+
Name: "myname",
196199
Value: *v1beta1.NewArrayOrString("value"),
197200
}},
198201
TaskRef: &v1beta1.TaskRef{Name: "mytask"},
199202
},
200-
wantErr: apis.ErrMultipleOneOf("spec.params.name"),
203+
wantErr: apis.ErrMultipleOneOf("params[myname].name"),
201204
}}
202205
for _, ts := range tests {
203206
t.Run(ts.name, func(t *testing.T) {

0 commit comments

Comments
 (0)