Skip to content

feat: Add code coverage delta to PR's - #927

Open
MaximilianSoerenPollak wants to merge 12 commits into
eclipse-score:mainfrom
MaximilianSoerenPollak:main
Open

MaximilianSoerenPollak wants to merge 12 commits into
eclipse-score:mainfrom
MaximilianSoerenPollak:main

Conversation

@MaximilianSoerenPollak

@MaximilianSoerenPollak MaximilianSoerenPollak commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

📌 Description

This brings in the ability to measure complete code coverage in DaC and display the code coverage as a comment in the PR's themselves.

WIP:

  • Documentation still missing and final approval of how the comments etc look like.
  • Also I think some defensive programming & error handling is missing (what if there is no coverage on main etc.)
  • Also to think about, somehow pull this out into a reusable workflow and put it into cicd? Or is this too specific to DaC?

Currently this is how they look like:
image

image

Can be seen here

🚨 Impact Analysis

  • This change does not violate any tool requirements and is covered by existing tool requirements
  • This change does not violate any design decisions
  • Otherwise I have created a ticket for new tool qualification

✅ Checklist

  • Added/updated documentation for new or changed features
  • Added/updated tests to cover the changes
  • Followed project coding standards and guidelines

REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
pr=$(cat coverage-report/pr_number)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should not rely on what a PR has said what it is. See docs-publish workflow

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay that is a good catch.

Will address that once I take a look at trying to fix the code.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Missing-artifact handling can prevent reports, and malformed reference data can still crash rendering.

2 open findings
What changed in this PR

Adds merged Python coverage reporting and PR comments, including deltas against main.

Changes:

  • Adds LCOV merging, summaries, comparison logic, and tests.
  • Instruments Bazel and docs scenarios for coverage.
  • Adds workflows to collect, publish, and comment coverage results.
File Description
.github/​workflows/​_test.yml Collects and merges coverage artifacts.
.github/​workflows/​coverage_comment.yml Posts coverage summaries on PRs.
.gitignore Ignores generated coverage output.
bzl/​needs_rules.bzl Forwards coverage settings to Sphinx actions.
pyproject.toml Configures coverage.py.
src/​docs_cli/​BUILD Defines coverage build settings.
src/​docs_cli/​cli.py Starts coverage before application imports.
src/​requirements.in Adds coverage.py dependency.
src/​requirements.txt Locks coverage.py for Python 3.12.
src/​requirements_py314.txt Locks coverage.py for Python 3.14.
src/​tests/​docs_bzl/​README.md Documents scenario coverage usage.
src/​tests/​docs_bzl/​helpers.py Propagates coverage configuration through Bazel.
tools/​BUILD Defines the coverage-report binary.
tools/​coverage_report.py Implements merging, comparison, and Markdown output.
tools/​tests/​BUILD Registers coverage-report tests.
tools/​tests/​coverage_report_test.py Tests coverage processing and reporting.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +291 to +298
run: >-
bazel run --lockfile_mode=error //tools:coverage_report --
"Unit tests=coverage-data/unit_tests/unit_tests.lcov"
"docs.bzl scenarios=coverage-data/docs_bzl"
--output coverage-data/coverage.lcov
--markdown coverage-data/summary.md
--json coverage-data/coverage.json
${{ github.event_name == 'pull_request' && '--compare-with coverage-data/main/coverage.json' || '' }}
Comment thread tools/coverage_report.py
Comment on lines +183 to +185
lines_hit, lines_total = data["lines"]
branches_hit, branches_total = data["branches"]
return cls(lines_hit, lines_total, branches_hit, branches_total)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this actually ever occur?
I guess adding some defenses here is not a bad idea.
I will add this.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Documentation preview for this pull request is available at:
pr-927: https://eclipse-score.github.io/docs-as-code/pr-927/

Comment thread bzl/needs_rules.bzl Outdated
Comment on lines +163 to +166
"_coverage_file": attr.label(default = Label("//src/docs_cli:coverage_file")),
"_coverage_process_start": attr.label(
default = Label("//src/docs_cli:coverage_process_start"),
),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use internal_target for these?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the __internal__ prefix?

Comment thread src/tests/docs_bzl/helpers.py Outdated
Comment on lines +54 to +55
# An absolute path in the checkout is readable from every sandbox and
# runfiles tree the Sphinx runs start in.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not with remote execution

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, but I think once we have remote execution a lot of things will fail.

Though I will adapt the comments

"""Run Bazel, optionally overriding the environment of the subprocess."""
start_time = time.time()
cmd = ["bazel", *args]
coverage_env = _coverage_env()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, but something like: env |= _coverage_env()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you mean env = _coverage_env() | env?
Though this would then not add them but instead choose one or the other which is not quiet what we want.

Hmm but I think I kind of get what you mean, let me see if I can integrate this.

Comment thread src/requirements.in

# Measure what the docs.bzl scenario tests exercise inside Sphinx, and merge
# coverage reports in //tools:coverage_report.
coverage

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest after this PR we need to discuss splitting requirements.in for internal and public usage

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we for sure need to do this.

Comment thread tools/coverage_report.py
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
"""Merge Python coverage reports and add every tracked file no test imports.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract to tools? actually this is exact same thing as coverage_tool does... but generalizing coverage_tool is 10x effort.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw that tools has a similar script-ish already, and I think it might makes sense in the future to bring them together.
But I think for that coverage_tool needs to get into a better state first so we can see if maybe that script can be generalized and used here.

@MaximilianSoerenPollak MaximilianSoerenPollak left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions answered, and new ones raised.

Comment thread tools/coverage_report.py
@@ -0,0 +1,980 @@
# *******************************************************************************

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is quiet large due to the execesive comments that explain inputs & outputs as well as other things.

I'm unsure if this is good or bad.

Comment thread bzl/needs_rules.bzl Outdated
Comment on lines +163 to +166
"_coverage_file": attr.label(default = Label("//src/docs_cli:coverage_file")),
"_coverage_process_start": attr.label(
default = Label("//src/docs_cli:coverage_process_start"),
),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean the __internal__ prefix?

Comment thread src/tests/docs_bzl/helpers.py Outdated
Comment on lines +54 to +55
# An absolute path in the checkout is readable from every sandbox and
# runfiles tree the Sphinx runs start in.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, but I think once we have remote execution a lot of things will fail.

Though I will adapt the comments

"""Run Bazel, optionally overriding the environment of the subprocess."""
start_time = time.time()
cmd = ["bazel", *args]
coverage_env = _coverage_env()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you mean env = _coverage_env() | env?
Though this would then not add them but instead choose one or the other which is not quiet what we want.

Hmm but I think I kind of get what you mean, let me see if I can integrate this.

Comment thread src/requirements.in

# Measure what the docs.bzl scenario tests exercise inside Sphinx, and merge
# coverage reports in //tools:coverage_report.
coverage

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we for sure need to do this.

Comment thread tools/coverage_report.py
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
"""Merge Python coverage reports and add every tracked file no test imports.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw that tools has a similar script-ish already, and I think it might makes sense in the future to bring them together.
But I think for that coverage_tool needs to get into a better state first so we can see if maybe that script can be generalized and used here.

Comment thread tools/coverage_report.py
Comment on lines +183 to +185
lines_hit, lines_total = data["lines"]
branches_hit, branches_total = data["branches"]
return cls(lines_hit, lines_total, branches_hit, branches_total)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this actually ever occur?
I guess adding some defenses here is not a bad idea.
I will add this.

- Make new targets internal
- Add more defensive measures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants