ophi-dev/mehen GitHub Action computes changed-file metric trends on every pull
request, compares them against the base branch, and publishes a sticky comment with the deltas. It is
the primary consumption surface for mehen today.

The sticky PR comment: a Source Code Metrics table with per-file this-PR-vs-main deltas, followed by a Documentation Metrics table for changed Markdown.
Minimal workflow
.github/workflows/mehen.yml
mehen CLI, runs mehen diff against the PR’s base
branch, and posts a sticky comment with the per-file metric deltas.
Polyglot monorepo
For monorepos, pass each tracked root and let mehen pick supported languages from changed files in those trees:Inputs
Outputs
Permissions
The action needs to write PR comments:contents: read lets the runner check out the repo. pull-requests: write and issues: write let the
action upsert the sticky comment.
Sticky comment
The action posts a single comment on the PR and updates it on each push instead of stacking new comments. The Markdown layout, cell format, and callout catalog are documented on the PR comment design page.Markdown documentation section
When a PR touches Markdown files,mehen diff emits a Documentation Metrics section inside the
same sticky comment, anchored by <!-- mehen-docs --> (visible in the screenshot above). It carries a
five-column headline table (DMI, Words, FKGL/Tateishi RS, Link Debt, Filler Risk), severity-ranked
callouts drawn from a fixed template catalog, and a collapsed drill-down with the deeper structural,
wording, and readability tables. On code-only PRs the section is suppressed entirely. The full
specification — anchor rules, cell format, callout catalog, and --fail-on gating — is on the
PR comment design page.
SQL in the diff
SQL files are analyzed automatically and appear in the same Source Code Metrics table on the PR comment. Because SQL and source-code files publish different metric families, a mixed PR renders a single table whose columns are the union of each language’s defaults — every row fills only the columns its analyzer emits, and the rest render as–. This keeps SQL changes visible on the default
action path instead of silently dropping out. See mehen diff for how the default
metric set is resolved per file language.
Coverage trends
Pointcoverage-files at the report(s) your test step already writes and the sticky comment gains a
Coverage column with real trend arrows — head value vs. the base revision’s value:
mehen diff --coverage=<file>. The base side is retrieved
by the action — mehen itself stays network-free — walking a degradation ladder whose every rung is
disclosed in the PR comment, never silently:
- Exact cache hit — on every push to the default branch the action saves your
coverage-filesto the Actions cache undermehen-coverage-<sha>; a PR restores the entry for its exact base SHA. - Workflow artifact by base SHA — opt-in via
coverage-artifact-name: if your workflow already uploads coverage reports as an artifact (many do — including the upload job GitHub Code Quality’s setup generates), the artifact from the base SHA’s run is downloaded and its files handed to--base-coverage. Artifacts persist ~90 days where cache entries evict after 7 unused days, so this rung survives long-lived PRs. Requiresactions: readon the job. - codecov.io by base SHA — the commit report is fetched from the codecov API and converted to
LCOV (line dimension only: codecov’s merged view has no original branch arms, and fabricated ones
would poison
coverage.branchgates). This is the durable source of last resort for exact-SHA data. - Nearest default-branch cache — a prefix-key fallback that is recency-based, not ancestor-aware; the comment discloses that trends may compare against an older commit, and mehen itself warns when the restored report predates the base commit.
- Absent — coverage cells show head values without a base to compare against
(
85 (main: n/a)on changed files,85 🆕on new ones), never fabricated regressions.
coverage-base-source pins the ladder to one source: cache (rungs 1 → 4 → 5), artifact
(2 → 5), codecov (3 → 5), or off (head-side coverage only). A retrieved report that mehen
cannot parse (a truncated cache entry, an artifact with unexpected content) degrades to absent with
a disclosure instead of failing the action.
The cache-save rung requires the action to run on default-branch pushes too (after the same test
step), so trigger the workflow with both on: pull_request and on: push: branches: [main].
Works with GitHub Code Quality
GitHub Code Quality (Team/Enterprise Cloud) checks an aggregate line-coverage percentage on pull requests from a Cobertura XML report uploaded viaactions/upload-code-coverage. Cobertura is one
of mehen’s six ingestion formats, so the same report feeds both consumers — one test run, no
extra tooling. GitHub’s upload needs the code-quality: write permission on the job, on top of the
permissions the mehen action needs:
- Both consumers need the report to describe the head revision: GitHub’s docs mandate checking
out
pull_request.head.sha(not the merge commit) “so coverage line numbers map correctly to the diff” — the same-revision rule mehen’s diff relies on as well. - If GitHub’s generated upload job stores the Cobertura file as a workflow artifact (its default
pattern), point
coverage-artifact-nameat that artifact and the base-coverage ladder reuses it — no extra uploads. - Prefer a format with branch records (e.g. LCOV) for
coverage-fileswhen your tooling offers both; GitHub needs the Cobertura serialization, but mehen’scoverage.branchdimension can only be measured from reports that carry branch data. This repository does exactly that: onellvm-covcollection, serialized twice (coverage.yml).
Examples
- Strict gating
- Comment-only (advisory)
- Pin a version
- Use a pre-installed binary
See also
- Commands → diff — the underlying CLI command.
- Concepts → Thresholds and diffs.
- PR comment design — full Markdown spec.