diff --git a/docs/changelog.md b/docs/changelog.md index f63adb7..67832fe 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -11,6 +11,7 @@ page that documents it. | Version | What changed | Documented in | |---|---|---| +| [2.20.3](#v2203) | Failures print a one-line header and an indented block per check, in place of the ASCII banner; an agent skill for coding agents | [Getting started](getting-started.md#2-watch-it-reject-something) · [With AI coding agents](guides/ai-agents.md#tell-the-agent) | | [2.20.1](#v2201) | `--ai-attribution-only` checks a pull request description against your AI policy; JSON lists the AI tools found; more AI marks recognised | [Checking a pull request description](guides/policies.md#checking-a-pull-request-description) · [CC013](rules.md#cc013) | | [2.20.0](#v2200) | Commits authored by an AI tool rejected; subject length `0` turns the rule off; Python 3.11+ required | [CC017](rules.md#cc017) · [CC013](rules.md#cc013) · [CC004](rules.md#cc004) | | [2.19.5](#v2195) | GitHub merge queue branches accepted by default; aider's default co-author trailer recognised; exit 2 when git cannot read the repository | [CC201](rules.md#cc201) · [CC013](rules.md#cc013) · [Exit codes](troubleshoot.md#exit-codes) | @@ -38,6 +39,29 @@ page that documents it. | [2.5.0](#v250) | Organization-wide config with `inherit_from` | [Across an organization](guides/organization.md) | | [2.0.0](#v200) | Configuration moved from YAML to TOML — breaking | [Migrating from v1](migration.md) | +## v2.20.4 (2026-11-10) { #v2204 } + +### Fixed + +* `require_body` no longer takes trailers alone, such as the `Signed-off-by:` line from `git commit -s`, for a body. ([CC011](rules.md#cc011), [#689](https://github.com/commit-check/commit-check/pull/689)) +* `ignore_authors` written as one string is split on commas, instead of skipping any author whose name is part of it. ([Every option](configuration.md#every-option), [#689](https://github.com/commit-check/commit-check/pull/689)) +* `--author-name` and `--author-email` honour `git commit --author` and the `author.name` and `author.email` settings. ([Checking the committer](example.md#checking-the-committer), [#689](https://github.com/commit-check/commit-check/pull/689)) + +## v2.20.3 (2026-11-10) { #v2203 } + +### Added + +* An agent skill teaches coding agents to check a message before they commit. ([With AI coding agents](guides/ai-agents.md#tell-the-agent), [#679](https://github.com/commit-check/commit-check/pull/679), [#686](https://github.com/commit-check/commit-check/pull/686)) + +### Changed + +* A failure prints a one-line header and an indented block per check, in place of the ASCII banner. ([Getting started](getting-started.md#2-watch-it-reject-something), [#682](https://github.com/commit-check/commit-check/pull/682)) + +### Fixed + +* CC017 on a message that is not committed yet suggests setting your own `user.name` and `user.email`, not amending. ([CC017](rules.md#cc017), [#685](https://github.com/commit-check/commit-check/pull/685)) +* `--ai-attribution-only` with no text piped in passes, instead of judging `HEAD`. ([Guide](guides/policies.md#checking-a-pull-request-description), [#684](https://github.com/commit-check/commit-check/pull/684)) + ## v2.20.2 (2026-11-08) { #v2202 } ### Changed diff --git a/docs/configuration.md b/docs/configuration.md index 20ac7be..5478bd0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -178,7 +178,7 @@ conventional_branch = true ``` A warned rule prints the same block as a failure with `warning` in place of -`failed`, no rejection banner, and one closing line saying the run is not +`failed`, no rejection header, and one closing line saying the run is not failed by it; with `--compact` it is one `[WARN]` line. A one-line notice on stderr names the warned rules, so a hook that exits `0` after red-looking output is not mistaken for a broken hook. The exit code counts only enforced diff --git a/docs/example.md b/docs/example.md index 0d78eb6..bd1c904 100644 --- a/docs/example.md +++ b/docs/example.md @@ -56,10 +56,12 @@ revision. ```console $ echo "updated the parser" | commit-check -m -CC001 message check failed ==> updated the parser -The commit message should follow Conventional Commits. See https://www.conventionalcommits.org -Suggest: Use (): , where is one of: feat, fix, ... -Docs: https://commit-check.com/rules/#cc001 +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC001 message failed: updated the parser + The commit message should follow Conventional Commits. See https://www.conventionalcommits.org + Suggest: Use (): , where is one of: feat, fix, docs, style, refactor, test, chore, perf, build, ci + Docs: https://commit-check.com/rules/#cc001 ``` Fix it and it goes quiet: @@ -140,6 +142,9 @@ tighten them. Without `--rev`, these validate the *local git config* — whoever is about to commit — falling back to `HEAD`'s author only when no identity is configured. +The identity is read in git's order: `GIT_AUTHOR_NAME` and +`GIT_AUTHOR_EMAIL` when set, then `author.name` and `author.email`, then +`user.name` and `user.email`. That is the right subject for a hook and the wrong one for CI: an existing commit's identity is a fact about the commit, not about the operator running the check. Add `--rev` and both checks read that commit's recorded author, and @@ -206,7 +211,7 @@ and how CLI, environment and file settings override each other. === "No banner" - Plain text without the ASCII art, which is noise in a CI log. + Plain text without the one-line header that counts the failed checks. ```console $ commit-check -m --no-banner diff --git a/docs/getting-started.md b/docs/getting-started.md index 42698bc..06ccd8a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -67,18 +67,21 @@ $ commit-check --message ``` ```text -CC001 message check failed ==> updated the parser -The commit message should follow Conventional Commits. See https://www.conventionalcommits.org -Suggest: Use (): , where is one of: feat, fix, docs, ... -Docs: https://commit-check.com/rules/#cc001 +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC001 message failed: updated the parser + The commit message should follow Conventional Commits. See https://www.conventionalcommits.org + Suggest: Use (): , where is one of: feat, fix, docs, style, refactor, test, chore, perf, build, ci + Docs: https://commit-check.com/rules/#cc001 ``` -Four things are happening in that output, and each is deliberate: +The first line counts the failed checks. Each failure under it carries four +things, and each is deliberate: | Part | What it gives you | |---|---| | `CC001` | A stable rule ID. It will mean the same thing in five years. | -| `==> updated the parser` | The exact value that failed, not just "invalid message". | +| `updated the parser` | The exact value that failed, not just "invalid message". | | `Suggest:` | What to do about it. | | `Docs:` | Why the rule exists, and how to configure or disable it. | @@ -99,10 +102,12 @@ $ commit-check --branch ``` ```text -CC201 branch check failed ==> my-changes -The branch should follow Conventional Branch. See https://conventionalbranch.org -Suggest: Use / with an allowed type, or add the branch to allow_branch_names in config -Docs: https://commit-check.com/rules/#cc201 +✖ Branch rejected by Commit Check · 1 check failed + +✖ CC201 branch failed: my-changes + The branch should follow Conventional Branch. See https://conventionalbranch.org + Suggest: Use / with an allowed type, or add the branch to allow_branch_names in config + Docs: https://commit-check.com/rules/#cc201 ``` Rename it to something structured and it passes: diff --git a/docs/guides/policies.md b/docs/guides/policies.md index 67743a1..94f7f9b 100644 --- a/docs/guides/policies.md +++ b/docs/guides/policies.md @@ -133,10 +133,12 @@ ai_attribution = "forbid" Commits carrying a recognised AI signature now fail: ```text -CC013 ai-attribution check failed ==> Claude Code -AI attribution is forbidden in this project — detected: Claude Code -Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. -Docs: https://commit-check.com/rules/#cc013 +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC013 ai-attribution failed: Claude Code + AI attribution is forbidden in this project — detected: Claude Code + Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. + Docs: https://commit-check.com/rules/#cc013 ``` Recognised signatures are co-author and sign-off lines naming Claude Code, @@ -255,15 +257,17 @@ A commit that a vendor stamped and nobody disclosed fails the first two, and the failure carries the disclosure already written: ```text -CC014 ai-disclosure check failed ==> Co-Authored-By: Claude Opus 5 -AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code -Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" -Docs: https://commit-check.com/rules/#cc014 - -CC015 ai-co-author check failed ==> Co-Authored-By: Claude Opus 5 -An AI tool is credited as a co-author: Claude Code -Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line -Docs: https://commit-check.com/rules/#cc015 +✖ Commit rejected by Commit Check · 2 checks failed + +✖ CC014 ai-disclosure failed: Co-Authored-By: Claude Opus 5 + AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code + Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" + Docs: https://commit-check.com/rules/#cc014 + +✖ CC015 ai-co-author failed: Co-Authored-By: Claude Opus 5 + An AI tool is credited as a co-author: Claude Code + Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line + Docs: https://commit-check.com/rules/#cc015 ``` Both carry the same correction in `--format json`: the co-author line rewritten @@ -306,9 +310,12 @@ ai_disclosure_pattern = '^\S+/\S+$' ``` ```text -CC014 ai-disclosure check failed ==> Assisted-by: Claude Code -The Assisted-by value does not match the required pattern: ^\S+/\S+$ -Suggest: Write the Assisted-by value so that it matches ^\S+/\S+$ (set by ai_disclosure_pattern in the [commit] config) +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC014 ai-disclosure failed: Assisted-by: Claude Code + The Assisted-by value does not match the required pattern: ^\S+/\S+$ + Suggest: Write the Assisted-by value so that it matches ^\S+/\S+$ (set by ai_disclosure_pattern in the [commit] config) + Docs: https://commit-check.com/rules/#cc014 ``` That failure carries no correction, because the tool should not guess which @@ -330,11 +337,11 @@ ai_attribution = "disclose" ``` ```text -CC014 ai-disclosure check warning ==> 🤖 Generated with [Claude -AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code -Suggest: Disclose the tool with "Assisted-by: Claude Code" -Docs: https://commit-check.com/rules/#cc014 -This rule is set to warn in the config; it does not fail the run. +▲ CC014 ai-disclosure warning: 🤖 Generated with [Claude + AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code + Suggest: Disclose the tool with "Assisted-by: Claude Code" + Docs: https://commit-check.com/rules/#cc014 + This rule is set to warn in the config; it does not fail the run. ``` The run still passes. The warning still suggests a disclosure that pip and diff --git a/docs/index.md b/docs/index.md index d71155a..d1d6f2b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -39,9 +39,9 @@ description: Commit policy as code for teams and AI agents. Messages, branches,
@@ -50,14 +50,14 @@ description: Commit policy as code for teams and AI agents. Messages, branches,
check commit messageFailed
- hook id: check-message
- exit code: 1
-
Commit rejected by Commit-Check.
-
CC001 message check failed ==> Fix: add streaming support
-
The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
-
Suggest: Use "fix: add streaming support"
-
Docs: https://commit-check.com/rules/#cc001
+
✖ Commit rejected by Commit Check · 1 check failed
+
✖ CC001 message failed: Fix: add streaming support
+
The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
+
Suggest: Use "fix: add streaming support"
+
Docs: https://commit-check.com/rules/#cc001
❯ git commit -m "fix: add streaming support"
check commit messagePassed
-
[feature/streaming 77663ff] fix: add streaming support
+
[feature/streaming 276fd07] fix: add streaming support
@@ -409,10 +409,10 @@ conventional_branch = true
  • A fix you can paste, whenever the correction is unambiguous.
  • - +

    $ echo "Fix: add streaming support" | commit-check -m

    -

    1CC001 message check failed ==>

    +

    1✖ CC001 message failed:

    2Fix: add streaming support

    3The commit message should follow Conventional Commits. See https://www.conventionalcommits.org

    4Suggest: Use "fix: add streaming support"

    diff --git a/docs/rules.md b/docs/rules.md index 599e883..ada02bd 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -7,10 +7,12 @@ review comments, issue templates, and tooling. Rule IDs appear in commit-check's output and in `--format json` results: ```text -CC003 subject-imperative check failed ==> docs: revamped the profile -Commit message should use imperative mood (e.g., 'fix bug' not 'fixed bug', 'add feature' not 'adding feature') -Suggest: Change the first verb to imperative form, e.g., 'fix' instead of 'fixed'/'fixes'/'fixing' -Docs: https://commit-check.com/rules/#cc003 +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC003 subject-imperative failed: docs: revamped the profile + Commit message should use imperative mood (e.g., 'fix bug' not 'fixed bug', 'add feature' not 'adding feature') + Suggest: Change the first verb to imperative form, e.g., 'fix' instead of 'fixed'/'fixes'/'fixing' + Docs: https://commit-check.com/rules/#cc003 ``` `--compact` prints one line per failure, keeping the rule ID and dropping the @@ -25,10 +27,12 @@ repeating the rule — and `--format json` carries the corrected value in a `fix` field (see [Reading the JSON](example.md#reading-the-json)): ```text -CC001 message check failed ==> Fix: add x -The commit message should follow Conventional Commits. See https://www.conventionalcommits.org -Suggest: Use "fix: add x" -Docs: https://commit-check.com/rules/#cc001 +✖ Commit rejected by Commit Check · 1 check failed + +✖ CC001 message failed: Fix: add x + The commit message should follow Conventional Commits. See https://www.conventionalcommits.org + Suggest: Use "fix: add x" + Docs: https://commit-check.com/rules/#cc001 ``` ## How to read this page @@ -489,7 +493,12 @@ git commit --amend -m "feat: add a caching layer for role lookups" **What it does** -Requires a non-empty body after the subject line. +Requires a non-empty body after the subject line. A closing block of +trailers is not a body, so a subject followed only by the `Signed-off-by:` +line that `git commit -s` adds still fails. A line counts as a trailer when +its key has a hyphen, as in `Co-authored-by:` or `Change-Id:`, or is one of +`Fixes`, `Closes`, `Resolves`, `Refs`, `Link`, `Cc` and `Bug`. Any other +one-word key, such as `Note:`, is read as body text. A message file is judged as the message git will store: comment lines, and everything from the `git commit -v` scissors line on, do not count. So a @@ -592,9 +601,9 @@ mechanically rather than relitigated in every review. **Example** ```text -CC013 ai-attribution check failed ==> Claude Code -AI attribution is forbidden in this project — detected: Claude Code -Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. +✖ CC013 ai-attribution failed: Claude Code + AI attribution is forbidden in this project — detected: Claude Code + Suggest: This project does not accept AI attribution in commit messages. Remove the AI trailer lines and re-commit. ``` **Options** @@ -632,9 +641,9 @@ commits that look much the same. **Example** ```text -CC014 ai-disclosure check failed ==> Co-Authored-By: Claude Opus 5 -AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code -Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" +✖ CC014 ai-disclosure failed: Co-Authored-By: Claude Opus 5 + AI assistance is not disclosed with Assisted-by or Generated-by — detected: Claude Code + Suggest: Disclose the tool with "Assisted-by: Claude Opus 5" ``` The suggestion keeps the name the tool gave itself, and `--format json` @@ -668,9 +677,9 @@ and authorship are different claims. **Example** ```text -CC015 ai-co-author check failed ==> Co-Authored-By: Claude Opus 5 -An AI tool is credited as a co-author: Claude Code -Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line +✖ CC015 ai-co-author failed: Co-Authored-By: Claude Opus 5 + An AI tool is credited as a co-author: Claude Code + Suggest: Use "Assisted-by: Claude Opus 5" in place of the co-author line ``` **Options** @@ -698,9 +707,9 @@ off by accepting it as a disclosure. **Example** ```text -CC016 ai-signoff check failed ==> Signed-off-by: Claude -An AI tool signed off the commit: Claude Code -Suggest: Use "Assisted-by: Claude" in place of the AI sign-off, then sign off yourself (git commit --signoff) +✖ CC016 ai-signoff failed: Signed-off-by: Claude + An AI tool signed off the commit: Claude Code + Suggest: Use "Assisted-by: Claude" in place of the AI sign-off, then sign off yourself (git commit --signoff) ``` **Options** @@ -721,8 +730,9 @@ ending in `(aider)`, or any name at a tool's own address such as An existing commit is judged by the author it records. A message piped in, or one the `commit-msg` hook checks before the commit exists, is judged by the author git would record: `GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL` when -set, otherwise `user.name` and `user.email`. The GitHub Action passes each -pull request commit's own author this way. +set, then `author.name` and `author.email`, then `user.name` and +`user.email`. The GitHub Action passes each pull request commit's own author +this way. **Why is this bad?** @@ -735,12 +745,17 @@ is, and it is what GitHub shows as the contributor. **Example** ```text -CC017 ai-author check failed ==> google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> -An AI tool is the commit author: Jules -Suggest: Author the commit yourself: git commit --amend --reset-author +✖ CC017 ai-author failed: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> + An AI tool is the commit author: Jules + Suggest: Author the commit yourself: git commit --amend --reset-author ``` -The commit fails even with a human `Co-authored-by:` line. +The commit fails even with a human `Co-authored-by:` line. When the message +is checked before the commit exists, there is nothing to amend yet, so the +suggestion is to set `user.name` and `user.email` to your own and to unset +`GIT_AUTHOR_NAME` and `GIT_AUTHOR_EMAIL`. If `author.name` or `author.email` +names the tool, unset those as well: they outrank `user.name` and +`user.email`. **Options** diff --git a/docs/troubleshoot.md b/docs/troubleshoot.md index 1033dfd..1b71da0 100644 --- a/docs/troubleshoot.md +++ b/docs/troubleshoot.md @@ -15,12 +15,12 @@ check committer name.....................................................Failed - hook id: check-author-name - exit code: 1 -Commit rejected by Commit-Check. +✖ Commit rejected by Commit Check · 1 check failed -CC101 author-name check failed ==> 12 -The committer name seems invalid -Suggest: git config user.name 'Your Name' -Docs: https://commit-check.com/rules/#cc101 +✖ CC101 author-name failed: 12 + The committer name seems invalid + Suggest: git config user.name 'Your Name' + Docs: https://commit-check.com/rules/#cc101 ``` `12` is the configured `user.name` — usually a sign that diff --git a/tests/docs_sync_test.py b/tests/docs_sync_test.py index ab6a313..babb646 100644 --- a/tests/docs_sync_test.py +++ b/tests/docs_sync_test.py @@ -29,8 +29,12 @@ def _read_doc(name: str) -> str: return (DOCS / name).read_text(encoding="utf-8") -#: A pasted failure line, e.g. ``CC003 subject-imperative check failed ==> ...`` -_SAMPLE_FAILURE = re.compile(r"(CC\d{3}) (\S+) check failed ==>") +#: A pasted failure or warning line, e.g. ``✖ CC003 subject-imperative +#: failed: ...``, the form printed since 2.20.3. Dated blog posts keep the +#: earlier ``CC003 subject-imperative check failed ==> ...``, so both match. +_SAMPLE_FAILURE = re.compile( + r"(CC\d{3}) (\S+) (?:check failed ==>|(?:failed|warning):)" +) #: A pasted ``--compact`` line, e.g. ``[FAIL] CC003 subject-imperative: ...``. #: Indented, because these samples sit inside content tabs.