Skip to content

Export coverage as Cobertura XML - #118

Merged
davidanthoff merged 2 commits into
mainfrom
cobertura-export
Sep 20, 2026
Merged

davidanthoff merged 2 commits into
mainfrom
cobertura-export

Conversation

@davidanthoff

Copy link
Copy Markdown
Member

Opened by Claude.

Why

GitHub Code Quality now stores coverage itself: a github-code-quality[bot] comment on the pull request with aggregate and per-file line coverage against the default branch, and a Restrict code coverage branch ruleset that can block a merge below a minimum percentage or beyond a maximum drop. It accepts Cobertura XML and nothing else, and this package could only write LCOV.

This is the first of five PRs wiring that up end to end (TestItemControllers → TestItemRuns → TestItemApp → julia-run-testitems → testitem-workflow). This one is self-contained and green on its own.

What

write_cobertura(io_or_path, result; root) in a new src/cobertura.jl, deliberately built as the twin of write_lcov:

  • same root relativization through the shared _report_path, same / separators, same refusal to walk out of the root with ..;
  • same "returns false and writes nothing when the run collected no coverage" contract, so a caller can drive both from one if — and a run without coverage leaves no empty file behind for something to upload as a real 0%;
  • same skipping of entries whose URI is not a file: URI.

Cobertura describes branch and method coverage too. Julia's line-count instrumentation produces neither and Code Quality reads line coverage only, so those attributes are present — the format's consumers expect them — and always zero. A line Julia could not instrument is left out rather than reported as a line nobody ran: Cobertura has no "not applicable" hit count. Files are grouped into one <package> per directory, dotted, as the format's Java ancestry expects.

Verification

  • 250/250 test items pass locally, including 4 new ones in test/test_cobertura.jl covering the no-coverage case, escaping, non-file: URIs, root relativization (absolute and relative roots) and the path-writing method.
  • The output parses with a real XML parser (xml.etree.ElementTree), and its lines-covered / lines-valid agree exactly with the LH: / LF: totals write_lcov produces from the same TestrunResult.

Note

version goes to 1.12.0-DEV — additive feature, and the downstream [compat] bounds in the other four PRs assume "1.12". Say the word if you want a different number.

Unrelated, but noticed while editing: CHANGELOG.md's unreleased section has been headed ## [2.0.0] - Unreleased since the file was added, while releases have been shipping as 1.11.x. Left alone here.

GitHub Code Quality stores coverage itself now -- a bot comment on the pull
request with aggregate and per-file line coverage against the default branch,
and a `Restrict code coverage` ruleset that can gate merges on it. It takes
Cobertura XML and nothing else, and this package could only write LCOV.

`write_cobertura(io_or_path, result; root)` is the sibling of `write_lcov`:
same `root` relativization through `_report_path`, same `/` separators, same
"returns `false` and writes nothing when the run collected no coverage"
contract, so a caller can drive both from one `if`.

Cobertura describes branch and method coverage too. Julia's line-count
instrumentation produces neither and the consumer this exists for reads line
coverage only, so those attributes are present -- the format's consumers expect
them -- and always zero. A line Julia could not instrument is left out rather
than reported as a line nobody ran: Cobertura has no "not applicable" hit count.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`round(Int, time() * 1000)` is `round(Int32, ...)` on a 32-bit Julia, and epoch
milliseconds passed what an Int32 can hold in 1970. Every x86 leg therefore
threw `InexactError: Int32(1.7898e12)` out of `write_cobertura` and produced no
report at all.

The test now pins the attribute: it has to parse as an integer larger than
`typemax(Int32)`, which is true on every platform and is what the 32-bit legs
were failing to reach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@davidanthoff
davidanthoff merged commit e6022ff into main Sep 20, 2026
38 of 40 checks passed
@davidanthoff
davidanthoff deleted the cobertura-export branch September 20, 2026 04:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant