Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change ordering of ResolveResultRefs/ApplyTaskResults #6792

Merged
merged 1 commit into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions pkg/reconciler/pipelinerun/pipelinerun.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ func (c *Reconciler) resolvePipelineState(
},
getCustomRunFunc,
task,
pst,
)
if err != nil {
if tresources.IsGetTaskErrTransient(err) {
Expand Down Expand Up @@ -719,18 +720,14 @@ func (c *Reconciler) runNextSchedulableTask(ctx context.Context, pr *v1.Pipeline
return controller.NewPermanentError(err)
}

resolvedResultRefs, _, err := resources.ResolveResultRefs(pipelineRunFacts.State, nextRpts)
// Check for Missing Result References
err = resources.CheckMissingResultReferences(pipelineRunFacts.State, nextRpts)
if err != nil {
logger.Infof("Failed to resolve task result reference for %q with error %v", pr.Name, err)
pr.Status.MarkFailed(ReasonInvalidTaskResultReference, err.Error())
return controller.NewPermanentError(err)
}

resources.ApplyTaskResults(nextRpts, resolvedResultRefs)
// After we apply Task Results, we may be able to evaluate more
// when expressions, so reset the skipped cache
pipelineRunFacts.ResetSkippedCache()

// GetFinalTasks only returns final tasks when a DAG is complete
fNextRpts := pipelineRunFacts.GetFinalTasks()
if len(fNextRpts) != 0 {
Expand All @@ -754,6 +751,7 @@ func (c *Reconciler) runNextSchedulableTask(ctx context.Context, pr *v1.Pipeline
if rpt.IsFinalTask(pipelineRunFacts) {
c.setFinallyStartedTimeIfNeeded(pr, pipelineRunFacts)
}

if rpt == nil || rpt.Skip(pipelineRunFacts).IsSkipped || rpt.IsFinallySkipped(pipelineRunFacts).IsSkipped {
continue
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/reconciler/pipelinerun/pipelinerun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ spec:
- name: foo
image: busybox
script: 'exit 0'
`)}
`)}

trs := []*v1.TaskRun{mustParseTaskRunWithObjectMeta(t,
taskRunObjectMeta("test-pipeline-missing-results-task1", "foo",
Expand Down Expand Up @@ -1181,7 +1181,7 @@ status:
image: busybox
script: 'exit 0'
conditions:
- message: "Could not find result with name result2 for task task1"
- message: "Invalid task result reference: Could not find result with name result2 for task task1"
reason: InvalidTaskResultReference
status: "False"
type: Succeeded
Expand Down
38 changes: 37 additions & 1 deletion pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,14 +542,25 @@ func ResolvePipelineTask(
getTaskRun resources.GetTaskRun,
getRun GetRun,
pipelineTask v1.PipelineTask,
pst PipelineRunState,
) (*ResolvedPipelineTask, error) {
rpt := ResolvedPipelineTask{
PipelineTask: &pipelineTask,
}
rpt.CustomTask = rpt.PipelineTask.TaskRef.IsCustomTask() || rpt.PipelineTask.TaskSpec.IsCustomTask()
numCombinations := 1
// We want to resolve all of the result references and ignore any errors at this point since there could be
// instances where result references are missing here, but will be later skipped or resolved in a subsequent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under what circumstances could result references be missing? In these circumstances, will pipelineTask.Matrix.CountCombinations() return the correct number of combinations, and will resolvePipelineTask create the correct number of TaskRuns?

I think we may try to resolve all pipeline tasks immediately, before running any. It seems to me like on the first reconcile loop, ResolvePipelineTask will generate TaskRunNames w/ length 1 for matrixed tasks fanned out from results, and on later reconcile loops will have the correct value.

I think having TaskRunNames in ResolvedPipelineTask doesn't work so well for matrixed pipeline tasks fanned out from array results, and would like to revisit the idea of label selectors. (We could also just merge #6603 if that gets too complicated.) I think this PR is running into a similar problem as #6603 though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The circumstance when result references will be missing is TestMissingResultWhenStepErrorIsIgnored
https://github.com/tektoncd/pipeline/blob/main/pkg/reconciler/pipelinerun/pipelinerun_test.go#L1052-L1090

The reason why we are reordering where we resolve and applyTaskResults in this PR is so that a matrixed pipelinetask that contains references to whole array results will not contain missing result references because the references will have already been resolved before where we try to generate the taskNames based on the number of combination in runNextSchedulableTask() so that we have the accurate number of combinations when fanning out the TaskRun() the first and only time it's called.

I have rebased and applied theses changes in the Add support for consuming whole array results in matrix PR and it's passing all of the tests. #6603

name: "whole array result replacements in matrix.params",
pName: "p-dag-3",
p: parse.MustParseV1beta1Pipeline(t, fmt.Sprintf(`
metadata:
name: %s
namespace: foo
spec:
tasks:
- name: pt-with-result
params:
- name: platforms
type: array
taskRef:
name: taskwithresults
- name: echo-platforms
matrix:
params:
- name: platform
value: $(tasks.pt-with-result.results.platforms[*])
taskRef:
name: mytask
`, "p-dag-3")),
tr: mustParseTaskRunWithObjectMeta(t,
taskRunObjectMeta("pr-pt-with-result", "foo",
"pr", "p-dag-3", "pt-with-result", false),
`
spec:
serviceAccountName: test-sa
taskRef:
name: taskwithresults
status:
conditions:
- type: Succeeded
status: "True"
reason: Succeeded
message: All Tasks have completed executing
taskResults:
- name: platforms
value:
- linux
- mac
- windows
`),
expectedTaskRuns: []*v1beta1.TaskRun{
mustParseTaskRunWithObjectMeta(t,
taskRunObjectMeta("pr-echo-platforms-0", "foo",
"pr", "p-dag-3", "echo-platforms", false),
`
spec:
params:
- name: platform
value: linux
serviceAccountName: test-sa
taskRef:
name: mytask
kind: Task
labels:
tekton.dev/memberOf: tasks
tekton.dev/pipeline: p-dag-3
`),
mustParseTaskRunWithObjectMeta(t,
taskRunObjectMeta("pr-echo-platforms-1", "foo",
"pr", "p-dag-3", "echo-platforms", false),
`
spec:
params:
- name: platform
value: mac
serviceAccountName: test-sa
taskRef:
name: mytask
kind: Task
labels:
tekton.dev/memberOf: tasks
tekton.dev/pipeline: p-dag-3
`),
mustParseTaskRunWithObjectMeta(t,
taskRunObjectMeta("pr-echo-platforms-2", "foo",
"pr", "p-dag-3", "echo-platforms", false),
`
spec:
params:
- name: platform
value: windows
serviceAccountName: test-sa
taskRef:
name: mytask
kind: Task
labels:
tekton.dev/memberOf: tasks
tekton.dev/pipeline: p-dag-3
`),
},
expectedPipelineRun: parse.MustParseV1beta1PipelineRun(t, `
metadata:
name: pr
namespace: foo
annotations: {}
labels:
tekton.dev/pipeline: p-dag-3
spec:
serviceAccountName: test-sa
pipelineRef:
name: p-dag-3
status:
pipelineSpec:
tasks:
- name: pt-with-result
params:
- name: platforms
type: array
taskRef:
name: taskwithresults
kind: Task
- name: echo-platforms
taskRef:
name: mytask
kind: Task
matrix:
params:
- name: platform
value: $(tasks.pt-with-result.results.platforms[*])
conditions:
- type: Succeeded
status: "Unknown"
reason: "Running"
message: "Tasks Completed: 1 (Failed: 0, Cancelled 0), Incomplete: 1, Skipped: 0"
childReferences:
- apiVersion: tekton.dev/v1beta1
kind: TaskRun
name: pr-pt-with-result
pipelineTaskName: pt-with-result
- apiVersion: tekton.dev/v1beta1
kind: TaskRun
name: pr-echo-platforms-0
pipelineTaskName: echo-platforms
- apiVersion: tekton.dev/v1beta1
kind: TaskRun
name: pr-echo-platforms-1
pipelineTaskName: echo-platforms
- apiVersion: tekton.dev/v1beta1
kind: TaskRun
name: pr-echo-platforms-2
pipelineTaskName: echo-platforms
provenance:
featureFlags:
RunningInEnvWithInjectedSidecars: true
EnableTektonOCIBundles: true
EnableAPIFields: "alpha"
AwaitSidecarReadiness: true
VerificationNoMatchPolicy: "ignore"
EnableProvenanceInStatus: true
ResultExtractionMethod: "termination-message"
MaxResultSize: 4096
`),
}}
for _, tt := range tests {
t.Run(tt.pName, func(t *testing.T) {
pr := parse.MustParseV1beta1PipelineRun(t, fmt.Sprintf(`
metadata:
name: pr
namespace: foo
spec:
serviceAccountName: test-sa
pipelineRef:
name: %s
`, tt.pName))
d := test.Data{
PipelineRuns: []*v1beta1.PipelineRun{pr},
Pipelines: []*v1beta1.Pipeline{tt.p},
Tasks: []*v1beta1.Task{task, taskwithresults},
ConfigMaps: cms,
}
if tt.tr != nil {
d.TaskRuns = []*v1beta1.TaskRun{tt.tr}
}
prt := newPipelineRunTest(t, d)
defer prt.Cancel()
pipelineRun, clients := prt.reconcileRun(pr.Namespace, pr.Name, []string{} /* wantEvents*/, false /* permanentError*/)
taskRuns := getTaskRunsForPipelineTask(prt.TestAssets.Ctx, t, clients, pr.Namespace, pr.Name, "echo-platforms")
validateTaskRunsCount(t, taskRuns, len(tt.expectedTaskRuns))
for _, expectedTaskRun := range tt.expectedTaskRuns {
trName := expectedTaskRun.Name
actual := getTaskRunByName(t, taskRuns, trName)
if d := cmp.Diff(expectedTaskRun, actual, ignoreResourceVersion, ignoreTypeMeta); d != "" {
t.Errorf("expected to see TaskRun %v created. Diff %s", expectedTaskRun.Name, diff.PrintWantGot(d))
}
}
if d := cmp.Diff(tt.expectedPipelineRun, pipelineRun, ignoreResourceVersion, ignoreTypeMeta, ignoreLastTransitionTime, ignoreStartTime, ignoreFinallyStartTime, cmpopts.EquateEmpty()); d != "" {
t.Errorf("expected PipelineRun was not created. Diff %s", diff.PrintWantGot(d))
}
})
}
}

Let me know if that answers your question/concern.

// TaskRun. The final validation is handled in skipBecauseResultReferencesAreMissing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: instead of passing in the pipelinerunState struct to ResolvePipelineTask, could we resolve the references right after we call ResolvedPipelineTask but before we append it to the pipelinerun state i.e. after line 379

resolvedResultRefs, _, _ := ResolveResultRefs(pst, PipelineRunState{&rpt})
if err := validateArrayResultsIndex(resolvedResultRefs); err != nil {
return nil, err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit (not a block for the PR): I think this line is not covered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this PR the coverage for ValidateArrayResultsIndex() exists within resolutionrefresolution_test.go.

func TestValidateArrayResultsIndex(t *testing.T) {

However I do have a pipelinerun.go unit test that covers an invalid array result index in the whole array results implementation https://github.com/tektoncd/pipeline/blob/c164f71ab448c4ac263d0113bf1b58d1c0199be3/pkg/reconciler/pipelinerun/pipelinerun_test.go#LL10603C6-L10603C66

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test in TestValidateArrayResultsIndex only tests the validateArrayResultsIndex but not tests the ResolvePipelineTask where we call the function.

The 2nd link makes sense! The validation happened in pipelinerun.go before but in this PR we moved it to the ResolvePipelineTask, I think it should be ok to rely on that test.

This line is red in the coverage report but I think that's fine.

}

ApplyTaskResults(PipelineRunState{&rpt}, resolvedResultRefs)

if rpt.PipelineTask.IsMatrixed() {
numCombinations = pipelineTask.Matrix.CountCombinations()
numCombinations = rpt.PipelineTask.Matrix.CountCombinations()
}
if rpt.IsCustomTask() {
rpt.CustomRunNames = getNamesOfCustomRuns(pipelineRun.Status.ChildReferences, pipelineTask.Name, pipelineRun.Name, numCombinations)
Expand Down Expand Up @@ -748,3 +759,28 @@ func (t *ResolvedPipelineTask) hasResultReferences() bool {
func isCustomRunCancelledByPipelineRunTimeout(cr *v1beta1.CustomRun) bool {
return cr.Spec.StatusMessage == v1beta1.CustomRunCancelledByPipelineTimeoutMsg
}

// CheckMissingResultReferences returns an error if it is missing any result references.
// Missing result references can occur if task fails to produce a result but has
// OnError: continue (ie TestMissingResultWhenStepErrorIsIgnored)
func CheckMissingResultReferences(pipelineRunState PipelineRunState, targets PipelineRunState) error {
for _, target := range targets {
for _, resultRef := range v1.PipelineTaskResultRefs(target.PipelineTask) {
referencedPipelineTask := pipelineRunState.ToMap()[resultRef.PipelineTask]
if referencedPipelineTask.IsCustomTask() {
customRun := referencedPipelineTask.CustomRuns[0]
_, err := findRunResultForParam(customRun, resultRef)
if err != nil {
return err
}
} else {
taskRun := referencedPipelineTask.TaskRuns[0]
_, err := findTaskResultForParam(taskRun, resultRef)
if err != nil {
return err
}
}
}
}
return nil
}
40 changes: 13 additions & 27 deletions pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2057,7 +2057,7 @@ func TestHasCustomRunsStarted(t *testing.T) {
}
}

func TestAreCustomRunsConditionStatusFalse(t *testing.T) {
func TestIsConditionStatusFalse(t *testing.T) {
for _, tc := range []struct {
name string
rpt ResolvedPipelineTask
Expand Down Expand Up @@ -2196,21 +2196,7 @@ func TestAreCustomRunsConditionStatusFalse(t *testing.T) {
CustomRuns: []*v1beta1.CustomRun{withCustomRunCancelled(newCustomRun(customRuns[0])), makeCustomRunStarted(customRuns[1])},
},
want: false,
}} {
t.Run(tc.name, func(t *testing.T) {
if got := tc.rpt.areCustomRunsConditionStatusFalse(); got != tc.want {
t.Errorf("expected areCustomRunsConditionStatusFalse: %t but got %t", tc.want, got)
}
})
}
}

func TestAreTaskRunsConditionStatusFalse(t *testing.T) {
for _, tc := range []struct {
name string
rpt ResolvedPipelineTask
want bool
}{{
}, {
name: "taskrun not started",
rpt: ResolvedPipelineTask{
PipelineTask: &v1.PipelineTask{Name: "task"},
Expand Down Expand Up @@ -2336,8 +2322,8 @@ func TestAreTaskRunsConditionStatusFalse(t *testing.T) {
want: false,
}} {
t.Run(tc.name, func(t *testing.T) {
if got := tc.rpt.areTaskRunsConditionStatusFalse(); got != tc.want {
t.Errorf("expected areTaskRunsConditionStatusFalse: %t but got %t", tc.want, got)
if got := tc.rpt.isConditionStatusFalse(); got != tc.want {
t.Errorf("expected isConditionStatusFalse: %t but got %t", tc.want, got)
}
})
}
Expand Down Expand Up @@ -2513,7 +2499,7 @@ func TestResolvePipelineRun_CustomTask(t *testing.T) {
cfg := config.NewStore(logtesting.TestLogger(t))
ctx = cfg.ToContext(ctx)
for _, task := range pts {
ps, err := ResolvePipelineTask(ctx, pr, nopGetTask, nopGetTaskRun, getRun, task)
ps, err := ResolvePipelineTask(ctx, pr, nopGetTask, nopGetTaskRun, getRun, task, nil)
if err != nil {
t.Fatalf("ResolvePipelineTask: %v", err)
}
Expand Down Expand Up @@ -2564,7 +2550,7 @@ func TestResolvePipelineRun_PipelineTaskHasNoResources(t *testing.T) {
}
pipelineState := PipelineRunState{}
for _, task := range pts {
ps, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, task)
ps, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, task, nil)
if err != nil {
t.Errorf("Error getting tasks for fake pipeline %s: %s", p.ObjectMeta.Name, err)
}
Expand Down Expand Up @@ -2615,7 +2601,7 @@ func TestResolvePipelineRun_TaskDoesntExist(t *testing.T) {
},
}
for _, pt := range pts {
_, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt)
_, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt, nil)
var tnf *TaskNotFoundError
switch {
case err == nil:
Expand Down Expand Up @@ -2655,7 +2641,7 @@ func TestResolvePipelineRun_VerificationFailed(t *testing.T) {
},
}
for _, pt := range pts {
rt, _ := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt)
rt, _ := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt, nil)
if d := cmp.Diff(verificationResult, rt.ResolvedTask.VerificationResult, cmpopts.EquateErrors()); d != "" {
t.Errorf(diff.PrintWantGot(d))
}
Expand Down Expand Up @@ -2899,7 +2885,7 @@ func TestResolvePipeline_WhenExpressions(t *testing.T) {
}

t.Run("When Expressions exist", func(t *testing.T) {
_, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt)
_, err := ResolvePipelineTask(context.Background(), pr, getTask, getTaskRun, nopGetCustomRun, pt, nil)
if err != nil {
t.Fatalf("Did not expect error when resolving PipelineRun: %v", err)
}
Expand Down Expand Up @@ -3001,7 +2987,7 @@ func TestIsCustomTask(t *testing.T) {
ctx := context.Background()
cfg := config.NewStore(logtesting.TestLogger(t))
ctx = cfg.ToContext(ctx)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt, nil)
if err != nil {
t.Fatalf("Did not expect error when resolving PipelineRun: %v", err)
}
Expand Down Expand Up @@ -3744,7 +3730,7 @@ func TestIsMatrixed(t *testing.T) {
},
})
ctx = cfg.ToContext(ctx)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt, nil)
if err != nil {
t.Fatalf("Did not expect error when resolving PipelineRun: %v", err)
}
Expand Down Expand Up @@ -3852,7 +3838,7 @@ func TestResolvePipelineRunTask_WithMatrix(t *testing.T) {
},
})
ctx = cfg.ToContext(ctx)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, getRun, tc.pt, nil)
if err != nil {
t.Fatalf("Did not expect error when resolving PipelineRun: %v", err)
}
Expand Down Expand Up @@ -3972,7 +3958,7 @@ func TestResolvePipelineRunTask_WithMatrixedCustomTask(t *testing.T) {
if tc.getRun == nil {
tc.getRun = getRun
}
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, tc.getRun, tc.pt)
rpt, err := ResolvePipelineTask(ctx, pr, getTask, getTaskRun, tc.getRun, tc.pt, nil)
if err != nil {
t.Fatalf("Did not expect error when resolving PipelineRun: %v", err)
}
Expand Down
23 changes: 16 additions & 7 deletions pkg/reconciler/pipelinerun/resources/resultrefresolution.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@ limitations under the License.
package resources

import (
"errors"
"fmt"
"sort"

v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
)

var (
// ErrInvalidTaskResultReference indicates that the reason for the failure status is that there
// is an invalid task result reference
ErrInvalidTaskResultReference = errors.New("Invalid task result reference")
)

// ResolvedResultRefs represents all of the ResolvedResultRef for a pipeline task
type ResolvedResultRefs []*ResolvedResultRef

Expand All @@ -43,7 +50,7 @@ func ResolveResultRef(pipelineRunState PipelineRunState, target *ResolvedPipelin
if err != nil {
return nil, pt, err
}
return validateArrayResultsIndex(removeDup(resolvedResultRefs))
return removeDup(resolvedResultRefs), "", nil
}

// ResolveResultRefs resolves any ResultReference that are found in the target ResolvedPipelineTask
Expand All @@ -56,19 +63,19 @@ func ResolveResultRefs(pipelineRunState PipelineRunState, targets PipelineRunSta
}
allResolvedResultRefs = append(allResolvedResultRefs, resolvedResultRefs...)
}
return validateArrayResultsIndex(removeDup(allResolvedResultRefs))
return removeDup(allResolvedResultRefs), "", nil
}

// validateArrayResultsIndex checks if the result array indexing reference is out of bound of the array size
func validateArrayResultsIndex(allResolvedResultRefs ResolvedResultRefs) (ResolvedResultRefs, string, error) {
func validateArrayResultsIndex(allResolvedResultRefs ResolvedResultRefs) error {
for _, r := range allResolvedResultRefs {
if r.Value.Type == v1.ParamTypeArray {
if r.ResultReference.ResultsIndex >= len(r.Value.ArrayVal) {
return nil, "", fmt.Errorf("Array Result Index %d for Task %s Result %s is out of bound of size %d", r.ResultReference.ResultsIndex, r.ResultReference.PipelineTask, r.ResultReference.Result, len(r.Value.ArrayVal))
return fmt.Errorf("Array Result Index %d for Task %s Result %s is out of bound of size %d", r.ResultReference.ResultsIndex, r.ResultReference.PipelineTask, r.ResultReference.Result, len(r.Value.ArrayVal))
}
}
}
return allResolvedResultRefs, "", nil
return nil
}

func removeDup(refs ResolvedResultRefs) ResolvedResultRefs {
Expand Down Expand Up @@ -168,7 +175,8 @@ func findRunResultForParam(customRun *v1beta1.CustomRun, reference *v1.ResultRef
return result.Value, nil
}
}
return "", fmt.Errorf("Could not find result with name %s for task %s", reference.Result, reference.PipelineTask)
err := fmt.Errorf("%w: Could not find result with name %s for task %s", ErrInvalidTaskResultReference, reference.Result, reference.PipelineTask)
return "", err
}

func findTaskResultForParam(taskRun *v1.TaskRun, reference *v1.ResultRef) (v1.ResultValue, error) {
Expand All @@ -178,7 +186,8 @@ func findTaskResultForParam(taskRun *v1.TaskRun, reference *v1.ResultRef) (v1.Re
return result.Value, nil
}
}
return v1.ResultValue{}, fmt.Errorf("Could not find result with name %s for task %s", reference.Result, reference.PipelineTask)
err := fmt.Errorf("%w: Could not find result with name %s for task %s", ErrInvalidTaskResultReference, reference.Result, reference.PipelineTask)
return v1.ResultValue{}, err
}

func (rs ResolvedResultRefs) getStringReplacements() map[string]string {
Expand Down
Loading