Skip to content

Commit 697c54b

Browse files
EmmaMunleytekton-robot
authored andcommitted
Added Skip Logic: Matrix parameters cannot be empty arrays
If a matrix parameter contains an empty array it will be skipped - no PipelineTask will be created - this follows the same logic for when expressions.
1 parent 3ebba4d commit 697c54b

File tree

9 files changed

+152
-3
lines changed

9 files changed

+152
-3
lines changed

docs/matrix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ Note that:
188188
- The names of the `Parameters` in the `Matrix` must be unique. Specifying the same parameter multiple times
189189
will result in a validation error.
190190
- A `Parameter` can be passed to either the `matrix` or `params` field, not both.
191+
- If the `Matrix` has an empty array `Parameter`, then the `PipelineTask` will be skipped.
191192

192193
For further details on specifying `Parameters` in the `Pipeline` and passing them to
193194
`PipelineTasks`, see [documentation](pipelines.md#specifying-parameters).

docs/pipeline-api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3868,7 +3868,10 @@ SkippingReason
38683868
<th>Description</th>
38693869
</tr>
38703870
</thead>
3871-
<tbody><tr><td><p>&#34;PipelineRun Finally timeout has been reached&#34;</p></td>
3871+
<tbody><tr><td><p>&#34;Matrix Parameters have an empty array&#34;</p></td>
3872+
<td><p>EmptyArrayInMatrixParams means the task was skipped because Matrix parameters contain empty array.</p>
3873+
</td>
3874+
</tr><tr><td><p>&#34;PipelineRun Finally timeout has been reached&#34;</p></td>
38723875
<td><p>FinallyTimedOutSkip means the task was skipped because the PipelineRun has passed its Timeouts.Finally.</p>
38733876
</td>
38743877
</tr><tr><td><p>&#34;PipelineRun was gracefully cancelled&#34;</p></td>

examples/v1beta1/pipelineruns/alpha/pipelinerun-with-matrix.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ kind: PipelineRun
2020
metadata:
2121
generateName: matrixed-pr-
2222
spec:
23-
serviceAccountName: 'default'
23+
serviceAccountName: "default"
2424
pipelineSpec:
2525
tasks:
2626
- name: platforms-and-browsers
@@ -51,3 +51,28 @@ spec:
5151
value: chrome
5252
taskRef:
5353
name: platform-browsers
54+
- name: matrix-params-with-empty-array-skipped
55+
matrix:
56+
params:
57+
- name: version
58+
value: []
59+
taskSpec:
60+
params:
61+
- name: version
62+
steps:
63+
- name: echo
64+
image: ubuntu
65+
script: exit 1
66+
finally:
67+
- name: matrix-params-with-empty-array-skipped-in-finally
68+
matrix:
69+
params:
70+
- name: version
71+
value: []
72+
taskSpec:
73+
params:
74+
- name: version
75+
steps:
76+
- name: echo
77+
image: ubuntu
78+
script: exit 1

pkg/apis/pipeline/v1/pipelinerun_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ const (
469469
TasksTimedOutSkip SkippingReason = "PipelineRun Tasks timeout has been reached"
470470
// FinallyTimedOutSkip means the task was skipped because the PipelineRun has passed its Timeouts.Finally.
471471
FinallyTimedOutSkip SkippingReason = "PipelineRun Finally timeout has been reached"
472+
// EmptyArrayInMatrixParams means the task was skipped because Matrix parameters contain empty array.
473+
EmptyArrayInMatrixParams SkippingReason = "Matrix Parameters have an empty array"
472474
// None means the task was not skipped
473475
None SkippingReason = "None"
474476
)

pkg/apis/pipeline/v1beta1/pipelinerun_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ const (
495495
TasksTimedOutSkip SkippingReason = "PipelineRun Tasks timeout has been reached"
496496
// FinallyTimedOutSkip means the task was skipped because the PipelineRun has passed its Timeouts.Finally.
497497
FinallyTimedOutSkip SkippingReason = "PipelineRun Finally timeout has been reached"
498+
// EmptyArrayInMatrixParams means the task was skipped because Matrix parameters contain empty array.
499+
EmptyArrayInMatrixParams SkippingReason = "Matrix Parameters have an empty array"
498500
// None means the task was not skipped
499501
None SkippingReason = "None"
500502
)

pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ func (t *ResolvedPipelineTask) skip(facts *PipelineRunFacts) TaskSkipStatus {
383383
skippingReason = v1beta1.PipelineTimedOutSkip
384384
case t.skipBecausePipelineRunTasksTimeoutReached(facts):
385385
skippingReason = v1beta1.TasksTimedOutSkip
386+
case t.skipBecauseEmptyArrayInMatrixParams():
387+
skippingReason = v1beta1.EmptyArrayInMatrixParams
386388
default:
387389
skippingReason = v1beta1.None
388390
}
@@ -499,6 +501,19 @@ func (t *ResolvedPipelineTask) skipBecausePipelineRunFinallyTimeoutReached(facts
499501
return false
500502
}
501503

504+
// skipBecauseEmptyArrayInMatrixParams returns true if the matrix parameters contain an empty array
505+
func (t *ResolvedPipelineTask) skipBecauseEmptyArrayInMatrixParams() bool {
506+
if t.PipelineTask.IsMatrixed() {
507+
for _, ps := range t.PipelineTask.Matrix.Params {
508+
if len(ps.Value.ArrayVal) == 0 {
509+
return true
510+
}
511+
}
512+
}
513+
514+
return false
515+
}
516+
502517
// IsFinalTask returns true if a task is a finally task
503518
func (t *ResolvedPipelineTask) IsFinalTask(facts *PipelineRunFacts) bool {
504519
return facts.isFinalTask(t.PipelineTask.Name)
@@ -521,6 +536,8 @@ func (t *ResolvedPipelineTask) IsFinallySkipped(facts *PipelineRunFacts) TaskSki
521536
skippingReason = v1beta1.PipelineTimedOutSkip
522537
case t.skipBecausePipelineRunFinallyTimeoutReached(facts):
523538
skippingReason = v1beta1.FinallyTimedOutSkip
539+
case t.skipBecauseEmptyArrayInMatrixParams():
540+
skippingReason = v1beta1.EmptyArrayInMatrixParams
524541
default:
525542
skippingReason = v1beta1.None
526543
}

pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,77 @@ func TestIsSkipped(t *testing.T) {
11591159
"mytask1": false,
11601160
"mytask2": true,
11611161
},
1162+
}, {
1163+
name: "matrix-params-contain-empty-arr",
1164+
state: PipelineRunState{{
1165+
// not skipped no empty arrs
1166+
PipelineTask: &v1beta1.PipelineTask{
1167+
Name: "mytask1",
1168+
TaskRef: &v1beta1.TaskRef{Name: "matrix-1"},
1169+
Matrix: &v1beta1.Matrix{
1170+
Params: []v1beta1.Param{{
1171+
Name: "a-param",
1172+
Value: v1beta1.ParamValue{
1173+
Type: v1beta1.ParamTypeArray,
1174+
ArrayVal: []string{"foo", "bar"},
1175+
},
1176+
}}},
1177+
},
1178+
TaskRunName: "pipelinerun-matrix-empty-params",
1179+
TaskRun: nil,
1180+
ResolvedTask: &resources.ResolvedTask{
1181+
TaskSpec: &task.Spec,
1182+
},
1183+
}, {
1184+
// skipped empty ArrayVal exist in matrix param
1185+
PipelineTask: &v1beta1.PipelineTask{
1186+
Name: "mytask2",
1187+
TaskRef: &v1beta1.TaskRef{Name: "matrix-2"},
1188+
Matrix: &v1beta1.Matrix{
1189+
Params: []v1beta1.Param{{
1190+
Name: "a-param",
1191+
Value: v1beta1.ParamValue{
1192+
Type: v1beta1.ParamTypeArray,
1193+
ArrayVal: []string{},
1194+
},
1195+
}}},
1196+
},
1197+
TaskRunName: "pipelinerun-matrix-empty-params",
1198+
TaskRun: nil,
1199+
ResolvedTask: &resources.ResolvedTask{
1200+
TaskSpec: &task.Spec,
1201+
},
1202+
}, {
1203+
// skipped empty ArrayVal exist in matrix param
1204+
PipelineTask: &v1beta1.PipelineTask{
1205+
Name: "mytask3",
1206+
TaskRef: &v1beta1.TaskRef{Name: "matrix-2"},
1207+
Matrix: &v1beta1.Matrix{
1208+
Params: []v1beta1.Param{{
1209+
Name: "a-param",
1210+
Value: v1beta1.ParamValue{
1211+
Type: v1beta1.ParamTypeArray,
1212+
ArrayVal: []string{"foo", "bar"},
1213+
},
1214+
}, {
1215+
Name: "b-param",
1216+
Value: v1beta1.ParamValue{
1217+
Type: v1beta1.ParamTypeArray,
1218+
ArrayVal: []string{},
1219+
},
1220+
}}},
1221+
},
1222+
TaskRunName: "pipelinerun-matrix-empty-params",
1223+
TaskRun: nil,
1224+
ResolvedTask: &resources.ResolvedTask{
1225+
TaskSpec: &task.Spec,
1226+
},
1227+
}},
1228+
expected: map[string]bool{
1229+
"mytask1": false,
1230+
"mytask2": true,
1231+
"mytask3": true,
1232+
},
11621233
}} {
11631234
t.Run(tc.name, func(t *testing.T) {
11641235
d, err := dagFromState(tc.state)
@@ -2421,6 +2492,16 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24212492
Values: []string{"none"},
24222493
}},
24232494
},
2495+
}, {
2496+
PipelineTask: &v1beta1.PipelineTask{
2497+
Name: "final-task-7",
2498+
TaskRef: &v1beta1.TaskRef{Name: "task"},
2499+
Matrix: &v1beta1.Matrix{
2500+
Params: []v1beta1.Param{{
2501+
Name: "platform",
2502+
Value: v1beta1.ParamValue{Type: v1beta1.ParamTypeArray, ArrayVal: []string{}},
2503+
}}},
2504+
},
24242505
}}
24252506

