Skip to content

Commit

Permalink
fix: workaround absolute paths appearing in coverage data (#524)
Browse files Browse the repository at this point in the history
Issue reported here:
aspect-build/bazel-examples#404 (comment)

Now looks like

```
SF:src/__init__.py
DA:1,1
DA:2,1
```

Similar to
https://github.com/bazelbuild/rules_python/blob/466da1d9710289bfb01061b9be7bb124132996e0/python/private/python_bootstrap_template.txt#L336-L346
but ours is a bit more principled since we don't break the abstraction
of what coveragepy happens to do with the paths.


### Changes are visible to end-users: no

### Test plan

- Manual testing; please provide instructions so we can reproduce:
Just `bazel coverage src:test` and inspect the .dat file
  • Loading branch information
alexeagle authored Jan 30, 2025
1 parent 9270b4d commit 1717d11
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 4 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ jobs:
uses: zgosalvez/github-actions-report-lcov@5989987f8058a03137e90bc16f9c0baaac5e069a # v4.1.22
with:
title-prefix: "e2e/use_release folder:"
working-directory: e2e/use_release
# Point to the already-merged data file Bazel produces with --combined_report=lcov
# Follows https://bazel.build/configure/coverage#running_coverage
coverage-files: "${{ env.output_path }}/_coverage/_coverage_report.dat"
Expand Down
6 changes: 6 additions & 0 deletions e2e/use_release/.coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[run]
# NB: this ought to put relative paths into the report files.
# However Bazel actions run in a sandbox with symlinks, and coveragepy follows those out of the sandbox
# resulting in the wrong paths.
# See https://github.com/nedbat/coveragepy/issues/963 and https://github.com/aspect-build/rules_py/pull/524
relative_files = False
2 changes: 2 additions & 0 deletions e2e/use_release/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("@rules_uv//uv:pip.bzl", "pip_compile")

exports_files([".coveragerc"])

pip_compile(name = "pip_compile")
1 change: 1 addition & 0 deletions e2e/use_release/src/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ py_binary(
# TODO(alex): land https://github.com/aspect-build/rules_py/pull/401 and shorten this
py_pytest_main(
name = "__test__",
data = ["//:.coveragerc"],
deps = [
"@pip//coverage",
"@pip//pytest",
Expand Down
21 changes: 17 additions & 4 deletions py/private/pytest.py.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ from typing import List
import pytest
# None means coverage wasn't enabled
cov = None
# For workaround of https://github.com/nedbat/coveragepy/issues/963
coveragepy_absfile_mapping = {}

# Since our py_test had InstrumentedFilesInfo, we know Bazel will hand us this environment variable.
# https://bazel.build/rules/lib/providers/InstrumentedFilesInfo
Expand All @@ -28,9 +30,13 @@ if "COVERAGE_MANIFEST" in os.environ:
import coverage
# The lines are files that matched the --instrumentation_filter flag
with open(os.getenv("COVERAGE_MANIFEST"), "r") as mf:
cov = coverage.Coverage(include = mf.read().splitlines())
manifest_entries = mf.read().splitlines()
cov = coverage.Coverage(include = manifest_entries)
# coveragepy incorrectly converts our entries by following symlinks
# record a mapping of their conversion so we can undo it later in reporting the coverage
coveragepy_absfile_mapping = {coverage.files.abs_file(mfe): mfe for mfe in manifest_entries}
cov.start()
except Exception as e:
except ModuleNotFoundError as e:
print("WARNING: python coverage setup failed. Do you need to include the 'coverage' library as a dependency of py_pytest_main?", e)
pass

Expand Down Expand Up @@ -95,15 +101,22 @@ if __name__ == "__main__":
# https://bazel.build/configure/coverage
coverage_output_file = os.getenv("COVERAGE_OUTPUT_FILE")

# Workaround https://github.com/bazelbuild/bazel/issues/25118
# by removing 'end line number' from FN: records
unfixed_dat = coverage_output_file + ".tmp"
cov.lcov_report(outfile = unfixed_dat)
cov.save()

with open(unfixed_dat, "r") as unfixed:
with open(coverage_output_file, "w") as output_file:
for line in unfixed:
# Workaround https://github.com/nedbat/coveragepy/issues/963
# by mapping SF: records to un-do the symlink-following
if line.startswith('SF:'):
sourcefile = line[3:].rstrip()
if sourcefile in coveragepy_absfile_mapping:
output_file.write(f"SF:{coveragepy_absfile_mapping[sourcefile]}\n")
continue
# Workaround https://github.com/bazelbuild/bazel/issues/25118
# by removing 'end line number' from FN: records
if line.startswith('FN:'):
parts = line[3:].split(",") # Remove 'FN:' and split by commas
if len(parts) == 3:
Expand Down

0 comments on commit 1717d11

Please sign in to comment.