Skip to content

action: select the baseline by the PR base commit and explain it in the report - #110

Merged
fgrosse merged 4 commits into
mainfrom
baseline-selection
Oct 1, 2026
Merged

fgrosse merged 4 commits into
mainfrom
baseline-selection

Conversation

@fgrosse

@fgrosse fgrosse commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Refs #109 (the remaining fallback issue will be addressed in a follow-up PR)

Problem

The baseline coverage was always taken from the first result of gh run list --limit=1 on the target branch. On busy repositories this API can return stale runs. The report then either compared against old code, or said the baseline artifact was unavailable even though a recent one existed.

Changes

Baseline selection (scripts/github-action.sh, action.yml)

The baseline run is now selected in this order:

  1. The run given via the new baseline-run-id input, if set. An unknown run ID fails the job.
  2. The latest successful run for the new baseline-sha input, which defaults to github.event.pull_request.base.sha.
  3. The latest successful run on the target branch, as before. If a SHA was given, this fallback emits a warning.

Setting baseline-sha: "" restores the previous behavior. This is a behavior change: by default, PRs are now compared against their base commit instead of the latest run on the target branch.

Diagnostics

  • The selected run is logged with its ID, commit, age and URL.
  • Warnings now distinguish between "no baseline run found", "base commit has no run, using latest" and "artifact of the selected run could not be downloaded".

PR comment

  • If the report does not compare against the base commit, a single line [!CAUTION] callout at the top explains why.
  • New CLI flags -baseline-commit, -baseline-run-id and -baseline-run-url name the baseline at the top of the details section.
  • The details section is renamed to "Coverage details" and no longer uses headings, to avoid mixing many text sizes.

Example with a fallback:

> [!CAUTION]
> No coverage for base commit 3ab52af was found, so this report compares against 2eb52af (latest run on `main`)

### Merging this branch will **increase** overall coverage
...
<details>

<summary>Coverage details</summary>