24262507
testCases := []struct {
@@ -2440,6 +2521,7 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24402521
"final-task-4": true,
24412522
"final-task-5": false,
24422523
"final-task-6": true,
2524+
"final-task-7": true,
24432525
},
24442526
}, {
24452527
name: "finally timeout not yet reached",
@@ -2452,6 +2534,7 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24522534
"final-task-4": true,
24532535
"final-task-5": false,
24542536
"final-task-6": true,
2537+
"final-task-7": true,
24552538
},
24562539
}, {
24572540
name: "pipeline timeout not yet reached",
@@ -2464,6 +2547,7 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24642547
"final-task-4": true,
24652548
"final-task-5": false,
24662549
"final-task-6": true,
2550+
"final-task-7": true,
24672551
},
24682552
}, {
24692553
name: "finally timeout passed",
@@ -2476,6 +2560,7 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24762560
"final-task-4": true,
24772561
"final-task-5": true,
24782562
"final-task-6": true,
2563+
"final-task-7": true,
24792564
},
24802565
}, {
24812566
name: "pipeline timeout passed",
@@ -2488,6 +2573,7 @@ func TestResolvedPipelineRunTask_IsFinallySkipped(t *testing.T) {
24882573
"final-task-4": true,
24892574
"final-task-5": true,
24902575
"final-task-6": true,
2576+
"final-task-7": true,
24912577
},
24922578
},
24932579
}

pkg/reconciler/taskrun/validate_taskrun.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ import (
3333
// validateParams validates that all Pipeline Task, Matrix.Params and Matrix.Include parameters all have values, match the specified
3434
// type and object params have all the keys required
3535
func validateParams(ctx context.Context, paramSpecs []v1beta1.ParamSpec, params v1beta1.Params, matrixParams v1beta1.Params) error {
36+
if paramSpecs == nil {
37+
return nil
38+
}
3639
neededParamsNames, neededParamsTypes := neededParamsNamesAndTypes(paramSpecs)
3740
providedParams := params
3841
providedParams = append(providedParams, matrixParams...)
@@ -99,6 +102,7 @@ func wrongTypeParamsNames(params []v1beta1.Param, matrix v1beta1.Params, neededP
99102
// passed to the task that aren't being used.
100103
continue
101104
}
105+
// Matrix param replacements must be of type String
102106
if neededParamsTypes[param.Name] != v1beta1.ParamTypeString {
103107
wrongTypeParamNames = append(wrongTypeParamNames, param.Name)
104108
}
@@ -160,7 +164,11 @@ func findMissingKeys(neededKeys, providedKeys map[string][]string) map[string][]
160164
// It also validates that all parameters have values, parameter types match the specified type and
161165
// object params have all the keys required
162166
func ValidateResolvedTask(ctx context.Context, params v1beta1.Params, matrix *v1beta1.Matrix, rtr *resources.ResolvedTask) error {
163-
if err := validateParams(ctx, rtr.TaskSpec.Params, params, matrix.GetAllParams()); err != nil {
167+
var paramSpecs v1beta1.ParamSpecs
168+
if rtr != nil {
169+
paramSpecs = rtr.TaskSpec.Params
170+
}
171+
if err := validateParams(ctx, paramSpecs, params, matrix.GetAllParams()); err != nil {
164172
return fmt.Errorf("invalid input params for task %s: %w", rtr.TaskName, err)
165173
}
166174
return nil

pkg/reconciler/taskrun/validate_taskrun_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ func TestValidateResolvedTask_ValidParams(t *testing.T) {
4747
}, {
4848
Name: "zoo",
4949
Type: v1beta1.ParamTypeString,
50+
}, {
51+
Name: "matrixParam",
52+
Type: v1beta1.ParamTypeString,
5053
}, {
5154
Name: "include",
5255
Type: v1beta1.ParamTypeString,
@@ -110,6 +113,8 @@ func TestValidateResolvedTask_ValidParams(t *testing.T) {
110113
Params: v1beta1.Params{{
111114
Name: "zoo",
112115
Value: *v1beta1.NewStructuredValues("a", "b", "c"),
116+
}, {
117+
Name: "matrixParam", Value: v1beta1.ParamValue{Type: v1beta1.ParamTypeArray, ArrayVal: []string{}},
113118
}},
114119
Include: []v1beta1.IncludeParams{{
115120
Name: "build-1",

0 commit comments

Comments
 (0)