Skip to content

Commit 5cd2740

Browse files
committed
fix(gitlab): pin commit statuses to same pipeline
When PAC posts multiple commit statuses for the same SHA, GitLab's auto-assignment logic can route them to different pipelines, leaving the MR pipeline permanently stuck with stale intermediate statuses. Cache the pipeline_id returned by the first SetCommitStatus response and pass it on subsequent calls for the same (project, SHA) pair so all statuses land in the same GitLab pipeline. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Abhishek Ghosh <abghosh@redhat.com>
1 parent 5c09648 commit 5cd2740

4 files changed

Lines changed: 518 additions & 62 deletions

File tree

pkg/apis/pipelinesascode/keys/keys.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848
OriginalPRName = pipelinesascode.GroupName + "/original-prname"
4949
GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret"
5050
CheckRunID = pipelinesascode.GroupName + "/check-run-id"
51+
GitLabPipelineID = pipelinesascode.GroupName + "/gitlab-pipeline-id"
5152
OnEvent = pipelinesascode.GroupName + "/on-event"
5253
OnComment = pipelinesascode.GroupName + "/on-comment"
5354
OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch"

pkg/provider/gitlab/gitlab.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"strconv"
1313
"strings"
1414

15+
"github.com/openshift-pipelines/pipelines-as-code/pkg/action"
16+
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
1517
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
1618
"github.com/openshift-pipelines/pipelines-as-code/pkg/changedfiles"
1719
"github.com/openshift-pipelines/pipelines-as-code/pkg/events"
@@ -69,6 +71,7 @@ type Provider struct {
6971
memberCache map[int64]bool
7072
cachedChangedFiles *changedfiles.ChangedFiles
7173
pacUserID int64 // user login used by PAC
74+
pipelineID int64
7275
}
7376

7477
var defaultGitlabListOptions = gitlab.ListOptions{
@@ -354,22 +357,39 @@ func (v *Provider) CreateStatus(ctx context.Context, event *info.Event, statusOp
354357
Context: gitlab.Ptr(contextName),
355358
}
356359

360+
// Reuse a previously discovered pipeline ID so that all commit statuses
361+
// for the same SHA land in the same GitLab pipeline.
362+
if statusOpts.PipelineRun != nil {
363+
if id, ok := statusOpts.PipelineRun.GetAnnotations()[keys.GitLabPipelineID]; ok {
364+
pid, err := strconv.ParseInt(id, 10, 64)
365+
if err == nil {
366+
opt.PipelineID = gitlab.Ptr(pid)
367+
v.pipelineID = pid
368+
}
369+
}
370+
}
371+
if opt.PipelineID == nil && v.pipelineID != 0 {
372+
opt.PipelineID = gitlab.Ptr(v.pipelineID)
373+
}
374+
357375
// In case we have access, set the status. Typically, on a Merge Request (MR)
358376
// from a fork in an upstream repository, the token needs to have write access
359377
// to the fork repository in order to create a status. However, the token set on the
360378
// Repository CR usually doesn't have such broad access, preventing from creating
361379
// a status comment on it.
362380
// This would work on a push or an MR from a branch within the same repo.
363381
// Ignoring errors because of the write access issues,
364-
_, _, err := v.Client().Commits.SetCommitStatus(event.SourceProjectID, event.SHA, opt)
382+
commitStatus, _, err := v.Client().Commits.SetCommitStatus(event.SourceProjectID, event.SHA, opt)
365383
if err != nil {
366384
v.Logger.Debugf("cannot set status with the GitLab token on the source project: %v", err)
367385
} else {
386+
v.storePipelineID(ctx, statusOpts, commitStatus.PipelineID)
368387
// we managed to set the status on the source repo, all good we are done
369388
v.Logger.Debugf("created commit status on source project ID %d", event.TargetProjectID)
370389
return nil
371390
}
372-
if _, _, err = v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt); err == nil {
391+
if commitStatus, _, err = v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt); err == nil {
392+
v.storePipelineID(ctx, statusOpts, commitStatus.PipelineID)
373393
v.Logger.Debugf("created commit status on target project ID %d", event.TargetProjectID)
374394
// we managed to set the status on the target repo, all good we are done
375395
return nil
@@ -860,3 +880,35 @@ func (v *Provider) formatPipelineComment(sha string, status providerstatus.Statu
860880
return fmt.Sprintf("%s **%s: %s/%s for %s**\n\n%s\n\n<small>Full log available [here](%s)</small>",
861881
emoji, status.Title, v.pacInfo.ApplicationName, status.OriginalPipelineRunName, sha, status.Text, status.DetailsURL)
862882
}
883+
884+
// storePipelineID caches the pipeline ID from a successful SetCommitStatus
885+
// response and patches it onto the PipelineRun annotation for the reconciler.
886+
func (v *Provider) storePipelineID(ctx context.Context, statusOpts providerstatus.StatusOpts, pipelineID int64) {
887+
if pipelineID == 0 {
888+
return
889+
}
890+
v.pipelineID = pipelineID
891+
v.patchPipelineIDAnnotation(ctx, statusOpts, pipelineID)
892+
}
893+
894+
// patchPipelineIDAnnotation stores the GitLab pipeline ID as a PipelineRun
895+
// annotation so the reconciler can read it back across Provider instances.
896+
func (v *Provider) patchPipelineIDAnnotation(ctx context.Context, statusOpts providerstatus.StatusOpts, pipelineID int64) {
897+
pr := statusOpts.PipelineRun
898+
if pr == nil || (pr.GetName() == "" && pr.GetGenerateName() == "") {
899+
return
900+
}
901+
if _, ok := pr.GetAnnotations()[keys.GitLabPipelineID]; ok {
902+
return
903+
}
904+
mergePatch := map[string]any{
905+
"metadata": map[string]any{
906+
"annotations": map[string]string{
907+
keys.GitLabPipelineID: strconv.FormatInt(pipelineID, 10),
908+
},
909+
},
910+
}
911+
if _, err := action.PatchPipelineRun(ctx, v.Logger, "gitlabPipelineID", v.run.Clients.Tekton, pr, mergePatch); err != nil {
912+
v.Logger.Debugf("failed to patch pipelinerun with gitlab pipeline ID: %v", err)
913+
}
914+
}

0 commit comments

Comments
 (0)