Skip to content

Commit c139528

Browse files
committed
feat: support PipelineRun running status reporting on Github with Kueue
this adds support running status of the PipelineRun when PipelineRuns are managed by Kueue. https://issues.redhat.com/browse/SRVKP-7738 Signed-off-by: Zaki Shaikh <[email protected]>
1 parent bca681c commit c139528

File tree

4 files changed

+104
-16
lines changed

4 files changed

+104
-16
lines changed

pkg/pipelineascode/pipelineascode.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/openshift-pipelines/pipelines-as-code/pkg/kubeinteraction"
1515
"github.com/openshift-pipelines/pipelines-as-code/pkg/matcher"
1616
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
17-
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
1817
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
1918
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
2019
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/triggertype"
@@ -241,12 +240,23 @@ func (p *PacRun) startPR(ctx context.Context, match matcher.Match) (*tektonv1.Pi
241240
OriginalPipelineRunName: pr.GetAnnotations()[keys.OriginalPRName],
242241
}
243242

243+
patchAnnotations := map[string]string{}
244+
patchLabels := map[string]string{}
245+
whatPatching := ""
244246
// if pipelineRun is in pending state then report status as queued
245247
if pr.Spec.Status == tektonv1.PipelineRunSpecStatusPending {
246248
status.Status = queuedStatus
247249
if status.Text, err = mt.MakeTemplate(p.vcx.GetTemplate(provider.QueueingPipelineType)); err != nil {
248250
return nil, fmt.Errorf("cannot create message template: %w", err)
249251
}
252+
// If the PipelineRun is in the "queued" state, add the appropriate label and annotation.
253+
// These are later used by the watcher to determine whether the PipelineRun status
254+
// should be reported back to the Git provider. We do add the `state` annotations and label when
255+
// concurrency is enabled but this would happen when PipelineRun's status has been changed by
256+
// the other controller and PaC is not aware of that change.
257+
whatPatching = "annotations.state and labels.state"
258+
patchAnnotations[keys.State] = kubeinteraction.StateQueued
259+
patchLabels[keys.State] = kubeinteraction.StateQueued
250260
}
251261

