Pre-merge coverage resultsets in the RSpec artifact collectors

What does this MR do and why?

rspec:coverage and rspec:undercoverage run one after the other after the last RSpec job, and end most tier 3 pipelines (#636505 (closed)). rspec:coverage collates about 300 SimpleCov resultsets, one per RSpec job. In job 17491331510, downloading them took 51s and merge-simplecov 2m14s.

This MR has each rspec:artifact-collector job merge its group's resultsets into one before it uploads them, so rspec:coverage downloads and collates about 7 files instead. This was the open follow-up in #629055 (closed).

  • scripts/premerge-simplecov merges the resultsets with SimpleCov's own merger, writes one resultset and only then deletes the inputs.
  • The merged coverage is written unfiltered. Filtering needs the source files, which the collectors don't have, so rspec:coverage still applies every filter, as it does today.
  • It leaves the resultsets as they are when there is only one.
  • The collectors extend .fast-no-clone-job and use the Ruby alpine image, as retrieve-tests-metadata does: they download only scripts/premerge-simplecov and Gemfile.lock through the Files API, then install the simplecov gem at the locked version. If the merge itself fails, scripts/premerge-simplecov leaves the resultsets as they are.

Results

The collectors are on the critical path too: the last one to finish, usually rspec:artifact-collector ee unit, starts right after the last RSpec job. So this only helps if what it adds there costs less than what it saves in rspec:coverage.

Tier 3 pipeline of this MR (pipeline 2996913085) against another MR's tier 3 pipeline (pipeline 2992718000), by job section:

rspec:artifact-collector ee unit:

Section Before (job 17491331508) With this MR (job 17523326031)
Runner setup 5s 7s
Download artifacts 33s 35s
Script: download files, install simplecov, pre-merge 1s 32s (merge: 29.0s)
Upload artifacts 6s 2s
Total 46s 78s

rspec:coverage:

Section Before (job 17491331510) With this MR (job 17523326033)
Runner setup 22s 19s
Restore cache 20s 17s
Download artifacts 51s 29s
Script (merge-simplecov and splitting coverage.xml) 160s 79s
Upload artifacts 7s 5s
Total 267s 154s

Time from the last RSpec job finishing to the end of each job, against the medians of 113 tier 3 MR pipelines from 2026-10-26 and 2026-10-27:

Median before (p20–p80) With this MR
Last collector 46s (33–51s) 80s
rspec:coverage 274s (192–317s) 236s
rspec:undercoverage 371s (294–445s) 323s

So the slowest collector takes about 30s longer, rspec:coverage about 75s less than its median of 228s (p20–p80: 190–260s), and the pipeline ends roughly 45s sooner. One pipeline is within the normal range of the medians, so this needs confirming over more pipelines after merge.

Other runs of this MR:

  • Pipeline 2995460253 used the full repository from clone-gitlab-repo and the Ruby slim image in the collectors. That added about 20s of downloads and 15s of runner setup to rspec:artifact-collector ee unit (112s), so the pipeline wasn't faster (399s to the end of rspec:undercoverage).
  • In pipeline 2996662918, single artifact downloads of RSpec jobs stalled for 135–269s in rspec:artifact-collector ee unit and ee remainder, which happens with or without this MR. Apart from that, the collectors' script took the same time as above (31s in ee unit, merge 29.8s), and rspec:coverage took 145s.

The merged coverage is the same as before: every resultset of the RSpec jobs that ran reaches rspec:coverage (rspec-ee fail-fast uploads none), and building the reports from the pre-merged resultsets of pipeline 2992718000 gives byte-identical lcov and coverage.xml files (apart from the timestamp).

How to set up and validate locally

  1. Download the artifacts of the RSpec artifact collectors of a tier 3 pipeline, and extract each one into its own directory.
  2. Check out the pipeline's commit, and replace /builds/gitlab-org/gitlab/ in the .resultset.json files with the path of that checkout. Leave /builds/gitlab-org/gitlab-foss/ paths as they are, as they are in CI.
  3. In each collector's directory, run scripts/premerge-simplecov premerged-<collector>.
  4. Copy the resulting coverage/* directories into one coverage/ directory, and run scripts/merge-simplecov against it, with the original resultsets in another directory.
  5. Compare coverage/lcov/*.lcov and coverage/coverage.xml (without the timestamp attribute) between the two.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Heinrich Lee Yu

Merge request reports

Loading
Loading