Skip to content
Open
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
1 change: 1 addition & 0 deletions pkg/apis/pipelinesascode/keys/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
OriginalPRName = pipelinesascode.GroupName + "/original-prname"
GitAuthSecret = pipelinesascode.GroupName + "/git-auth-secret"
CheckRunID = pipelinesascode.GroupName + "/check-run-id"
GitLabPipelineID = pipelinesascode.GroupName + "/gitlab-pipeline-id"
OnEvent = pipelinesascode.GroupName + "/on-event"
OnComment = pipelinesascode.GroupName + "/on-comment"
OnTargetBranch = pipelinesascode.GroupName + "/on-target-branch"
Expand Down
55 changes: 53 additions & 2 deletions pkg/provider/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"strconv"
"strings"

"github.com/openshift-pipelines/pipelines-as-code/pkg/action"
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
"github.com/openshift-pipelines/pipelines-as-code/pkg/changedfiles"
"github.com/openshift-pipelines/pipelines-as-code/pkg/events"
Expand Down Expand Up @@ -354,22 +356,42 @@ func (v *Provider) CreateStatus(ctx context.Context, event *info.Event, statusOp
Context: gitlab.Ptr(contextName),
}

// Read a previously stored pipeline ID from PipelineRun annotations so
// that all commit statuses land in the same GitLab pipeline instead of
// GitLab potentially auto-creating a new "external" pipeline mid-stream.
if statusOpts.PipelineRun != nil {
if id, ok := statusOpts.PipelineRun.GetAnnotations()[keys.GitLabPipelineID]; ok {
pid, err := strconv.ParseInt(id, 10, 64)
if err == nil {
opt.PipelineID = gitlab.Ptr(pid)
}
}
}

// In case we have access, set the status. Typically, on a Merge Request (MR)
// from a fork in an upstream repository, the token needs to have write access
// to the fork repository in order to create a status. However, the token set on the
// Repository CR usually doesn't have such broad access, preventing from creating
// a status comment on it.
// This would work on a push or an MR from a branch within the same repo.
// Ignoring errors because of the write access issues,
_, _, err := v.Client().Commits.SetCommitStatus(event.SourceProjectID, event.SHA, opt)
commitStatus, _, err := v.Client().Commits.SetCommitStatus(event.SourceProjectID, event.SHA, opt)
if err != nil {
v.Logger.Debugf("cannot set status with the GitLab token on the source project: %v", err)
} else {
v.patchPipelineIDAnnotation(ctx, statusOpts, commitStatus)
// we managed to set the status on the source repo, all good we are done
v.Logger.Debugf("created commit status on source project ID %d", event.TargetProjectID)
return nil
}
if _, _, err = v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt); err == nil {
// Clear pipeline ID when falling back to the target project โ€” the cached
// ID belongs to the source project's pipeline namespace and is invalid on
// a different project (fork MR scenario).
if event.SourceProjectID != event.TargetProjectID {
opt.PipelineID = nil
}
if commitStatus, _, err = v.Client().Commits.SetCommitStatus(event.TargetProjectID, event.SHA, opt); err == nil {
v.patchPipelineIDAnnotation(ctx, statusOpts, commitStatus)
v.Logger.Debugf("created commit status on target project ID %d", event.TargetProjectID)
// we managed to set the status on the target repo, all good we are done
return nil
Expand Down Expand Up @@ -860,3 +882,32 @@ func (v *Provider) formatPipelineComment(sha string, status providerstatus.Statu
return fmt.Sprintf("%s **%s: %s/%s for %s**\n\n%s\n\n<small>Full log available [here](%s)</small>",
emoji, status.Title, v.pacInfo.ApplicationName, status.OriginalPipelineRunName, sha, status.Text, status.DetailsURL)
}

// patchPipelineIDAnnotation stores the GitLab pipeline ID from a successful
// SetCommitStatus response as a PipelineRun annotation. This allows the
// reconciler (which creates a new Provider instance) to read it back and
// pass it on subsequent status updates, keeping all statuses in the same
// GitLab pipeline.
func (v *Provider) patchPipelineIDAnnotation(ctx context.Context, statusOpts providerstatus.StatusOpts, cs *gitlab.CommitStatus) {
if cs == nil || cs.PipelineID == 0 {
return
}
pr := statusOpts.PipelineRun
if pr == nil || (pr.GetName() == "" && pr.GetGenerateName() == "") {
return
}
// Skip if annotation is already set โ€” avoid unnecessary patches.
if _, ok := pr.GetAnnotations()[keys.GitLabPipelineID]; ok {
return
}
mergePatch := map[string]any{
"metadata": map[string]any{
"annotations": map[string]string{
keys.GitLabPipelineID: strconv.FormatInt(cs.PipelineID, 10),
},
},
}
if _, err := action.PatchPipelineRun(ctx, v.Logger, "gitlabPipelineID", v.run.Clients.Tekton, pr, mergePatch); err != nil {
v.Logger.Debugf("failed to patch pipelinerun with gitlab pipeline ID: %v", err)
}
}
Loading
Loading
โšก