252262
if err := p.vcx.CreateStatus(ctx, p.event, status); err != nil {
@@ -257,7 +267,12 @@ func (p *PacRun) startPR(ctx context.Context, match matcher.Match) (*tektonv1.Pi
257267

258268
// Patch pipelineRun with logURL annotation, skips for GitHub App as we patch logURL while patching CheckrunID
259269
if _, ok := pr.Annotations[keys.InstallationID]; !ok {
260-
pr, err = action.PatchPipelineRun(ctx, p.logger, "logURL", p.run.Clients.Tekton, pr, getLogURLMergePatch(p.run.Clients, pr))
270+
patchAnnotations[keys.LogURL] = p.run.Clients.ConsoleUI().DetailURL(pr)
271+
whatPatching = "annotations.logURL" + whatPatching
272+
}
273+
274+
if len(patchAnnotations) > 0 || len(patchLabels) > 0 {
275+
pr, err = action.PatchPipelineRun(ctx, p.logger, whatPatching, p.run.Clients.Tekton, pr, getMergePatch(patchAnnotations, patchLabels))
261276
if err != nil {
262277
// we still return the created PR with error, and allow caller to decide what to do with the PR, and avoid
263278
// unneeded SIGSEGV's
@@ -268,12 +283,11 @@ func (p *PacRun) startPR(ctx context.Context, match matcher.Match) (*tektonv1.Pi
268283
return pr, nil
269284
}
270285

271-
func getLogURLMergePatch(clients clients.Clients, pr *tektonv1.PipelineRun) map[string]any {
286+
func getMergePatch(annotations, labels map[string]string) map[string]any {
272287
return map[string]any{
273288
"metadata": map[string]any{
274-
"annotations": map[string]string{
275-
keys.LogURL: clients.ConsoleUI().DetailURL(pr),
276-
},
289+
"annotations": annotations,
290+
"labels": labels,
277291
},
278292
}
279293
}

pkg/pipelineascode/pipelineascode_test.go

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,49 @@ func TestRun(t *testing.T) {
497497
finalStatusText: "User fantasio is not allowed to trigger CI by GitOps comment on push commit in this repo.",
498498
skipReplyingOrgPublicMembers: true,
499499
},
500+
{
501+
name: "pull request/pipelinerun created in pending state (state changed by other controller)",
502+
runevent: info.Event{
503+
Event: &github.PullRequestEvent{
504+
PullRequest: &github.PullRequest{
505+
Number: github.Ptr(666),
506+
},
507+
},
508+
SHA: "fromwebhook",
509+
Organization: "owner",
510+
Sender: "owner",
511+
Repository: "repo",
512+
URL: "https://service/documentation",
513+
HeadBranch: "press",
514+
BaseBranch: "main",
515+
EventType: "pull_request",
516+
TriggerTarget: "pull_request",
517+
PullRequestNumber: 666,
518+
InstallationID: 1234,
519+
},
520+
tektondir: "testdata/pending_pipelinerun",
521+
},
522+
{
523+
name: "pull request/pipelinerun created in pending state without installationID (state changed by other controller)",
524+
runevent: info.Event{
525+
Event: &github.PullRequestEvent{
526+
PullRequest: &github.PullRequest{
527+
Number: github.Ptr(666),
528+
},
529+
},
530+
SHA: "fromwebhook",
531+
Organization: "owner",
532+
Sender: "owner",
533+
Repository: "repo",
534+
URL: "https://service/documentation",
535+
HeadBranch: "press",
536+
BaseBranch: "main",
537+
EventType: "pull_request",
538+
TriggerTarget: "pull_request",
539+
PullRequestNumber: 666,
540+
},
541+
tektondir: "testdata/pending_pipelinerun",
542+
},
500543
}
501544
for _, tt := range tests {
502545
t.Run(tt.name, func(t *testing.T) {
@@ -675,10 +718,10 @@ func TestRun(t *testing.T) {
675718
secretName, ok := pr.GetAnnotations()[keys.GitAuthSecret]
676719
assert.Assert(t, ok, "Cannot find secret %s on annotations", secretName)
677720
}
678-
if tt.concurrencyLimit > 0 {
679-
concurrencyLimit, ok := pr.GetAnnotations()[keys.State]
680-
assert.Assert(t, ok, "State hasn't been set on PR", concurrencyLimit)
681-
assert.Equal(t, concurrencyLimit, kubeinteraction.StateQueued)
721+
if tt.concurrencyLimit > 0 || pr.Spec.Status == pipelinev1.PipelineRunSpecStatusPending {
722+
state, ok := pr.GetAnnotations()[keys.State]
723+
assert.Assert(t, ok, "State hasn't been set on PR", state)
724+
assert.Equal(t, state, kubeinteraction.StateQueued)
682725
}
683726
}
684727
}
@@ -690,12 +733,8 @@ func TestGetLogURLMergePatch(t *testing.T) {
690733
con := consoleui.FallBackConsole{}
691734
clients := clients.Clients{}
692735
clients.SetConsoleUI(con)
693-
pr := &pipelinev1.PipelineRun{
694-
ObjectMeta: metav1.ObjectMeta{
695-
Name: "test-pipeline-run",
696-
},
697-
}
698-
result := getLogURLMergePatch(clients, pr)
736+
ann := map[string]string{keys.LogURL: con.URL()}
737+
result := getMergePatch(ann, map[string]string{})
699738
m, ok := result["metadata"].(map[string]any)
700739
assert.Assert(t, ok)
701740
a, ok := m["annotations"].(map[string]string)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
apiVersion: tekton.dev/v1beta1
2+
kind: PipelineRun
3+
metadata:
4+
generateName: pull_request-test1
5+
annotations:
6+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
7+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
8+
spec:
9+
status: PipelineRunPending
10+
pipelineSpec:
11+
tasks:
12+
- name: max
13+
taskSpec:
14+
steps:
15+
- name: success
16+
image: registry.access.redhat.com/ubi9/ubi-minimal
17+
script: 'exit 0'

pkg/reconciler/reconciler.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, pr *tektonv1.PipelineRun
6060
return nil
6161
}
6262

63+
reason := ""
64+
if len(pr.Status.GetConditions()) > 0 {
65+
reason = pr.Status.GetConditions()[0].GetReason()
66+
}
67+
// This condition handles cases where the PipelineRun has entered a "Running" state,
68+
// but its status in the Git provider remains "queued" (e.g., due to updates made by
69+
// another controller outside PaC). To maintain consistency between the PipelineRun
70+
// status and the Git provider status, we update both the PipelineRun resource and
71+
// the corresponding status on the Git provider here.
72+
if reason == string(tektonv1.PipelineRunReasonRunning) && state == kubeinteraction.StateQueued {
73+
repoName := pr.GetAnnotations()[keys.Repository]
74+
repo, err := r.repoLister.Repositories(pr.Namespace).Get(repoName)
75+
if err != nil {
76+
return fmt.Errorf("failed to get repository CR: %w", err)
77+
}
78+
return r.updatePipelineRunToInProgress(ctx, logger, repo, pr)
79+
}
80+
6381
// if its a GitHub App pipelineRun PR then process only if check run id is added otherwise wait
6482
if _, ok := pr.Annotations[keys.InstallationID]; ok {
6583
if _, ok := pr.Annotations[keys.CheckRunID]; !ok {

0 commit comments

Comments
 (0)