Skip to content

Enforce coverage inside of Bazel lcov merger - #450

Merged
tinder-maxwellelliott merged 4 commits into
Tinder:masterfrom
maxwellE:claude/lcov-merger-bazel-coverage-tl9k4j
Aug 10, 2026
Merged

Enforce coverage inside of Bazel lcov merger#450
tinder-maxwellelliott merged 4 commits into
Tinder:masterfrom
maxwellE:claude/lcov-merger-bazel-coverage-tl9k4j

Conversation

@maxwellE

Copy link
Copy Markdown
Contributor

As we look to possibly port this project into Rust we need to ensure that at a core level we are not regressing on the high standards in the codebase around test coverage. This work moves our coverage enforcement inside of bazel itself, providing agents with direct feedback when work they are performing does not contain the necessary coverage standards to merge into this codebase.

claude added 2 commits August 10, 2026 13:59
Replace Bazel's built-in LCOV merger with a dependency-free Rust binary
(//tools/coverage:lcov_merger, wired via --coverage_output_generator in
.bazelrc) that merges each test's raw per-runner LCOV tracefiles into its
coverage.dat and, when the target declares one, enforces a minimum line
coverage percentage. Bazel only invokes the merger during 'bazel coverage',
so plain 'bazel test' runs are never affected.

Targets opt in through their env attribute via //tools/coverage:defs.bzl
(coverage_enforced_test macro / coverage_minimum_env helper), which works
with any test rule exposing the standard env attribute (go_test, rust_test,
kt_jvm_test, py_test, ...). Applied so far:

- //tools/go/sample:sample_test — min 90% over tools/go/ (mirrors the CI gate)
- //tools/coverage:lcov_merger_test — min 90% over its own sources,
  enforced by the merger itself (currently at 98%)

The merger mirrors the built-in CoverageOutputGenerator's contract:
--coverage_dir/--output_file/--filter_sources/--source_file_manifest,
full-match filter regexes (small built-in subset, no third-party crates),
manifest restriction to instrumented sources, and recomputed summary
counters. Unknown flags warn instead of failing so newer Bazels degrade
gracefully. Below-minimum targets exit with code 33 and a per-file
breakdown in the test log; the merged coverage.dat is still written and
--combined_report=lcov works unchanged.

rules_rust is a dev_dependency (consumers of bazel-diff as a module do not
inherit it), pinned to Rust 1.90.0, edition 2021.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016KqwUSCW2t6fmvnRFyw9vX
Apply the lcov_merger enforcement (previous commit) across every test
target in the repository that produces coverage:

- cli/BUILD: all 40 kt_jvm_test targets declare a minimum via
  coverage_minimum_env, scoped to the source file(s) each test is
  responsible for (Jacoco instruments all of :cli-lib for every test, so
  unscoped percentages would be meaningless). Floors were set from
  measured per-target coverage minus ~10 points of headroom, rounded down
  to 5 and capped at 90, to absorb platform/Bazel-version variance while
  still catching real regressions. E2ETest carries a conservative 30%
  smoke floor over the whole main tree instead of a measured one.
- rules_kotlin ignores --coverage_output_generator: kt_jvm_test hardcodes
  its _lcov_merger attribute to Bazel's built-in merger instead of the
  coverage fragment's output_generator configuration field, which would
  silently bypass enforcement for Kotlin targets. A single_version_override
  patch (tools/coverage/rules_kotlin_lcov_merger.patch) makes it read the
  configuration field, like rules_go/rules_rust/rules_java already do.
  Verified: an unreachable floor fails 'bazel coverage' with the merger's
  per-file report in the test log, and plain 'bazel test' is unaffected.
- gazelle direct dep bumped 0.45.0 -> 0.47.0 to match the version MVS now
  resolves (rules_rust requires the newer one), silencing the
  check_direct_dependencies warning.
- CI/Makefile coverage universes include //tools/coverage/...; README
  documents the per-target system.

All 40 Kotlin targets (39 measured + E2E), the Go sample test, and the
Rust merger's own test pass 'bazel coverage' with enforcement active.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016KqwUSCW2t6fmvnRFyw9vX
@maxwellE
maxwellE force-pushed the claude/lcov-merger-bazel-coverage-tl9k4j branch from a6e0304 to d03e4bb Compare August 10, 2026 14:05
tinder-maxwellelliott and others added 2 commits August 10, 2026 12:20
Make 90% the Starlark default, drop enforcement on E2E/partial tests,
and expand primary-owner unit tests (including RuleHasherTest) so every
remaining coverage_minimum_env target clears the floor.

Co-authored-by: Cursor <cursoragent@cursor.com>
chflags is macOS-only and ProcessBuilder.start throws when the binary is
missing, so the prior skip path never ran on Ubuntu. Use POSIX directory
permissions and a VisibleForTesting touch hook instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tinder-maxwellelliott
tinder-maxwellelliott merged commit f863c75 into Tinder:master Aug 10, 2026
15 checks passed
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.

3 participants