Skip to content

ci: use a maintained commitlint action fork - #20

Merged
robinbowes merged 1 commit into
mainfrom
fix/commitlint-ci-version-skew
Aug 11, 2026
Merged

ci: use a maintained commitlint action fork#20
robinbowes merged 1 commit into
mainfrom
fix/commitlint-ci-version-skew

Conversation

@robinbowes

@robinbowes robinbowes commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

What

Points the commitlint job at yo61/commitlint-github-action — a maintained fork running commitlint v21 on Node 24.

Why

Dependabot PRs fail the commitlint job on body-max-line-length, while the pre-commit lint job passes the same commit. Same commit, same commitlint.config.mjs, different verdict.

@commitlint/ensure v20 added an exemption for long lines containing a URL:

const URL_REGEX = /\bhttps?:\/\/\S+/;
value.split(/\r?\n/).every((line) => URL_REGEX.test(line) || ensure(line, max));

wagoid/commitlint-github-action@v6.2.1 is the latest release and pins @commitlint/ensure: ^19.0.3, so CI enforced a stricter rule than the config intends. Dependabot bodies are markdown link lists — one real example is 314 characters on a single line.

Upstream is unmaintained: no commit to master since 2025-01-14, and the v20 bump (PR #837) has been open and mergeable since July with no response.

The fork

yo61/commitlint-github-action@v6.3.0 — all @commitlint/* at ^21, Node 24.19.0 LTS (v21 needs node >= 22.12), commitlint-plugin-function-rules at ^5 (v4's peer range caps at <20 and breaks npm ci), published to ghcr.io from a pushed tag. Actions SHA-pinned, least-privilege permissions, actionlint and zizmor clean.

Verified against the action's own load+lint path with a real commitlint.config.mjs:

Case Result
Dependabot commit, 314-char body line valid
Sentence-case subject with subject-case: [0] valid — the .mjs override is honored
Malformed commit rejected

Commit subjects stay validated for Dependabot as well as humans, rather than exempting bot commits.

yo61-lastlight[bot]
yo61-lastlight Bot previously approved these changes Aug 11, 2026

@yo61-lastlight yo61-lastlight Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaces wagoid/commitlint-github-action (which pins @commitlint/ensure ^19, predating the v20 URL exemption in body-max-line-length) with a direct npx-run of commitlint pinned to the same major (v21) used by the pre-commit hook, fixing the CI/local skew described in the PR body. The env-var indirection for BASE_SHA/HEAD_SHA avoids shell interpolation of untrusted values, the permissions change (pull-requests: read -> contents: read) correctly follows the action's replacement (range now comes from local git via fetch-depth: 0), and the fix is scoped to a single workflow file with no test/config changes needed. No correctness, contract, or security issues found.

@yo61-lastlight

Copy link
Copy Markdown
Contributor

pr-review is waiting for cluster capacity — it'll start automatically when a slot frees.

@yo61-lastlight yo61-lastlight Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaces the stale commitlint action with a directly-pinned run, but the CI job for this PR's own head commit is currently failing (run 31493095772, 'Lint commit messages' step) — reproduced locally: commitlint installs into .github/commitlint/node_modules while commitlint.config.mjs lives at the repo root, so Node can't resolve extends: ['@commitlint/config-conventional'] from the config file's own directory and the job errors out (MODULE_NOT_FOUND) before linting anything. This breaks CI harder than the skew it's fixing — every future PR, human or Dependabot, fails until this is corrected. A prior bot review approved an earlier commit in this PR (before the manifest-pinning commit was pushed); it is dismissed and superseded by this one.

Comment thread .github/workflows/ci.yml Outdated
Comment on lines +37 to +45
- name: Lint commit messages
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
./.github/commitlint/node_modules/.bin/commitlint \
--config commitlint.config.mjs \
--from "$BASE_SHA" --to "$HEAD_SHA" --verbose

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Critical] commitlint can't resolve @commitlint/config-conventional — job fails on every PR

commitlint.config.mjs (repo root) does extends: ['@commitlint/config-conventional']. @commitlint/resolve-extends resolves that module starting from the config file's own directory (the repo root), not from cwd or --cwd — confirmed by testing --cwd .github/commitlint here, which still fails the same way. Since the package is only installed under .github/commitlint/node_modules, this throws Error: Cannot find module "@commitlint/config-conventional" from "<repo root>" on every invocation. Reproduced locally with the exact workflow command, and it matches this PR's own failing CI run (https://github.com/yo61/claude-plugin-reportlab-pdf/actions/runs/31493095772). Setting NODE_PATH to the nested node_modules before invoking commitlint fixes it locally (verified: 0 problems on this PR's own commits, and the control commit with an empty subject still fails as expected).

Suggested change
- name: Lint commit messages
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
./.github/commitlint/node_modules/.bin/commitlint \
--config commitlint.config.mjs \
--from "$BASE_SHA" --to "$HEAD_SHA" --verbose
- name: Lint commit messages
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
NODE_PATH: ${{ github.workspace }}/.github/commitlint/node_modules
run: |
set -euo pipefail
./.github/commitlint/node_modules/.bin/commitlint \
--config commitlint.config.mjs \
--from "$BASE_SHA" --to "$HEAD_SHA" --verbose

@robinbowes
robinbowes force-pushed the fix/commitlint-ci-version-skew branch from 82ad2e2 to c3a8a15 Compare August 11, 2026 13:13
wagoid/commitlint-github-action pins @commitlint/ensure ^19. The
exemption for long lines containing a URL landed in v20, so CI enforced
a stricter rule than the config intended and failed Dependabot commits
on body-max-line-length, while the pre-commit hook resolving v21 passed
the same commit.

Upstream is unmaintained: master has had no commit since 2025-01-14 and
the v20 bump has sat open since July. Point at yo61/commitlint-github-action
instead, which runs commitlint v21 on node 24 and is published to ghcr.io.
@robinbowes robinbowes changed the title ci: run commitlint directly instead of stale action ci: use a maintained commitlint action fork Aug 11, 2026
@robinbowes
robinbowes force-pushed the fix/commitlint-ci-version-skew branch from c3a8a15 to 7dec54c Compare August 11, 2026 13:39

@yo61-lastlight yo61-lastlight Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior findings ledger: my previous CHANGES_REQUESTED (MODULE_NOT_FOUND resolving @commitlint/config-conventional from the nested .github/commitlint/node_modules install, and the earlier tracked-manifest/npm-ci approach it was raised against) — withdrawn. That approach was abandoned wholesale: this commit is built directly on main, not on top of the two commits (c3a8a15, 82ad2e2) that introduced it, so the code the finding pointed at no longer exists on this branch. The current diff takes a different, simpler tack: swap the stale wagoid/commitlint-github-action pin for yo61/commitlint-github-action@v6.3.0 (a fork on @commitlint v21/Node 24), same configFile: commitlint.config.mjs interface as before. I independently confirmed the pinned SHA (31e5e0454fc0709625e6dcfb502ea18978f45f15) is the current tip of the fork's master and matches the referenced v6.3.0 tag/ghcr.io image, and that permissions: pull-requests: read on the job is still correct for this action (it hits the GitHub API via github.token, unlike the dropped direct-npx-run variant which needed contents:read instead). No correctness, contract, or security issues found in the one-line action swap.

@robinbowes
robinbowes merged commit 4cefc8f into main Aug 11, 2026
3 checks passed
@robinbowes
robinbowes deleted the fix/commitlint-ci-version-skew branch August 11, 2026 13:51
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.

1 participant