ci: post the LOC diff as a sticky pull request comment - #1753
Conversation
count_diff now takes two explicit tree paths instead of the MFC_PR env var, reports only files whose count moved, adds a per-directory rollup, and with --markdown writes a GitHub-flavored table (empty when nothing changed). The workflow moves to pull_request_target so fork PRs can be commented on, and posts via sticky-pull-request-comment. It counts against the merge base rather than the tip of the base branch, so a PR is only charged for the lines it actually adds. The counter also recurses into src/*/include, which the old glob silently skipped.
Key the concurrency group on the PR number rather than github.head_ref, which is a branch name and collides across forks (two PRs from branches both named master would cancel each other, silently dropping one comment). Skip non-regular files and read with errors=replace, since under pull_request_target the counted tree is attacker-controlled: a symlinked src/*.fpp pointing at /dev/zero would otherwise read until the runner died, and one non-UTF-8 byte in a comment would fail the job. Take the comment back down when the diff returns to zero instead of leaving a stale number, which also means the workflow can no longer be filtered on src/**: a PR that stops touching src/ has to still run in order to be cleaned up.
|
Claude Code Review Head SHA: 9827831 Files changed:
Findings:
|
There was a problem hiding this comment.
Pull request overview
This PR adds a GitHub Actions workflow that posts a single sticky pull request comment showing per-file and per-directory line-of-code (LOC) deltas, making ./mfc.sh count_diff output visible directly on PRs (including from forks) by using pull_request_target and comparing against the merge base.
Changes:
- Updated
./mfc.sh count_diffto compare two explicit source-tree paths and optionally emit GitHub-flavored Markdown for CI commenting. - Extended LOC counting to recurse into
src/*/**(includinginclude/) and harden reading behavior for CI by skipping non-files and usingerrors="replace". - Added a
pull_request_targetworkflow that computes the merge-base diff and posts/removes a sticky PR comment accordingly.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
toolchain/mfc/count.py |
Adds two-tree diffing, Markdown output for CI, recursive counting, and untrusted-tree handling. |
toolchain/mfc/cli/commands.py |
Updates the CLI schema for count_diff to accept positional tree paths and a --markdown output option. |
toolchain/mfc/args.py |
Adjusts parser default-population list to exclude count_diff. |
.github/workflows/line-count.yml |
Implements the PR sticky comment workflow using merge-base comparison under pull_request_target. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
os.path.isfile follows symlinks, so the previous guard rejected /dev/zero but happily counted src/common/x.f90 -> /etc/passwd, leaking a file's existence and size into a public PR comment. Worse, glob's ** recurses into symlinked directories, so a single src/common/link -> /etc pulled in every file beneath it, none of which are themselves symlinks and none of which an islink check would catch. Require instead that each path resolve to a regular file inside the tree being counted. Read lazily rather than via f.read(), so a large file in the tree costs one line of memory instead of all of it. Materialize the PR tree with git worktree from refs/pull/N/head in the base clone rather than with actions/checkout, which removes the checkout of untrusted code that CodeQL flags in this privileged workflow. Also say comment lines are excluded in the status line, which they always were.
b89c30a to
cfdfabc
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1753 +/- ##
=======================================
Coverage 61.61% 61.61%
=======================================
Files 84 84
Lines 21520 21520
Branches 3180 3180
=======================================
Hits 13259 13259
Misses 6082 6082
Partials 2179 2179 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
Makes the line-of-code diff actually visible:
github-actions[bot]now posts a single sticky comment on each PR showing which files changed size and by how much. Today./mfc.sh count_diffexists but its output only ever reaches the CI log, where nobody reads it.This is a port of tinygrad's LOC bot (
sz.py+szdiff.yml), with three deliberate departures:master. tinygrad compares PR head against currentmaster, so a stale branch is charged for other people's commits; they need a second job to detect that and post "the line count difference bot is disabled" instead. Fetchingrefs/pull/N/headand diffing againstgit merge-basemakes that failure mode impossible, and the extra job disappears../mfc.sh formatalready makes that unavailable here.pull_request_targetis required so that PRs from forks can be commented on at all — underpull_requesttheirGITHUB_TOKENis read-only. The safety invariant, noted in the workflow: the toolchain runs frombase/, andpr/is only ever opened and line-counted, never executed.persist-credentials: falseon the PR checkout, and no attacker-controlled string is interpolated into arun:block.Two fixes to
count_difffall out of pointing it at an untrusted tree: non-regular files are skipped (a symlinkedsrc/*.fpppointing at/dev/zerowould otherwise be read until the runner died) and reads useerrors="replace"(one non-UTF-8 byte in a comment — an accented name — would otherwise fail the job).Incidentally, the counter now recurses into
src/*/include, which the oldsrc/<dir>/*.*f*glob silently skipped — 13 files including the GPU macro headers.Type of change
Testing
The workflow itself cannot run until it is on
master, sincepull_request_targetreads the workflow file from the base branch. What was verified locally:count_diffagainst a real merge-base worktree of this branch, and againstmaster~5to exercise the negative-diff path; both the terminal table and the Markdown render correctly./dev/zerois skipped rather than read forever, and a Latin-1 byte in a comment counts normally instead of raisingUnicodeDecodeError.changed=true/falsestep logic underbash -e, GitHub's default shell.marocchino/sticky-pull-request-commentbehavior read from source:delete: truewith an empty body passes validation, and deleting a nonexistent comment returns cleanly rather than erroring../mfc.sh formatand./mfc.sh precheckpass. No Fortran changed, so no golden files are affected.Checklist
No test: this is CI plumbing whose only real integration point is GitHub Actions, which the test suite cannot reach. No docs: the CLI reference is generated and gitignored, and
count_diffis a CI-only command.One reviewer-facing note —
count_diffchanged signature from anMFC_PRenvironment variable to two positional tree paths (./mfc.sh count_diff <base> <pr>). Nothing outside the workflow called it.