fix: keep pipeline stages and jobs in place when a job is retried

Description

When a job is retried, the pipeline tree in the sidebar moves it: the job goes to the end of its stage, and once every job of a stage has been retried (a stage with a single job, for example), the whole stage drops below the stages that came after it.

The tree orders stages and jobs by job ID (PipelineItemModel.getChildren, since 7b0c4fb8 "fix: ci stages not correctly sorted"). The jobs GitLab creates with a pipeline get their IDs stage by stage, so the IDs give the right order until a job is retried: the retry is a new job with a higher ID, and the pipeline jobs endpoint leaves the older attempts out by default, so nothing the tree receives says where the retried job used to be.

This MR, in three commits:

  1. Adds tests for what the next two commits change: what getJobsForPipeline requests and returns, and the order of the jobs inside a stage.
  2. getJobsForPipeline asks the endpoint for the retried attempts too (include_retried=true), keeps the latest attempt of each job and sets firstAttemptId on a job that was retried. When GitLab adds a job, it marks every older job with the same name in the pipeline as retried (CommitStatus#update_older_statuses_retried!), so the attempt with the highest ID is the one the endpoint returns without the parameter. Callers get the same jobs as before, in the same order.
  3. PipelineItemModel orders stages and jobs by firstAttemptId ?? id instead of id. A pipeline in which no job was retried shows exactly as before.

firstAttemptId is an optional field on RestJob that the API does not return; its comment says so. I kept the ordering on the REST data the tree already uses: the GraphQL API lists stages in order, but that would be another request on every refresh, and it sorts the jobs inside a stage by status or name rather than in the order the pipeline created them.

Two things this does not change:

  • Trigger jobs come from the bridges endpoint, which does not document include_retried, so a retried trigger job still moves to the end of its stage, as it does today, and a stage that holds only trigger jobs still drops below the later stages once all of them have been retried.
  • The jobs request now also returns the retried attempts, so a pipeline with retries returns more jobs (23 instead of 21 for the pipeline below).

Closes #2346 (closed)

How has this been tested?

  • Everything ran in node:22.20.0, the image CI uses. On each of the three commits: npm run test:unit (291 suites, all passing), tsc -p . --noEmit, and ESLint and Prettier on the files the commit changes. The tests the second commit adds or changes fail on the first, and the tests the third commit adds fail on the second.
  • At the last commit also: npm run lint, npm run test:integration set up as the test-integration job does (60 passing, 1 pending), and scripts/commit-lint/lint.js over the three commits and over the title.
  • I replayed a real pipeline of this project, 2932293056, where test-e2e-windows ran three times: I fed the two answers gitlab.com gave for its jobs, with and without include_retried, through getJobsForPipeline and PipelineItemModel before and after this MR. Before, test-e2e-windows is listed last in the test stage; after, it is back between test-integration-web and test-webview, where it was created. In both runs the service returned the same 21 jobs in the same order.
  • src/browser and src/common are not modified.
Replay of pipeline 2932293056, before and after
-requested: https://gitlab.example.com/api/v4/projects/5261717/pipelines/2932293056/jobs
+requested: https://gitlab.example.com/api/v4/projects/5261717/pipelines/2932293056/jobs?include_retried=true
 jobs: 21
 same IDs, in the same order, as the default listing: true
 stage .pre
   no-squash-with-tags
 stage application-security-testing
   dependency-scanning-profile-0
 stage test
   gitlab-advanced-sast
   gemnasium-dependency_scanning
   secret_detection
   package-lock-integrity
   check-docs-markdown
   lint
   check-ci-variables
   test-unit
   test-integration
   test-integration-web
+  test-e2e-windows
   test-webview
   test-webview2
   test-browser-build
   test-e2e
   test-e2e-chat
-  test-e2e-windows
 stage package
   package-test
 stage publish
   publish-pre-release::manual
   publish-release::manual

The three attempts of test-e2e-windows in that pipeline are jobs 17073671958 and 17073857334 (retried) and 17074030283 (latest); the jobs created with the pipeline run from 17073671946 to 17073671966.

Screenshots (if appropriate)

What CHANGELOG entry will this MR create?

  • fix: Bug fix fixes - a user-facing issue in production - included in changelog
  • feat: New feature - a user-facing change which adds functionality - included in changelog
  • BREAKING CHANGE: (fix or feature that would cause existing functionality to change) - should bump major version, mentioned in the changelog
  • None - other non-user-facing changes

Merge request reports

Loading
Loading