Skip to main content
The official 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.
mehen GitHub Action sticky comment showing a Source Code Metrics table (Cyclomatic, Cognitive, Functions, LLOC, MI columns with green/red/white delta indicators) and a Documentation Metrics table (DMI, Words, FKGL, Link Debt, Filler Risk).

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.

Each cell shows the new value with the base-branch value in parentheses and a colored indicator — 🟢 improvement, 🔴 regression, ⚪ no material change — so reviewers see at a glance which files a PR made more or less complex.

Minimal workflow

.github/workflows/mehen.yml
That’s the whole setup. The action installs the 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. Point coverage-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:
The head side is simply passed to 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:
  1. Exact cache hit — on every push to the default branch the action saves your coverage-files to the Actions cache under mehen-coverage-<sha>; a PR restores the entry for its exact base SHA.
  2. 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. Requires actions: read on the job.
  3. 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.branch gates). This is the durable source of last resort for exact-SHA data.
  4. 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.
  5. 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.
codecov-token must be a personal API access token — generate one under Settings → Access on app.codecov.io. The CODECOV_TOKEN repository upload token most repos already have in secrets is a different credential and the API rejects it. On public repositories the token can be omitted entirely.
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 via actions/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:
The two are complementary: GitHub gives the aggregate percentage and merge-blocking rulesets on its own plans; mehen gives per-file trend columns, per-function coverage attribution, branch/function dimensions where the format carries them, and works on any plan — including GHES — with no network access in the binary. Notes for shared setups:
  • 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-name at that artifact and the base-coverage ladder reuses it — no extra uploads.
  • Prefer a format with branch records (e.g. LCOV) for coverage-files when your tooling offers both; GitHub needs the Cobertura serialization, but mehen’s coverage.branch dimension can only be measured from reports that carry branch data. This repository does exactly that: one llvm-cov collection, serialized twice (coverage.yml).

Examples

See also