Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ jobs:
with:
fetch-depth: 0

# Rules come from the committed .commitlintrc.json — the same file the local
# pre-commit commit-msg hook reads — so local and CI validation cannot drift.
- name: Install commitlint
run: npm install -g @commitlint/{cli,config-conventional}
# Rules come from the committed .commitlintrc.json, and the commitlint, preset and
# Node versions from the `commitlint` hook in .pre-commit-config.yaml. CI runs that
# same hook through pre-commit rather than its own npm install, so local and CI
# validation cannot drift.
- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Cache the pre-commit hook environment
uses: actions/cache@v6
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}

- name: Validate commits
run: |
Expand All @@ -37,9 +45,12 @@ jobs:
echo "No PR-unique commits to lint (mergeback/back-merge or merge-only PR)."
exit 0
fi
msg="${RUNNER_TEMP}/COMMIT_EDITMSG"
rc=0
while read -r sha; do
echo "── ${sha} ──"
git log -1 --format=%B "${sha}" | npx commitlint --verbose || rc=1
git log -1 --format=%B "${sha}" > "${msg}"
uvx pre-commit run commitlint --verbose \
--hook-stage commit-msg --commit-msg-filename "${msg}" || rc=1
done <<< "${commits}"
exit "${rc}"
19 changes: 15 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,21 @@ repos:
files: ^src/swgoh_comlink/
types: [python]

# ── Commitlint (mirrors CI commitlint job) ────────────────────────────
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.21.0
# ── Commitlint (CI's Commit Lint job runs this exact hook) ────────────
# Every version is pinned here and nowhere else: .github/workflows/commitlint.yml
# invokes this hook through pre-commit, so local and CI linting cannot drift. A
# third-party hook rev would only pin a caret range (its lockfile is not honoured),
# and commitlint changes rule behaviour across majors. Bump cli and
# config-conventional together; language_version makes pre-commit fetch its own Node
# (commitlint 21 needs >= 22.12) instead of depending on whatever is installed.
- repo: local
hooks:
- id: commitlint
name: commitlint
entry: commitlint --edit
language: node
language_version: "24.21.0"
stages: [commit-msg]
additional_dependencies: ["@commitlint/config-conventional"]
additional_dependencies:
- "@commitlint/cli@21.2.3"
- "@commitlint/config-conventional@21.2.3"
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ comlink-python/
│ ├── workflows/
│ │ ├── backmerge.yml # Stages the main → develop back-merge after a release
│ │ ├── ci.yml # CI pipeline (lint, type-check, test, docs, build)
│ │ ├── commitlint.yml # Commit message validation (npm-based)
│ │ ├── commitlint.yml # Commit message validation (runs the pre-commit hook)
│ │ ├── docs.yml # Publishes the docs site to GitHub Pages from main
│ │ ├── integration.yml # Integration tests against live comlink services
│ │ ├── labeler.yml # Auto-label PRs by file path
Expand Down Expand Up @@ -370,6 +370,9 @@ Other accepted types — `build`, `deps`, `chore`, `test`, `style`, `ci` — are

Types and scopes are defined in [`.commitlintrc.json`](.commitlintrc.json), the single config used by both the
pre-commit `commit-msg` hook and the CI **Commit Lint** check. Unknown scopes produce a warning, not a failure.
The commitlint, preset and Node versions are pinned once, on the `commitlint` hook in
[`.pre-commit-config.yaml`](.pre-commit-config.yaml); CI runs that same hook, so a message that passes locally
passes in CI.

**Examples:**

Expand Down
Loading