diff --git a/pkg/apis/pipeline/v1alpha1/run_types.go b/pkg/apis/pipeline/v1alpha1/run_types.go index 74e3e0b09dc..4d7e1a94c27 100644 --- a/pkg/apis/pipeline/v1alpha1/run_types.go +++ b/pkg/apis/pipeline/v1alpha1/run_types.go @@ -201,7 +201,7 @@ func (r *Run) HasStarted() bool { // IsSuccessful returns true if the Run's status indicates that it is done. func (r *Run) IsSuccessful() bool { - return r.Status.GetCondition(apis.ConditionSucceeded).IsTrue() + return r != nil && r.Status.GetCondition(apis.ConditionSucceeded).IsTrue() } // GetRunKey return the run's key for timeout handler map diff --git a/pkg/apis/pipeline/v1beta1/taskrun_types.go b/pkg/apis/pipeline/v1beta1/taskrun_types.go index 1bb1dea40ac..03e98bec971 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_types.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_types.go @@ -414,7 +414,7 @@ func (tr *TaskRun) HasStarted() bool { // IsSuccessful returns true if the TaskRun's status indicates that it is done. func (tr *TaskRun) IsSuccessful() bool { - return tr.Status.GetCondition(apis.ConditionSucceeded).IsTrue() + return tr != nil && tr.Status.GetCondition(apis.ConditionSucceeded).IsTrue() } // IsCancelled returns true if the TaskRun's spec status is set to Cancelled state diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index 6667cf2d5c3..e6483802611 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -100,11 +100,24 @@ func (t ResolvedPipelineRunTask) IsMatrixed() bool { } // isSuccessful returns true only if the run has completed successfully +// If the PipelineTask has a Matrix, isSuccessful returns true if all runs have completed successfully func (t ResolvedPipelineRunTask) isSuccessful() bool { - if t.IsCustomTask() { - return t.Run != nil && t.Run.IsSuccessful() + switch { + case t.IsCustomTask(): + return t.Run.IsSuccessful() + case t.IsMatrixed(): + if len(t.TaskRuns) == 0 { + return false + } + for _, taskRun := range t.TaskRuns { + if !taskRun.IsSuccessful() { + return false + } + } + return true + default: + return t.TaskRun.IsSuccessful() } - return t.TaskRun != nil && t.TaskRun.IsSuccessful() } // isFailure returns true only if the run has failed and will not be retried. diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index f4c464bed7c..9087d85adfd 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go @@ -3159,6 +3159,131 @@ func TestIsSuccessful(t *testing.T) { CustomTask: true, }, want: false, + }, { + name: "matrixed taskruns not started", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + }, + want: false, + }, { + name: "matrixed taskruns running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeStarted(trs[0]), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "one matrixed taskrun running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeStarted(trs[0]), makeSucceeded(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns succeeded", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeSucceeded(trs[0]), makeSucceeded(trs[1])}, + }, + want: true, + }, { + name: "one matrixed taskrun succeeded", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeSucceeded(trs[0]), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns failed", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeFailed(trs[0]), makeFailed(trs[1])}, + }, + want: false, + }, { + name: "one matrixed taskrun failed, one matrixed taskrun running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{makeFailed(trs[0]), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns failed: retries remaining", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{makeFailed(trs[0]), makeFailed(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns failed: one taskrun with retries remaining", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{makeFailed(trs[0]), withRetries(makeFailed(trs[1]))}, + }, + want: false, + }, { + name: "matrixed taskruns failed: no retries remaining", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{withRetries(makeFailed(trs[0])), withRetries(makeFailed(trs[1]))}, + }, + want: false, + }, { + name: "matrixed taskruns cancelled", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{withCancelled(makeFailed(trs[0])), withCancelled(makeFailed(trs[1]))}, + }, + want: false, + }, { + name: "one matrixed taskrun cancelled, one matrixed taskrun running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{withCancelled(makeFailed(trs[0])), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns cancelled but not failed", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{withCancelled(newTaskRun(trs[0])), withCancelled(newTaskRun(trs[1]))}, + }, + want: false, + }, { + name: "one matrixed taskrun cancelled but not failed", + rprt: ResolvedPipelineRunTask{ + PipelineTask: matrixedPipelineTask, + TaskRuns: []*v1beta1.TaskRun{withCancelled(newTaskRun(trs[0])), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns cancelled: retries remaining", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{withCancelled(makeFailed(trs[0])), withCancelled(makeFailed(trs[1]))}, + }, + want: false, + }, { + name: "one matrixed taskrun cancelled: retries remaining, one matrixed taskrun running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{withCancelled(makeFailed(trs[0])), makeStarted(trs[1])}, + }, + want: false, + }, { + name: "matrixed taskruns cancelled: no retries remaining", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{withCancelled(withRetries(makeFailed(trs[0]))), withCancelled(withRetries(makeFailed(trs[1])))}, + }, + want: false, + }, { + name: "one matrixed taskrun cancelled: no retries remaining, one matrixed taskrun running", + rprt: ResolvedPipelineRunTask{ + PipelineTask: withPipelineTaskRetries(*matrixedPipelineTask, 1), + TaskRuns: []*v1beta1.TaskRun{withCancelled(withRetries(makeFailed(trs[0]))), makeStarted(trs[1])}, + }, + want: false, }} { t.Run(tc.name, func(t *testing.T) { if got := tc.rprt.isSuccessful(); got != tc.want {