Skip to content

Commit

Permalink
Propagate Pipeline name label to PipelineRun
Browse files Browse the repository at this point in the history
Currently, a `PipelineRun` started in a `Cancelled` or `Pending` state
doesn't receive the `Pipeline` name label.

As such, a user cannot find all the `PipelineRuns` related to a given
`Pipeline`. This is a challenge for a user searching for associated
`PipelineRuns` in `Pending` state in order to start them.

In this change, we ensure that the `Pipeline` name label is propagated
from the `Pipeline` to the `PipelineRun`.

Fixes #3903.
  • Loading branch information
jerop committed Aug 17, 2021
1 parent f0a2f00 commit e0373f4
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 16 deletions.
58 changes: 42 additions & 16 deletions pkg/reconciler/pipelinerun/pipelinerun.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ func (c *Reconciler) ReconcileKind(ctx context.Context, pr *v1beta1.PipelineRun)
return c.finishReconcileUpdateEmitEvents(ctx, pr, before, nil)
}

if err := propagatePipelineNameLabelToPipelineRun(pr); err != nil {
logger.Errorf("Failed to propagate pipeline name label to pipelinerun %s: %v", pr.Name, err)
return c.finishReconcileUpdateEmitEvents(ctx, pr, before, err)
}

// If the pipelinerun is cancelled, cancel tasks and update status
if pr.IsCancelled() {
err := cancelPipelineRun(ctx, logger, pr, c.PipelineClientSet)
Expand Down Expand Up @@ -344,22 +349,8 @@ func (c *Reconciler) reconcile(ctx context.Context, pr *v1beta1.PipelineRun, get
logger.Errorf("Failed to store PipelineSpec on PipelineRun.Status for pipelinerun %s: %v", pr.Name, err)
}

// Propagate labels from Pipeline to PipelineRun.
if pr.ObjectMeta.Labels == nil {
pr.ObjectMeta.Labels = make(map[string]string, len(pipelineMeta.Labels)+1)
}
for key, value := range pipelineMeta.Labels {
pr.ObjectMeta.Labels[key] = value
}
pr.ObjectMeta.Labels[pipeline.PipelineLabelKey] = pipelineMeta.Name

// Propagate annotations from Pipeline to PipelineRun.
if pr.ObjectMeta.Annotations == nil {
pr.ObjectMeta.Annotations = make(map[string]string, len(pipelineMeta.Annotations))
}
for key, value := range pipelineMeta.Annotations {
pr.ObjectMeta.Annotations[key] = value
}
propagateLabelsFromPipelineToPipelineRun(pr, pipelineMeta)
propagateAnnotationsFromPipelineToPipelineRun(pr, pipelineMeta)

d, err := dag.Build(v1beta1.PipelineTaskList(pipelineSpec.Tasks), v1beta1.PipelineTaskList(pipelineSpec.Tasks).Deps())
if err != nil {
Expand Down Expand Up @@ -931,6 +922,41 @@ func getTaskrunAnnotations(pr *v1beta1.PipelineRun) map[string]string {
return annotations
}

func propagatePipelineNameLabelToPipelineRun(pr *v1beta1.PipelineRun) error {
if pr.ObjectMeta.Labels == nil {
pr.ObjectMeta.Labels = make(map[string]string, 1)
}
switch {
case pr.Spec.PipelineRef != nil && pr.Spec.PipelineRef.Name != "":
pr.ObjectMeta.Labels[pipeline.PipelineLabelKey] = pr.Spec.PipelineRef.Name
case pr.Spec.PipelineSpec != nil:
pr.ObjectMeta.Labels[pipeline.PipelineLabelKey] = pr.Name
default:
return fmt.Errorf("pipelineRun %s not providing PipelineRef or PipelineSpec", pr.Name)
}
return nil
}

func propagateLabelsFromPipelineToPipelineRun(pr *v1beta1.PipelineRun, pipelineMeta *metav1.ObjectMeta) {
if pr.ObjectMeta.Labels == nil {
pr.ObjectMeta.Labels = make(map[string]string, len(pipelineMeta.Labels)+1)
}
for key, value := range pipelineMeta.Labels {
pr.ObjectMeta.Labels[key] = value
}
pr.ObjectMeta.Labels[pipeline.PipelineLabelKey] = pipelineMeta.Name
}

func propagateAnnotationsFromPipelineToPipelineRun(pr *v1beta1.PipelineRun, pipelineMeta *metav1.ObjectMeta) {
if pr.ObjectMeta.Annotations == nil {
pr.ObjectMeta.Annotations = make(map[string]string, len(pipelineMeta.Annotations))
}
for key, value := range pipelineMeta.Annotations {
pr.ObjectMeta.Annotations[key] = value
}

}

func getTaskrunLabels(pr *v1beta1.PipelineRun, pipelineTaskName string, includePipelineLabels bool) map[string]string {
// Propagate labels from PipelineRun to TaskRun.
labels := make(map[string]string, len(pr.ObjectMeta.Labels)+1)
Expand Down
88 changes: 88 additions & 0 deletions pkg/reconciler/pipelinerun/pipelinerun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2557,9 +2557,14 @@ func TestReconcileCancelledFailsTaskRunCancellation(t *testing.T) {
tb.PipelineRunStartTime(time.Now()),
),
)}
ps := []*v1beta1.Pipeline{tb.Pipeline("test-pipeline", tb.PipelineNamespace("foo"), tb.PipelineSpec(
tb.PipelineTask("hello-world-1", "hello-world"),
tb.PipelineTask("hello-world-2", "hello-world"),
))}

d := test.Data{
PipelineRuns: prs,
Pipelines: ps,
}

testAssets, cancel := getPipelineRunController(t, d)
Expand All @@ -2583,6 +2588,13 @@ func TestReconcileCancelledFailsTaskRunCancellation(t *testing.T) {
t.Fatalf("Somehow had error getting reconciled run out of fake client: %s", err)
}

if val, ok := reconciledRun.GetLabels()[pipeline.PipelineLabelKey]; !ok {
t.Fatalf("expected pipeline label")
if d := cmp.Diff("test-pipelines", val); d != "" {
t.Errorf("expected to see pipeline label. Diff %s", diff.PrintWantGot(d))
}
}

// The PipelineRun should not be cancelled b/c we couldn't cancel the TaskRun
condition := reconciledRun.Status.GetCondition(apis.ConditionSucceeded)
if !condition.IsUnknown() {
Expand Down Expand Up @@ -2701,6 +2713,82 @@ func TestReconcilePropagateLabels(t *testing.T) {
}
}

func TestReconcilePropagateLabelsPending(t *testing.T) {
names.TestingSeed()
taskName := "hello-world-1"

ps := []*v1beta1.Pipeline{tb.Pipeline("test-pipeline", tb.PipelineNamespace("foo"), tb.PipelineSpec(
tb.PipelineTask(taskName, "hello-world"),
))}
prs := []*v1beta1.PipelineRun{tb.PipelineRun("test-pipeline-run-with-labels", tb.PipelineRunNamespace("foo"),
tb.PipelineRunLabel("PipelineRunLabel", "PipelineRunValue"),
tb.PipelineRunSpec("test-pipeline",
tb.PipelineRunServiceAccountName("test-sa"),
tb.PipelineRunPending,
),
)}
ts := []*v1beta1.Task{tb.Task("hello-world", tb.TaskNamespace("foo"))}

d := test.Data{
PipelineRuns: prs,
Pipelines: ps,
Tasks: ts,
}
prt := newPipelineRunTest(d, t)
defer prt.Cancel()

_, clients := prt.reconcileRun("foo", "test-pipeline-run-with-labels", []string{}, false)

reconciledRun, err := clients.Pipeline.TektonV1beta1().PipelineRuns("foo").Get(prt.TestAssets.Ctx, "test-pipeline-run-with-labels", metav1.GetOptions{})
if err != nil {
t.Fatalf("unexpected error when updating status: %v", err)
}

want := "test-pipeline"
got := reconciledRun.ObjectMeta.Labels["tekton.dev/pipeline"]
if d := cmp.Diff(want, got); d != "" {
t.Errorf("expected to see label %v created. Diff %s", want, diff.PrintWantGot(d))
}
}

func TestReconcilePropagateLabelsCancelled(t *testing.T) {
names.TestingSeed()
taskName := "hello-world-1"

ps := []*v1beta1.Pipeline{tb.Pipeline("test-pipeline", tb.PipelineNamespace("foo"), tb.PipelineSpec(
tb.PipelineTask(taskName, "hello-world"),
))}
prs := []*v1beta1.PipelineRun{tb.PipelineRun("test-pipeline-run-with-labels", tb.PipelineRunNamespace("foo"),
tb.PipelineRunLabel("PipelineRunLabel", "PipelineRunValue"),
tb.PipelineRunSpec("test-pipeline",
tb.PipelineRunServiceAccountName("test-sa"),
tb.PipelineRunCancelled,
),
)}
ts := []*v1beta1.Task{tb.Task("hello-world", tb.TaskNamespace("foo"))}

d := test.Data{
PipelineRuns: prs,
Pipelines: ps,
Tasks: ts,
}
prt := newPipelineRunTest(d, t)
defer prt.Cancel()

_, clients := prt.reconcileRun("foo", "test-pipeline-run-with-labels", []string{}, false)

reconciledRun, err := clients.Pipeline.TektonV1beta1().PipelineRuns("foo").Get(prt.TestAssets.Ctx, "test-pipeline-run-with-labels", metav1.GetOptions{})
if err != nil {
t.Fatalf("unexpected error when updating status: %v", err)
}

want := "test-pipeline"
got := reconciledRun.ObjectMeta.Labels["tekton.dev/pipeline"]
if d := cmp.Diff(want, got); d != "" {
t.Errorf("expected to see label %v created. Diff %s", want, diff.PrintWantGot(d))
}
}

func TestReconcileWithDifferentServiceAccounts(t *testing.T) {
names.TestingSeed()

Expand Down

0 comments on commit e0373f4

Please sign in to comment.