Skip to content

feat(action): render annotations and job summary via the native GitHub formats#1839

Merged
BartWaardenburg merged 5 commits into
mainfrom
advisor/015-action-native-formats
Jul 13, 2026
Merged

feat(action): render annotations and job summary via the native GitHub formats#1839
BartWaardenburg merged 5 commits into
mainfrom
advisor/015-action-native-formats

Conversation

@BartWaardenburg

Copy link
Copy Markdown
Collaborator

The action's annotate and summary steps rendered through ~90KB of bundled jq that duplicated what the binary renders natively since v3.4.2. They now call fallow report --from <results.json> --format github-annotations|github-summary, re-rendering the same saved analysis JSON the run already produced (no extra analysis cost) behind a capability probe (fallow report --help, exported as HAS_NATIVE_REPORT via $GITHUB_ENV). Older binaries fall back to the jq renderers automatically; there is no version floor, and a step log line names which renderer ran.

Render precedence is native > typed decision/envelope > jq, fail-open at each step (a native render failure logs a ::warning and falls through; verified including the structured-error-envelope case). The action keeps applying its max-annotations cap plus truncation notice on the native stream, so that input keeps its contract. fix stays on the jq summary (report --from has no fix kind yet). No jq file is modified or deleted; the eventual jq retirement is a separate follow-up.

Tests: a new run.sh fastpath section (byte-equality vs the raw native render, truncation, fix bypass, probe-false byte-pinning the legacy jq output; skips cleanly without a report-capable binary: 421 vs 414 assertions, both green) plus a dogfood job in test-action.yml asserting the native path ran end-to-end (SHA-pinned steps, contents: read).

Closes #1816.

Add a HAS_NATIVE_REPORT capability probe next to the existing --sarif-file
probe. It greps nothing: the exit status of `fallow report --help` is enough,
and one probe covers both github-annotations and github-summary (they shipped
together). The result flows to the downstream annotate/summary steps through
$GITHUB_ENV, so older binaries without `fallow report` leave it unset and those
steps stay on the jq fallback.
When the analyze step probed HAS_NATIVE_REPORT=true, annotate.sh now renders
the saved envelope with `fallow report --from <results> --format
github-annotations` before the typed and jq paths. The action layers only the
existing MAX cap (head -n MAX) and its truncation notice on top, so the emitted
stream stays byte-identical to the raw native render. Native and jq select the
same scoped-or-full input via a shared resolve_results_file helper.

Fail-open throughout: a non-zero native render logs one ::warning:: and falls
through to the typed then jq paths, so a broken binary can never mean zero
annotations. A stderr log line names which renderer produced the output. fix
has no report kind and stays on jq (the step gate already excludes it).
When HAS_NATIVE_REPORT=true and the command carries a report kind, summary.sh
now renders the saved envelope with `fallow report --from <results> --format
github-summary` ahead of the typed and jq paths. The native summary is the
purpose-built step-summary rendering, so it takes precedence over the
comment-shaped typed body (which was itself a stopgap). Scoped runs keep the
existing changed-files disclaimer via a shared scoping_footnote helper.

Fail-open: a non-zero (or empty) native render logs one ::warning:: and falls
through to the typed then jq paths. fix has no report kind and stays on
summary-fix.jq. A stderr log line names which renderer produced the summary.
Note in the annotations and max-annotations input descriptions that on fallow
>= 3.4.2 the action renders both surfaces natively, that older binaries fall
back to jq, and how to tell which renderer ran from the step log. Record the
migration and its two behavior deltas (the trailing budget notice counting
toward max-annotations, and the purpose-built summary replacing the
comment-shaped body) under CHANGELOG [Unreleased].
Add a binary-gated 'Native report fastpath' section to run.sh: it resolves a
report-capable fallow (explicit $FALLOW_BIN, a local target build, or PATH) the
same way issuekind-drift-guard.sh does and skips cleanly when none is found,
so the pure-jq CI job stays green while local runs exercise the real renderer.
The load-bearing assertions are byte-equality between annotate.sh's output and
`report --from ... | head -n MAX` (the action adds nothing but the cap) and
probe-false, which pins the exact jq output for older binaries; plus the
truncation notice, the native summary heading, and fix staying on jq.

The fixture dead-code-envelope.json is a real `--format json` dead-code
envelope (the hand-authored jq fixtures carry no top-level kind, which
report --from requires). Add a test-action.yml dogfood job that runs the action
with annotations enabled and asserts annotate.sh takes the native path against
the installed binary.
@BartWaardenburg BartWaardenburg merged commit f57215b into main Jul 13, 2026
31 of 32 checks passed
@BartWaardenburg BartWaardenburg deleted the advisor/015-action-native-formats branch July 13, 2026 14:43
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.

Migrate the GitHub Action to the native github-annotations and github-summary formats

1 participant