Use latestPipeline for commit list CI status badge
What does this MR do and why?
On a project's commits list, each commit shows a small CI status badge, a green check or a red X. That badge could show the wrong status.
The badge read the single newest pipeline of any kind, using the GraphQL pipelines(first: 1) field. That field includes pipelines that are not the commit's real CI run, such as security policy scans (security_orchestration_policy). If one of those scans ran after the real CI pipeline and passed, the badge showed a green check even though the commit's actual CI pipeline had failed. Users saw a passing badge on a commit that really failed.
This MR switches the badge to the Commit.latestPipeline GraphQL field. That field only considers real CI pipelines, using the ci_sources scope, and ignores scans and other non-CI pipelines. This makes the commits-list badge agree with the commit page, the commit status API field, and everywhere else that already ignores these non-CI pipelines.
Before: badge could show a passing security scan instead of a failed CI pipeline. After: badge always reflects the commit's actual CI pipeline.
latestPipeline takes a ref argument, so the badge still shows the pipeline for the branch you are viewing. A commit can have separate pipelines on different branches, and this keeps that per-branch behavior, added earlier in commit c416feed.
Bug report: #579690
Release sequencing (ships in 19.4)
- 19.2:
latestPipelinefield added (!243957 (merged)). - 19.3:
refargument added tolatestPipeline(!245748 (merged)). - 19.4: this MR, which is the frontend change that uses
ref.
This ships one release after the argument because of rolling upgrades. GitLab Self-Managed and Dedicated can run older and newer backend nodes at the same time during an upgrade. Shipping in 19.4 means every backend node during a 19.3-to-19.4 upgrade already has the ref argument, so the query works no matter which node answers it.
Why no @gl_introduced directive
@gl_introduced can hide a whole field from older backends, but it cannot hide a single argument. The new part here is the ref argument, not the field itself, so neither directive version is safe.
Version 19.2.0 would not hide the field on a 19.2 node, since that node lacks the ref argument. The query would fail there with an unknown-argument error. Version 19.3.0 would hide the field on a 19.2 node, but then the $pipelineRef variable is no longer used anywhere. GraphQL rejects the whole commits query for having an unused variable, so the entire list would fail to load, not just the badge.
Because of this, the fix relies on release sequencing, shipping in 19.4, instead of the directive.
Verifying against production data
Run this single query in the GraphQL explorer (or with POST /api/graphql). It returns both the new field (new: latestPipeline, what the badge now reads) and the old one (old: pipelines(first: 1)) for the same commits in one request, so the two are always directly comparable, with no drift between separate runs:
query compareBadgeSource($projectPath: ID!, $ref: String!, $pipelineRef: String, $first: Int) {
project(fullPath: $projectPath) {
id
repository {
commits(ref: $ref, first: $first) {
nodes {
sha
new: latestPipeline(ref: $pipelineRef) {
id
detailedStatus { icon text }
}
old: pipelines(first: 1, ref: $pipelineRef) {
nodes {
id
detailedStatus { icon text }
}
}
}
}
}
}
}Variables:
{
"projectPath": "gitlab-org/gitlab",
"ref": "master",
"pipelineRef": "master",
"first": 100
}How to read the result
- For almost every commit,
newmatchesold(same pipelineidand status), and both arenullor empty for commits with no pipeline of their own. This is expected. The two fields only differ when a commit's newest pipeline is a dangling source, such assecurity_orchestration_policy. For every other commit, theci_sourcesscope changes nothing. - A commit where
new.iddoes not equalold.nodes[0].id, or wherenewshows a CI status whileoldshows a green dangling scan, is a live instance of the bug in #579690. The badge previously showed the dangling pipeline and now shows the real CI status. - The bug is intermittent, so a small window may show no difference. Widen the search with
first: 100and page through withpageInfoandendCursor, or check a commit known to have a security policy scan withrepository { commit(ref: "<sha>") { new: latestPipeline { ... } old: pipelines(first: 1) { nodes { ... } } } }.
Related
- Field added (19.2): !243957 (merged)
refargument (19.3): !245748 (merged)- Per-branch resolution this preserves: commit c416feed
- Root-cause analysis: #579690
MR acceptance checklist
- Frontend unit spec updated (
commit_list_item_badges_spec.js), passing. - Regression feature spec added (
spec/features/commits_spec.rb): a newer dangling-source pipeline does not determine the commit badge status. - Milestone: 19.4.