<sub>Compared to base commit 2eb52af (run [#8221109494](...))</sub>
...
</details>

Testing

  • go test ./... with new tests for the baseline line, and existing tests updated for the new details layout.
  • bash -n and shellcheck on the script.
  • Ran the script end-to-end with a mocked gh for the base SHA, fallback, missing artifact, no run and explicit run ID cases.
  • Tested in a real GitHub Actions run in Demo: coverage report comment for the go-coverage-report README prioqueue#6, which installs the binary from this branch. The baseline was found by the base commit and the comment renders as expected.

Notes

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.

Copilot review overview

🟡 Changes recommended

The default binary is incompatible with the new flags, and baseline metadata and caution handling still have unresolved correctness issues.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 High severity · 2 Medium severity

Open (4)
What changed in this PR

Updates baseline coverage selection to prefer the PR base commit and adds diagnostics and baseline metadata to reports.

Changes:

  • Adds baseline-run-id and baseline-sha inputs with fallback behavior.
  • Adds baseline run logging, warnings, and caution callouts.
  • Updates report layout, documentation, changelog, and tests.
File Summary
scripts/​github-action.sh Implements baseline discovery, diagnostics, and report integration.
README.md Updates baseline behavior and usage documentation.
cmd/​go-coverage-report/​report.go Renders baseline metadata in reports.
cmd/​go-coverage-report/​report_test.go Updates and expands report output tests.
cmd/​go-coverage-report/​main.go Adds baseline CLI flags.
CHANGELOG.md Documents the behavior changes.
action.yml Adds baseline inputs and action configuration.

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

Comment thread action.yml
Comment thread scripts/github-action.sh
Comment thread cmd/go-coverage-report/report.go Outdated
Comment thread scripts/github-action.sh
fgrosse added a commit to fgrosse/prioqueue that referenced this pull request Sep 24, 2026
…nshot

This branch serves as base for a demo pull request that shows the coverage
report comment of fgrosse/go-coverage-report#110. The code coverage job
installs the unreleased binary from that branch.
@fgrosse
fgrosse requested a lite review from Copilot September 24, 2026 20:53

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.

Copilot review overview

🔵 Needs a closer look

Two moderate baseline-selection issues and one documentation nit remain unresolved.

Review effort: Lite
Findings: None

Resolved since last review (4)

@fank fank 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.

Thanks for addressing this so quickly. The exact-base-SHA lookup, explicit run override, and diagnostics are all strong improvements, and I verified that the test suite and ShellCheck pass on the current head.

I think one correctness gap remains before the original failure mode is fully covered: the fallback at scripts/github-action.sh:145-147 still uses the same broad gh run list --branch … --status=success --event=… --limit=1 lookup that can return a stale result.

The new default path is correct when the base commit has a completed successful run. But there are ordinary cases where it does not:

  • the base commit's run failed or was cancelled;
  • it is still running when the report job reaches baseline selection;
  • it completed without the expected artifact;
  • the exact-SHA listing transiently returns no result.

In those cases the action falls back to find_baseline_run --branch="$TARGET_BRANCH". Because that broad query is the source of the intermittent stale selection, the fallback can still choose a substantially older run. The new caution and run-age diagnostics make the outcome visible, which is valuable, but the resulting delta can still include unrelated changes—or lose the baseline when the stale run's artifact has expired.

Would you consider making the fallback select the nearest usable ancestor of REQUESTED_BASELINE_SHA instead? For example:

  1. Start at the requested base SHA and inspect a bounded number of first-parent ancestors.
  2. Look up runs by exact head_sha/commit.
  3. Re-check SHA, branch, event and conclusion client-side.
  4. Continue when the run or coverage artifact is unavailable.
  5. Only use the broad “latest branch run” behavior when baseline-sha: "" explicitly opts into the legacy semantics.

A smaller alternative would be to retrieve multiple branch candidates and filter/sort them client-side, but that still cannot guarantee the baseline is at or before the tested base. Walking ancestors preserves the intended meaning of the coverage delta and handles gaps from failed/cancelled runs.

I would treat this as a meaningful improvement even without that change: the primary path should solve most occurrences. But I would not consider the stale-baseline failure fully closed while the automatic fallback still depends on the original broad query.

@henry-hived

Copy link
Copy Markdown

I am also coming up against this issue. I found that this CLI request always found the most recent run

gh run list --workflow=test.yml --limit 50 \
  --json databaseId,headBranch,event,conclusion \
  -q '[.[] | select(.headBranch=="main" and .event=="push" and .conclusion=="success")][0].databaseId'

Vs this which often returns data 14+ days old gh run list --status=success --branch=main --workflow=test.yml --event=push.

I agree the PR you have here is a significant improvement. Could the fallback be picked up in a later version?

…he report

Previously, the baseline coverage was always taken from the first result of
"gh run list --limit=1" on the target branch. On busy repositories this API
can return stale runs, so reports compared against old code or claimed the
baseline artifact was unavailable even though a recent one existed.

The baseline run is now selected as follows:

1. The run given via the new "baseline-run-id" input, if set.
2. The latest successful run for the new "baseline-sha" input, which
   defaults to the base commit of the pull request.
3. The latest successful run on the target branch, as before.

The selected run is logged with its ID, commit and age. Warnings now
distinguish between no baseline run being found and the artifact of the
selected run not being downloadable.

The pull request comment shows a single line caution callout at the top if
the report does not compare against the base commit of the pull request.
The new -baseline-commit, -baseline-run-id and -baseline-run-url flags name
the baseline at the top of the details section, which is renamed to
"Coverage details" and no longer uses headings.

Fixes #109
The screenshot shows the new layout of the details section including the
baseline commit and run. It was taken from fgrosse/prioqueue#6.
The action script now checks the usage of the installed binary before
passing the new -baseline-* flags. This keeps it working with older binaries,
e.g. when the "version" input is pinned to an older release or the action is
used from main before the default version is bumped.

Also label the baseline in the details section as "commit" instead of "base
commit", since it is not the base commit of the pull request after a fallback
or when using baseline-run-id.
@fgrosse
fgrosse force-pushed the baseline-selection branch from 47e5b13 to 15edbba Compare October 1, 2026 19:59
@fgrosse

fgrosse commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Thanks @fank and @henry-hived for the thorough feedback and for testing this.

You're right that the fallback still relies on the broad gh run list query that caused #109. I'll merge this PR as is, since the new default path already covers the common case, and I've changed "Fixes #109" to "Refs #109" so the issue stays open until the fallback is fixed too.

In the follow-up I plan to combine both of your suggestions:

  1. Fetch a bounded list of ancestors of the base commit.
  2. List recent runs of the baseline workflow without the server-side --status/--branch/--event filters and filter them client-side, since @henry-hived found that the filtered queries are the ones that return stale results.
  3. Use the nearest ancestor with a successful run, and move on to the next candidate if its coverage artifact can't be downloaded.
  4. Keep the "latest run on the target branch" behavior only when baseline-sha: "" opts into it.

This also covers base commits whose run failed, was cancelled or is still in progress.

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Merging this branch will decrease overall coverage

Impacted Packages Coverage Δ 🤖
cmd/go-coverage-report 64.34% (-0.37%) 👎
Coverage details

Compared to commit 6093ed4 (run #36230694596)

Changed File Coverage Δ Total Covered Missed 🤖
cmd/go-coverage-report/main.go 0.00% (ø) 56 (+5) 0 56 (+5)
cmd/go-coverage-report/report.go 85.16% (+0.49%) 155 (+5) 132 (+5) 23 👍

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files:

  • cmd/go-coverage-report/report_test.go

@fgrosse
fgrosse merged commit 7752bdc into main Oct 1, 2026
7 checks passed
@fgrosse
fgrosse deleted the baseline-selection branch October 1, 2026 20:01
1homsi pushed a commit to 1homsi/onekit that referenced this pull request Oct 6, 2026
Bumps
[fgrosse/go-coverage-report](https://github.com/fgrosse/go-coverage-report)
from 1.4.0 to 1.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/fgrosse/go-coverage-report/releases">fgrosse/go-coverage-report's
releases</a>.</em></p>
<blockquote>
<h2>v1.5.0</h2>
<ul>
<li>If the base commit of the pull request has no usable baseline run
(e.g. because it failed, is still running or its artifact
expired), the action now uses the nearest commit in the first-parent
history of the base commit with a usable run instead
of the latest run on the target branch. The runs of each commit are
filtered client-side, since the filtered workflow runs
API can return stale results, and further candidates are tried if a
coverage artifact cannot be downloaded or does not
<code>fgrosse/go-coverage-report#113</code></li>
<li>Add <code>baseline-search-depth</code> and
<code>baseline-max-downloads</code> inputs to configure how far the
action searches for a baseline
<code>fgrosse/go-coverage-report#113</code></li>
<li><code>fgrosse/go-coverage-report#13</code></li>
<li><strong>Behavior change:</strong> By default, the baseline coverage
is now taken from the latest successful run for the base commit
of the pull request (new <code>baseline-sha</code> input, defaults to
<code>github.event.pull_request.base.sha</code>) instead of the latest
successful run on the target branch. If there is no such run, the action
falls back to the latest successful run on the
target branch and emits a warning. Set <code>baseline-sha</code> to
<code>&quot;&quot;</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Add
<code>baseline-run-id</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Improve diagnostics when no baseline coverage is available: warnings
and the pull request comment now distinguish between
no successful baseline run being found and the coverage artifact of the
selected run not being downloadable, and the
<code>fgrosse/go-coverage-report#110</code></li>
<li>Show a caution callout at the top of the pull request comment if the
report does not compare against the base commit
<code>fgrosse/go-coverage-report#110</code></li>
<li>Name the baseline commit and run in the details section of the
report via the new <code>-baseline-commit</code>,
<code>-baseline-run-id</code> and

<code>-baseline-run-url</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Simplify the details section of the report: rename it to
&quot;Coverage details&quot; and drop its headings to avoid mixing many
<code>fgrosse/go-coverage-report#110</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/fgrosse/go-coverage-report/blob/main/CHANGELOG.md">fgrosse/go-coverage-report's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a
href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a>,
and this project adheres to <a
href="https://semver.org/spec/v2.0.0.html">Semantic Versioning</a>.</p>
<h2>[Unreleased]</h2>
<p><em>Nothing yet</em></p>
<h2>[v1.5.0] - 2026-10-02</h2>
<ul>
<li>If the base commit of the pull request has no usable baseline run
(e.g. because it failed, is still running or its artifact
expired), the action now uses the nearest commit in the first-parent
history of the base commit with a usable run instead
of the latest run on the target branch. The runs of each commit are
filtered client-side, since the filtered workflow runs
API can return stale results, and further candidates are tried if a
coverage artifact cannot be downloaded or does not
<code>fgrosse/go-coverage-report#113</code></li>
<li>Add <code>baseline-search-depth</code> and
<code>baseline-max-downloads</code> inputs to configure how far the
action searches for a baseline
<code>fgrosse/go-coverage-report#113</code></li>
<li><code>fgrosse/go-coverage-report#13</code></li>
<li><strong>Behavior change:</strong> By default, the baseline coverage
is now taken from the latest successful run for the base commit
of the pull request (new <code>baseline-sha</code> input, defaults to
<code>github.event.pull_request.base.sha</code>) instead of the latest
successful run on the target branch. If there is no such run, the action
falls back to the latest successful run on the
target branch and emits a warning. Set <code>baseline-sha</code> to
<code>&quot;&quot;</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Add
<code>baseline-run-id</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Improve diagnostics when no baseline coverage is available: warnings
and the pull request comment now distinguish between
no successful baseline run being found and the coverage artifact of the
selected run not being downloadable, and the
<code>fgrosse/go-coverage-report#110</code></li>
<li>Show a caution callout at the top of the pull request comment if the
report does not compare against the base commit
<code>fgrosse/go-coverage-report#110</code></li>
<li>Name the baseline commit and run in the details section of the
report via the new <code>-baseline-commit</code>,
<code>-baseline-run-id</code> and

<code>-baseline-run-url</code><code>fgrosse/go-coverage-report#110</code></li>
<li>Simplify the details section of the report: rename it to
&quot;Coverage details&quot; and drop its headings to avoid mixing many
<code>fgrosse/go-coverage-report#110</code></li>
</ul>
<h2>[v1.4.0] - 2026-09-20</h2>
<ul>
<li>Also report packages whose coverage changed without any of their
files being changed, e.g. when running integration tests with <code>go
test -coverpkg</code><code>fgrosse/go-coverage-report#102</code></li>
<li><code>fgrosse/go-coverage-report#103</code></li>
<li>Fix the
<code>exclude</code><code>fgrosse/go-coverage-report#104</code></li>
</ul>
<h2>[v1.3.1] - 2026-07-20</h2>
<ul>
<li><code>fgrosse/go-coverage-report#82</code></li>
<li>Fix the
<code>::endgroup::</code><code>fgrosse/go-coverage-report#89</code></li>
</ul>
<h2>[v1.3.0] - 2026-03-11</h2>
<ul>
<li>Add <code>event-name</code> and <code>target-branch</code> inputs to
support workflows triggered by events other than
<code>push</code><code>fgrosse/go-coverage-report#58</code></li>
<li><code>fgrosse/go-coverage-report#72</code></li>
<li><code>fgrosse/go-coverage-report#71</code></li>
<li>Add
<code>--exclude</code><code>fgrosse/go-coverage-report#59</code></li>
<li>Add structured outputs (<code>total_coverage</code>,
<code>coverage_delta</code>, <code>coverage_trend</code>,
<code>total_statements</code>, <code>covered_statements</code>,
<code>missed_statements</code><code>fgrosse/go-coverage-report#64</code></li>
</ul>
<h2>[v1.2.0] - 2024-08-28</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/fgrosse/go-coverage-report/commit/c4bf7e78d1379325814b4dd42d80e526082e788b"><code>c4bf7e7</code></a>
Release v1.5.0</li>
<li><a
href="https://github.com/fgrosse/go-coverage-report/commit/2d3d0a9621e933d9849ef63873c88ad1557786be"><code>2d3d0a9</code></a>
action: fall back to the nearest ancestor of the base commit (<a
href="https://redirect.github.com/fgrosse/go-coverage-report/issues/113">#113</a>)</li>
<li><a
href="https://github.com/fgrosse/go-coverage-report/commit/7752bdc735305e63c6f2739d47f2c7ceb8c9438d"><code>7752bdc</code></a>
action: select the baseline by the PR base commit and explain it in the
repor...</li>
<li><a
href="https://github.com/fgrosse/go-coverage-report/commit/6093ed43b53fa3fbe8efb961b2f79c562425587d"><code>6093ed4</code></a>
Bump github/codeql-action from 4.38.0 to 4.38.1 (<a
href="https://redirect.github.com/fgrosse/go-coverage-report/issues/112">#112</a>)</li>
<li><a
href="https://github.com/fgrosse/go-coverage-report/commit/b1b031ac32453fc15581c25a253da610796250f6"><code>b1b031a</code></a>
go-coverage-report: drop package name limitation (<a
href="https://redirect.github.com/fgrosse/go-coverage-report/issues/111">#111</a>)</li>
<li>See full diff in <a
href="https://github.com/fgrosse/go-coverage-report/compare/2eb52af4e808426e2d4edd850ff8c9ca14fce029...c4bf7e78d1379325814b4dd42d80e526082e788b">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=fgrosse/go-coverage-report&package-manager=github_actions&previous-version=1.4.0&new-version=1.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
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.

4 participants