Skip to content

Commit 4b1b761

Browse files
bobcatfishtekton-robot
authored andcommitted
Determine correct graph when params and results are mixed 🥄
This was partially addressed in #2387 however the example from the bug (#2387) was using runAfter, and it should be possible to determine the correct graph without runAfter. The logic that was determining the graph was returning an error if any of the substitutions present in a string along with a result were not results. Now we will instead ignore these substitutions. We might want to revisit the validation to make sure that invalid results substitutions are still caught.
1 parent fc2bf79 commit 4b1b761

File tree

8 files changed

+163
-73
lines changed

8 files changed

+163
-73
lines changed

‎examples/v1beta1/pipelineruns/pipelinerun-results-with-params.yaml‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,14 @@ spec:
2121
script: |
2222
echo -n "suffix" > $(results.suffix.path)
2323
- name: do-something
24-
runAfter:
25-
- generate-suffix
2624
taskSpec:
2725
params:
2826
- name: arg
2927
steps:
3028
- name: do-something
3129
image: alpine
3230
script: |
33-
echo "$(params.arg)"
31+
echo "$(params.arg)" | grep "prefix:suffix"
3432
params:
3533
- name: arg
3634
value: "$(params.prefix):$(tasks.generate-suffix.results.suffix)"

‎pkg/apis/pipeline/v1alpha1/pipeline_types.go‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,9 @@ func (pt PipelineTask) Deps() []string {
170170
for _, param := range cond.Params {
171171
expressions, ok := v1beta1.GetVarSubstitutionExpressionsForParam(param)
172172
if ok {
173-
if resultRefs, err := v1beta1.NewResultRefs(expressions); err == nil {
174-
for _, resultRef := range resultRefs {
175-
deps = append(deps, resultRef.PipelineTask)
176-
}
173+
resultRefs := v1beta1.NewResultRefs(expressions)
174+
for _, resultRef := range resultRefs {
175+
deps = append(deps, resultRef.PipelineTask)
177176
}
178177
}
179178
}
@@ -182,10 +181,9 @@ func (pt PipelineTask) Deps() []string {
182181
for _, param := range pt.Params {
183182
expressions, ok := v1beta1.GetVarSubstitutionExpressionsForParam(param)
184183
if ok {
185-
if resultRefs, err := v1beta1.NewResultRefs(expressions); err == nil {
186-
for _, resultRef := range resultRefs {
187-
deps = append(deps, resultRef.PipelineTask)
188-
}
184+
resultRefs := v1beta1.NewResultRefs(expressions)
185+
for _, resultRef := range resultRefs {
186+
deps = append(deps, resultRef.PipelineTask)
189187
}
190188
}
191189
}

‎pkg/apis/pipeline/v1beta1/pipeline_types.go‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,9 @@ func (pt PipelineTask) Deps() []string {
155155
for _, param := range cond.Params {
156156
expressions, ok := GetVarSubstitutionExpressionsForParam(param)
157157
if ok {
158-
if resultRefs, err := NewResultRefs(expressions); err == nil {
159-
for _, resultRef := range resultRefs {
160-
deps = append(deps, resultRef.PipelineTask)
161-
}
158+
resultRefs := NewResultRefs(expressions)
159+
for _, resultRef := range resultRefs {
160+
deps = append(deps, resultRef.PipelineTask)
162161
}
163162
}
164163
}
@@ -167,10 +166,9 @@ func (pt PipelineTask) Deps() []string {
167166
for _, param := range pt.Params {
168167
expressions, ok := GetVarSubstitutionExpressionsForParam(param)
169168
if ok {
170-
if resultRefs, err := NewResultRefs(expressions); err == nil {
171-
for _, resultRef := range resultRefs {
172-
deps = append(deps, resultRef.PipelineTask)
173-
}
169+
resultRefs := NewResultRefs(expressions)
170+
for _, resultRef := range resultRefs {
171+
deps = append(deps, resultRef.PipelineTask)
174172
}
175173
}
176174
}

‎pkg/apis/pipeline/v1beta1/pipeline_validation.go‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,9 @@ func validateParamResults(tasks []PipelineTask) error {
331331
if ok {
332332
if LooksLikeContainsResultRefs(expressions) {
333333
expressions = filter(expressions, looksLikeResultRef)
334-
if _, err := NewResultRefs(expressions); err != nil {
335-
return err
334+
resultRefs := NewResultRefs(expressions)
335+
if len(expressions) != len(resultRefs) {
336+
return fmt.Errorf("expected all of the expressions %v to be result expressions but only %v were", expressions, resultRefs)
336337
}
337338
}
338339
}
@@ -358,8 +359,9 @@ func validatePipelineResults(results []PipelineResult) error {
358359
if ok {
359360
if LooksLikeContainsResultRefs(expressions) {
360361
expressions = filter(expressions, looksLikeResultRef)
361-
if _, err := NewResultRefs(expressions); err != nil {
362-
return err
362+
resultRefs := NewResultRefs(expressions)
363+
if len(expressions) != len(resultRefs) {
364+
return fmt.Errorf("expected all of the expressions %v to be result expressions but only %v were", expressions, resultRefs)
363365
}
364366
}
365367
}

‎pkg/apis/pipeline/v1beta1/resultref.go‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,23 @@ const (
4141
var variableSubstitutionRegex = regexp.MustCompile(variableSubstitutionFormat)
4242

4343
// NewResultRefs extracts all ResultReferences from a param or a pipeline result.
44-
// If the ResultReference can be extracted, they are returned. Otherwise an error is returned
45-
func NewResultRefs(expressions []string) ([]*ResultRef, error) {
44+
// If the ResultReference can be extracted, they are returned. Expressions which are not
45+
// results are ignored.
46+
func NewResultRefs(expressions []string) []*ResultRef {
4647
var resultRefs []*ResultRef
4748
for _, expression := range expressions {
4849
pipelineTask, result, err := parseExpression(expression)
49-
if err != nil {
50-
return nil, fmt.Errorf("Invalid result reference expression: %v", err)
50+
// If the expression isn't a result but is some other expression,
51+
// parseExpression will return an error, in which case we just skip that expression,
52+
// since although it's not a result ref, it might be some other kind of reference
53+
if err == nil {
54+
resultRefs = append(resultRefs, &ResultRef{
55+
PipelineTask: pipelineTask,
56+
Result: result,
57+
})
5158
}
52-
resultRefs = append(resultRefs, &ResultRef{
53-
PipelineTask: pipelineTask,
54-
Result: result,
55-
})
5659
}
57-
return resultRefs, nil
60+
return resultRefs
5861
}
5962

6063
// LooksLikeContainsResultRefs attempts to check if param or a pipeline result looks like it contains any

‎pkg/apis/pipeline/v1beta1/resultref_test.go‎

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ func TestNewResultReference(t *testing.T) {
2929
param v1beta1.Param
3030
}
3131
tests := []struct {
32-
name string
33-
args args
34-
want []*v1beta1.ResultRef
35-
wantErr bool
32+
name string
33+
args args
34+
want []*v1beta1.ResultRef
3635
}{
3736
{
3837
name: "Test valid expression",
@@ -51,9 +50,8 @@ func TestNewResultReference(t *testing.T) {
5150
Result: "sumResult",
5251
},
5352
},
54-
wantErr: false,
5553
}, {
56-
name: "Test valid expression: substitution within string",
54+
name: "substitution within string",
5755
args: args{
5856
param: v1beta1.Param{
5957
Name: "param",
@@ -69,9 +67,8 @@ func TestNewResultReference(t *testing.T) {
6967
Result: "sumResult",
7068
},
7169
},
72-
wantErr: false,
7370
}, {
74-
name: "Test valid expression: multiple substitution",
71+
name: "multiple substitution",
7572
args: args{
7673
param: v1beta1.Param{
7774
Name: "param",
@@ -90,9 +87,28 @@ func TestNewResultReference(t *testing.T) {
9087
Result: "sumResult",
9188
},
9289
},
93-
wantErr: false,
9490
}, {
95-
name: "Test invalid expression: first separator typo",
91+
name: "multiple substitution with param",
92+
args: args{
93+
param: v1beta1.Param{
94+
Name: "param",
95+
Value: v1beta1.ArrayOrString{
96+
Type: v1beta1.ParamTypeString,
97+
StringVal: "$(params.param) $(tasks.sumTask1.results.sumResult) and another $(tasks.sumTask2.results.sumResult)",
98+
},
99+
},
100+
},
101+
want: []*v1beta1.ResultRef{
102+
{
103+
PipelineTask: "sumTask1",
104+
Result: "sumResult",
105+
}, {
106+
PipelineTask: "sumTask2",
107+
Result: "sumResult",
108+
},
109+
},
110+
}, {
111+
name: "first separator typo",
96112
args: args{
97113
param: v1beta1.Param{
98114
Name: "param",
@@ -102,10 +118,9 @@ func TestNewResultReference(t *testing.T) {
102118
},
103119
},
104120
},
105-
want: nil,
106-
wantErr: true,
121+
want: nil,
107122
}, {
108-
name: "Test invalid expression: third separator typo",
123+
name: "third separator typo",
109124
args: args{
110125
param: v1beta1.Param{
111126
Name: "param",
@@ -115,10 +130,9 @@ func TestNewResultReference(t *testing.T) {
115130
},
116131
},
117132
},
118-
want: nil,
119-
wantErr: true,
133+
want: nil,
120134
}, {
121-
name: "Test invalid expression: param substitution shouldn't be considered result ref",
135+
name: "param substitution shouldn't be considered result ref",
122136
args: args{
123137
param: v1beta1.Param{
124138
Name: "param",
@@ -128,10 +142,9 @@ func TestNewResultReference(t *testing.T) {
128142
},
129143
},
130144
},
131-
want: nil,
132-
wantErr: true,
145+
want: nil,
133146
}, {
134-
name: "Test invalid expression: One bad and good result substitution",
147+
name: "One bad and good result substitution",
135148
args: args{
136149
param: v1beta1.Param{
137150
Name: "param",
@@ -141,23 +154,24 @@ func TestNewResultReference(t *testing.T) {
141154
},
142155
},
143156
},
144-
want: nil,
145-
wantErr: true,
157+
want: []*v1beta1.ResultRef{
158+
{
159+
PipelineTask: "sumTask1",
160+
Result: "sumResult",
161+
},
162+
},
146163
},
147164
}
148165
for _, tt := range tests {
149166
t.Run(tt.name, func(t *testing.T) {
150167
expressions, ok := v1beta1.GetVarSubstitutionExpressionsForParam(tt.args.param)
151-
if !ok {
168+
if !ok && tt.want != nil {
152169
t.Fatalf("expected to find expressions but didn't find any")
153-
}
154-
got, err := v1beta1.NewResultRefs(expressions)
155-
if tt.wantErr != (err != nil) {
156-
t.Errorf("TestNewResultReference/%s wantErr %v, error = %v", tt.name, tt.wantErr, err)
157-
return
158-
}
159-
if d := cmp.Diff(tt.want, got); d != "" {
160-
t.Errorf("TestNewResultReference/%s (-want, +got) = %v", tt.name, d)
170+
} else {
171+
got := v1beta1.NewResultRefs(expressions)
172+
if d := cmp.Diff(tt.want, got); d != "" {
173+
t.Errorf("TestNewResultReference/%s (-want, +got) = %v", tt.name, d)
174+
}
161175
}
162176
})
163177
}
@@ -281,7 +295,7 @@ func TestHasResultReference(t *testing.T) {
281295
if !ok {
282296
t.Fatalf("expected to find expressions but didn't find any")
283297
}
284-
got, _ := v1beta1.NewResultRefs(expressions)
298+
got := v1beta1.NewResultRefs(expressions)
285299
sort.Slice(got, func(i, j int) bool {
286300
if got[i].PipelineTask > got[j].PipelineTask {
287301
return false

‎pkg/reconciler/pipelinerun/pipelinerun_test.go‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,85 @@ func TestReconcileWithTaskResults(t *testing.T) {
18911891
}
18921892
}
18931893

1894+
func TestReconcileWithTaskResultsEmbeddedNoneStarted(t *testing.T) {
1895+
names.TestingSeed()
1896+
prs := []*v1alpha1.PipelineRun{tb.PipelineRun("test-pipeline-run-different-service-accs", tb.PipelineRunNamespace("foo"),
1897+
tb.PipelineRunSpec("test-pipeline",
1898+
tb.PipelineRunPipelineSpec(
1899+
tb.PipelineParamSpec("foo", v1alpha1.ParamTypeString),
1900+
tb.PipelineTask("a-task", "a-task"),
1901+
tb.PipelineTask("b-task", "b-task",
1902+
tb.PipelineTaskParam("bParam", "$(params.foo)/baz@$(tasks.a-task.results.A_RESULT)"),
1903+
),
1904+
),
1905+
tb.PipelineRunParam("foo", "bar"),
1906+
tb.PipelineRunServiceAccountName("test-sa-0"),
1907+
),
1908+
)}
1909+
ts := []*v1alpha1.Task{
1910+
tb.Task("a-task", tb.TaskNamespace("foo"),
1911+
tb.TaskSpec(
1912+
tb.TaskResults("A_RESULT", ""),
1913+
),
1914+
),
1915+
tb.Task("b-task", tb.TaskNamespace("foo"),
1916+
tb.TaskSpec(
1917+
tb.TaskInputs(tb.InputsParamSpec("bParam", v1alpha1.ParamTypeString)),
1918+
),
1919+
),
1920+
}
1921+
d := test.Data{
1922+
PipelineRuns: prs,
1923+
Tasks: ts,
1924+
}
1925+
testAssets, cancel := getPipelineRunController(t, d)
1926+
defer cancel()
1927+
c := testAssets.Controller
1928+
clients := testAssets.Clients
1929+
err := c.Reconciler.Reconcile(context.Background(), "foo/test-pipeline-run-different-service-accs")
1930+
if err != nil {
1931+
t.Errorf("Did not expect to see error when reconciling completed PipelineRun but saw %s", err)
1932+
}
1933+
// Check that the PipelineRun was reconciled correctly
1934+
reconciledRun, err := clients.Pipeline.TektonV1alpha1().PipelineRuns("foo").Get("test-pipeline-run-different-service-accs", metav1.GetOptions{})
1935+
if err != nil {
1936+
t.Fatalf("Somehow had error getting completed reconciled run out of fake client: %s", err)
1937+
}
1938+
1939+
if !reconciledRun.Status.GetCondition(apis.ConditionSucceeded).IsUnknown() {
1940+
t.Errorf("Expected PipelineRun to be running, but condition status is %s", reconciledRun.Status.GetCondition(apis.ConditionSucceeded))
1941+
}
1942+
1943+
// Since b-task is dependent on a-task, via the results, only a-task should run
1944+
expectedTaskRunName := "test-pipeline-run-different-service-accs-a-task-9l9zj"
1945+
expectedTaskRun := tb.TaskRun(expectedTaskRunName,
1946+
tb.TaskRunNamespace("foo"),
1947+
tb.TaskRunOwnerReference("PipelineRun", "test-pipeline-run-different-service-accs",
1948+
tb.OwnerReferenceAPIVersion("tekton.dev/v1alpha1"),
1949+
tb.Controller, tb.BlockOwnerDeletion,
1950+
),
1951+
tb.TaskRunLabel("tekton.dev/pipeline", "test-pipeline-run-different-service-accs"),
1952+
tb.TaskRunLabel("tekton.dev/pipelineRun", "test-pipeline-run-different-service-accs"),
1953+
tb.TaskRunLabel("tekton.dev/pipelineTask", "a-task"),
1954+
tb.TaskRunSpec(
1955+
tb.TaskRunTaskRef("a-task", tb.TaskRefKind(v1beta1.NamespacedTaskKind)),
1956+
tb.TaskRunServiceAccountName("test-sa-0"),
1957+
),
1958+
)
1959+
// Check that the expected TaskRun was created (only)
1960+
actual, err := clients.Pipeline.TektonV1alpha1().TaskRuns("foo").List(metav1.ListOptions{})
1961+
if err != nil {
1962+
t.Fatalf("Failure to list TaskRun's %s", err)
1963+
}
1964+
if len(actual.Items) != 1 {
1965+
t.Fatalf("Expected 1 TaskRuns got %d", len(actual.Items))
1966+
}
1967+
actualTaskRun := actual.Items[0]
1968+
if d := cmp.Diff(expectedTaskRun, &actualTaskRun); d != "" {
1969+
t.Errorf("expected to see TaskRun %v created. Diff (-want, +got): %s", expectedTaskRun, d)
1970+
}
1971+
}
1972+
18941973
func TestReconcileWithPipelineResults(t *testing.T) {
18951974
names.TestingSeed()
18961975
ps := []*v1alpha1.Pipeline{tb.Pipeline("test-pipeline", tb.PipelineNamespace("foo"), tb.PipelineSpec(

‎pkg/reconciler/pipelinerun/resources/resultrefresolution.go‎

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,16 @@ func extractResultRefsForPipelineResult(pipelineRunState PipelineRunState, resul
7676
}
7777

7878
func extractResultRefs(expressions []string, pipelineRunState PipelineRunState) (ResolvedResultRefs, error) {
79-
if resultRefs, err := v1beta1.NewResultRefs(expressions); err == nil {
80-
var resolvedResultRefs ResolvedResultRefs
81-
for _, resultRef := range resultRefs {
82-
resolvedResultRef, err := resolveResultRef(pipelineRunState, resultRef)
83-
if err != nil {
84-
return nil, err
85-
}
86-
resolvedResultRefs = append(resolvedResultRefs, resolvedResultRef)
79+
resultRefs := v1beta1.NewResultRefs(expressions)
80+
var resolvedResultRefs ResolvedResultRefs
81+
for _, resultRef := range resultRefs {
82+
resolvedResultRef, err := resolveResultRef(pipelineRunState, resultRef)
83+
if err != nil {
84+
return nil, err
8785
}
88-
return removeDup(resolvedResultRefs), nil
86+
resolvedResultRefs = append(resolvedResultRefs, resolvedResultRef)
8987
}
90-
return nil, nil
88+
return removeDup(resolvedResultRefs), nil
9189
}
9290

9391
func removeDup(refs ResolvedResultRefs) ResolvedResultRefs {

0 commit comments

Comments
 (0)