Run the undercoverage check in the rspec:coverage job

What does this MR do and why?

rspec:undercoverage runs after rspec:coverage at the end of every MR pipeline that changes code (#636505 (closed)). In 29 of these jobs from tier 3 pipelines on 2026-10-26 and 2026-10-27, it took a median of 91s (p80 103s), of which:

Part p50 p80
Runner setup, cache, and downloading the repository and the rspec:coverage artifacts again 63s 65s
git diff --stat, which only prints the diff 7s 9s
scripts/undercoverage 12s 20s

It also started 1.6s (median) after rspec:coverage finished.

This MR runs scripts/undercoverage in rspec:coverage, after it merges the coverage data, and removes rspec:undercoverage:

  • rspec:coverage sets UNDERCOVERAGE_FAILURE: "block", and its rules override it with allow where rspec:undercoverage had allow_failure: true, so a failed check behaves as it did in rspec:undercoverage:

    Pipeline Before With this MR
    MR with pipeline:run-all-rspec blocks block: the job exits with 1
    Tier 3 MR that changes code blocks block: the job exits with 1
    Other MR that changes code allowed to fail allow: the job exits with 202, which allow_failure: exit_codes allows
    MR with pipeline:skip-undercoverage rspec:undercoverage doesn't run the check is skipped
    Scheduled maintenance and coverage export pipelines rspec:undercoverage doesn't run the check is skipped (not a merge request pipeline)
  • rspec:coverage runs in the same pipelines as before. Only the order of its rules changed, so that the undercoverage rules match first.

  • Its artifacts are now uploaded when: always, so the coverage report is still available when the check fails.

  • The docs describe the check as part of rspec:coverage, and say that pipeline:skip-undercoverage skips the check. It no longer lets a failing job pass, as they still said. Exit code 202 is listed next to the custom exit codes.

Trade-offs:

  • A failed check makes rspec:coverage fail (or fail with a warning below tier 3) instead of rspec:undercoverage.
  • Retrying a failed check reruns the coverage merge too, about 1.5 minutes longer than retrying rspec:undercoverage.

Results

Tier 3 pipeline 2997667689 of this MR, against the medians of 113 tier 3 MR pipelines from 2026-10-26 and 2026-10-27:

Time from the last RSpec job to the end of the pipeline's coverage jobs Before (median, p20–p80) With this MR
End of rspec:coverage 274s (192–317s) 328s
End of rspec:undercoverage 371s (294–445s) (job removed)

So the pipeline ends about 45s sooner. In job 17528110690, rspec:coverage took 274s, of which the undercoverage check took 55s:

Step Time
git diff ... --stat 40s
scripts/undercoverage 15s

Both are slower than in rspec:undercoverage (7s and 12s), probably because they read every file in the checkout, which the coverage merge has pushed out of the page cache by then. In an earlier pipeline of this MR without git diff --stat, scripts/undercoverage took 60–66s instead (job 17524751143 and its retry), so this MR keeps it.

!265692 (merged) upgrades undercover to 0.9.0 and compares commits instead of the working tree, which takes the check to about 2s in CI. With both, the pipeline would end about 90s sooner. Whichever of the two merges last can then remove git diff --stat.

How to set up and validate locally

The script's decisions can be checked with a stub bundle that fails like scripts/undercoverage does:

  1. Save the last script entry of rspec:coverage as script.sh.

  2. Create a bundle script on your PATH that runs exit ${FAKE_UNDERCOVER_EXIT:-0}.

  3. Run bash script.sh with these variables and check the exit code:

    Variables Expected exit code
    UNDERCOVERAGE_FAILURE=block FAKE_UNDERCOVER_EXIT=1 0 (not an MR pipeline)
    CI_MERGE_REQUEST_IID=1 UNDERCOVERAGE_FAILURE=block CI_MERGE_REQUEST_LABELS=pipeline:skip-undercoverage FAKE_UNDERCOVER_EXIT=1 0
    CI_MERGE_REQUEST_IID=1 UNDERCOVERAGE_FAILURE=block 0
    CI_MERGE_REQUEST_IID=1 UNDERCOVERAGE_FAILURE=block FAKE_UNDERCOVER_EXIT=1 1
    CI_MERGE_REQUEST_IID=1 UNDERCOVERAGE_FAILURE=allow FAKE_UNDERCOVER_EXIT=1 202
    CI_MERGE_REQUEST_IID=1 UNDERCOVERAGE_FAILURE=allow 0

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Heinrich Lee Yu

Merge request reports

Loading
Loading