Repository navigation
ci: show pull requests the nvx-rs lines that they add and no test reaches - #1353
Merged
Merged
Conversation
…ches A pull request that changes the nvx crate could not tell which of the lines that it adds or changes no test reaches: nvx-rs-coverage.yml ran only for pushes to dev and on dispatch, and its summary gave totals and a row per module. The workflow now also runs for ready pull requests to any branch that change its inputs, the paths that start it for dev, in jobs that skip drafts with the condition of ci.yml's jobs. No required check depends on them: dev requires only Required status check, a job of ci.yml, and merge groups never run the workflow. A pull request's jobs check out its head, rather than its merge with its base, with the history that their merge base needs, and pass the base's commit to the script with --base. With --base REVISION, scripts/nvx_rs_coverage.py: - takes the lines of the crate that the working tree adds or changes since the merge base of REVISION and HEAD from git diff, with rename detection and no context, whatever Git's configuration says of colors, prefixes, renames, context, external diff drivers, text conversions, or relative paths; it reads each hunk by the line counts of its header, so that an added line that looks like a header counts as a line, and the file names that Git quotes or ends with a tab; - reads the LCOV report of the production code, whose DA records give each instrumented line once, and whose BRDA records give the branches when the compiler measures them; - counts only the changed lines that the report instruments: a renamed file's changed lines, but neither deleted lines, nor comments, blank lines, or declarations, nor the lines of test code, test doubles, or files that the host's OS doesn't compile; - writes, before the summary's module table, the share of those lines that the tests reach, the lines that they don't, by file, and, when the compiler measures branches, the branches on the changed lines that no test takes. At 8394746, the script refused --base and the workflow had no pull_request trigger, on a Windows workstation and on nvx-kvm-test. With this change, on the Windows workstation, under nightly-2026-07-09 and its llvm-tools, since its pinned 1.97.1 lacks them, with an uncommitted function in src/gpt/crc.rs that no test calls: - --base origin/dev exited 0 in 160 s, and the summary said that the tests reach 60.0% of 5 instrumented changed lines, and listed lines 55-56 of src/gpt/crc.rs, the new function's, whose DA records hold 0. The three changed lines of Crc32::new ran 559 times each, and the changed comment, blank, doc comment, and attribute lines have no DA record. - With RUSTFLAGS=-Zcoverage-options=branch and an impossible bounds check added to Crc32::update, it listed lines 55-56 and 64, and the branch that no test takes on line 63, 1 of its 2, from BRDA records. The LCOV reports of dev's run 42398285564 parse into the counts that they hold: 262 files and 43,251 lines on Linux, and 164 files and 26,807 lines on Windows. scripts/test_nvx_rs_coverage.py tests the workflow's pull_request trigger, its draft condition, which matches ci.yml's, its checkout, and its Measure step, which a POSIX host runs with and without a base; the lines of Git's diffs in fixture repositories, with renamed, deleted, added, quoted, and untracked files, deleted lines, a base that moved on, uncommitted changes, and a hostile Git configuration; the LCOV records; the counting, with comments and files that the report lacks; and the summary. At 8394746, 38 of its 55 tests fail; with this change, all pass. Three existing tests change with the trigger, the Measure step, and the call of measure(). doc/ci.md describes the pull requests' report and --base on a development host. Part of #1324. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
This pull request changes existing testsIt modifies or removes 3 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests. Test code
Relocated unchanged: 0; added: 35. Compared the merge base |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The pull-request changed-line coverage update has no active review issues.
No open issues 🎉
What changed in this PR
Extends the existing nvx-rs coverage workflow to ready pull requests, reporting changed production lines that tests do not reach on Linux and Windows without changing required checks.
Changes:
- Measures each pull request’s head and compares its changes against the merge base.
- Adds
--basesupport to combine Git diffs with LCOV data and summarize unreached lines and, when measured, untaken branches. - Adds tests for workflow wiring, diff parsing, coverage calculations, and summaries, and documents the behavior.
| File | Description |
|---|---|
scripts/test_nvx_rs_coverage.py |
Tests pull-request workflow wiring and changed-line coverage reporting. |
scripts/nvx_rs_coverage.py |
Computes changed-line coverage and renders it in the summary. |
nvx-rs/README.md |
Describes coverage reporting for ready pull requests. |
doc/project-structure.md |
Updates the coverage workflow’s purpose in the repository map. |
doc/ci.md |
Documents triggers, reporting semantics, and local --base usage. |
.github/workflows/nvx-rs-coverage.yml |
Enables ready pull-request runs with head checkout and base comparison. |
Review effort: Balanced
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1324.
A pull request that changes the
nvxcrate could not tell which of the lines that it adds or changes no test reaches:nvx-rs-coverage.yml(#1333) ran only for pushes todevand on dispatch, and its summary gave totals and a row per module. This runs the measurement for ready pull requests too, and adds to each OS's summary the changed lines of production code that no test reaches.Decisions
pull_requesttrigger ofnvx-rs-coverage.yml, rather than jobs ofci.yml, asmodule-diagrams.ymldraws its diagrams for pull requests, so that no required check depends on it. As inci.yml, it runs for any base, so that a pull request stacked on another's branch lists the lines of its own changes, and drafts skip it with the condition ofci.yml's jobs.dev:nvx-rs/**, and alsorust-toolchain.toml, the tool manifest, the script, and the workflow, so that a pull request that changes how the crate is measured, this one included, runs the measurement before it merges. Such a pull request lists no line unless it changesnvx-rs/.pull_requestchecks out by default, so that the lines, from the diff against the merge base of the base's commit and the head, are those of the pull request's own changes. A pull request's checkout fetches the full history, asci.yml'sDetect CI workload inputsdoes in about 6 s; pushes keep a depth of 1.--basecompares the working tree, which the measurement builds, so that on a development host uncommitted changes count too, but untracked files, which no diff holds, don't. In CI, they are the same.Changes
.github/workflows/nvx-rs-coverage.yml: thepull_requesttrigger (opened, synchronize, reopened, ready_for_review), the draft condition, the checkout of the head with its history, and--base "${BASE}"for pull requests in theMeasurestep.scripts/nvx_rs_coverage.py:--base REVISION. It takes the lines ofnvx-rs/that the working tree adds or changes since the merge base ofREVISIONandHEADfromgit diff --find-renames --unified=0, with options that override what Git's configuration says of colors, prefixes, renames, context, external diff drivers, text conversions, and relative paths, reading each hunk by its header's counts, and the file names that Git quotes or ends with a tab. It reads the LCOV report'sDAandBRDArecords, and writes a section before the module table: the share of the changed lines that the report instruments that the tests reach, then, by file, the lines that no test reaches and, when branches are measured, the changed lines with branches that no test takes.scripts/test_nvx_rs_coverage.py: tests of the trigger, the draft condition, which matchesci.yml's, the checkout, and theMeasurestep, which a POSIX host runs with and without a base; of Git's diffs in fixture repositories, with renamed, deleted, added, quoted, and untracked files, deleted lines, a base that moved on, uncommitted changes, and a hostile Git configuration; of LCOV records; of the counting, with comments and files that the report lacks; of the summary; and of--basethroughmeasure()andmain().doc/ci.md: the trigger, a "Changed lines that no test reaches" subsection, and--baseon a development host;nvx-rs/README.md(Testing) anddoc/project-structure.md.Changes to existing tests
check_test_changes.py --base origin/devflags three tests ofscripts/test_nvx_rs_coverage.py, each of which checked behavior that this changes:WorkflowTests.test_pushes_to_dev_that_change_the_measurement_run_itasserted that the workflow's triggers are onlypushandworkflow_dispatch("Never for pull requests"). The set now includespull_request, and the comment says that merge groups never run it. Its checks of thepushtrigger are unchanged, and the newtest_ready_pull_requests_that_change_the_measurement_run_itchecks thepull_requesttrigger.WorkflowTests.test_the_workflow_measures_linux_and_windowsasserted theMeasurestep's exact command, which is now a bash script that adds--basefor a pull request. It now checks the script's output option and command, and the newtest_pull_requests_measure_their_head_and_their_changesruns the step with and without a base.CommandTests.test_the_output_defaults_to_the_build_directoryasserted the call ofmeasure(), which now passeschanges=Nonewhen there is no--base.Acceptance criteria of #1324
nvx-rsthat no test reaches finds it in its run's summary, and one that adds none finds none: on a Windows workstation, the script listed the lines of an uncommitted function that no test calls, and only them (Validation), andtest_changes_find_the_lines_that_they_add_and_no_test_reachesshows both halves through real Git. This pull request changes no instrumented line ofnvx-rs/, only its README, and its own run 42418117916 found none: both jobs measured its head,b611b51df, with the pinned rustc 1.97.1 and cargo-llvm-cov 0.9.1, and each summary says "The changes since8394746fd864add or change no instrumented line of production code".dev's rules require onlyRequired status check(gh api repos/microsoft/nvx/rules/branches/dev), a job ofci.yml, which this leaves unchanged. The new runs are themeasure / ubuntu-latestandmeasure / windows-latestjobs of another workflow, which merge groups never run.Problems found, not fixed here
const fnthat only the compiler evaluates as unreached, such astable()insrc/gpt/crc.rs(lines 18-36 indev's run 42398285564), so a pull request that changes such a function sees its lines listed.test_host_loopback_allow_script_checks_publication_and_trafficintest_microvm_tests.pyerror, as their shell script exceeds its 10 s timeout under Git for Windows'sh, at8394746fd(dev) too, as ci: report the coverage of the Python host tooling in scripts/ #1344 recorded.Validation
windows8394746fd(dev)nvx_rs_coverage.py --base origin/devunrecognized arguments: --base origin/dev. The workflow has nopull_requesttrigger, and no pull-request run of it existsnvx-kvm-test, Python 3.12.16, Git 2.45.4linux-kvmvirtual-machine8394746fd(dev)windows8394746fd, with this branch's teststest_nvx_rs_coverage.pywindowsb611b51dftest_nvx_rs_coverage.pynvx-kvm-testlinux-kvmvirtual-machineb611b51dftest_nvx_rs_coverage.py,test_tool_versions.py, andtest_markdown_links.pynvx-kvm-testlinux-kvmvirtual-machinee70a27eb2, before the review fix belowNVX_RSwindowse70a27eb2NVX_RS8394746fd(2 of them in a run of that test alone)windowssrc/gpt/crc.rsnvx_rs_coverage.py --base origin/dev, undernightly-2026-07-09and itsllvm-tools, which the workstation's 1.97.1 lackssrc/gpt/crc.rs55-56, the function. ItsDArecords hold 0, the changed lines ofCrc32::newran 559 times each, and the changed comment, blank, doc comment, and attribute lines have no recordwindowsCrc32::updateRUSTFLAGS=-Zcoverage-options=branchBRDArecords; the same with the review fix, from the run's LCOV reportAlso:
ruff check,ruff format --check, andpyright --pythonplatform LinuxandWindowsare clean;check_markdown_links.pyandcheck_test_layout.pypass; and the LCOV reports ofdev's run 42398285564 parse into the counts that they hold: 262 files and 43,251 lines on Linux, 164 files and 26,807 lines on Windows.A code review of
e70a27eb2found that the summary left out the branches of changed lines that no test reaches, whichb611b51dflists, as the issue asks.CI of
b611b51df: run 42418117994 ofci.ymlpassed, withNVX CLI / LinuxandNVX CLI / Windows, which run validate-nvx withNVX_RS, andRequired status check; its change classification skipped the microVM, platform, and package jobs, which this changes no input of. Run 42418117916 ofnvx-rs coverage, the first with the pinned release and--base, passed onubuntu-latestin 4 min andwindows-latestin 5 min, with no test run again and no stray profile.