Skip to content

chore(NO-TASK): Explain which part of a commit header failed - #6

Merged
aaronware merged 1 commit into
mainfrom
chore/NO-TASK/header-diagnostics
Aug 8, 2026
Merged

chore(NO-TASK): Explain which part of a commit header failed#6
aaronware merged 1 commit into
mainfrom
chore/NO-TASK/header-diagnostics

Conversation

@aaronware

Copy link
Copy Markdown
Contributor

Better failure output when a commit message is rejected.

Two problems

1. The messages block was dead config. The config carried a top-level messages key with friendly text for type-enum, subject-case and header-pattern. That is not a commitlint option — none of it ever reached a user.

2. What they saw instead was actively misleading. When headerPattern fails to match, the parser extracts nothing, so the built-in rules report an empty type and subject regardless of the real cause:

$ echo "nope(PROJ-123): Bad type here" | npx commitlint
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

The subject is right there. The actual problem — nope is not a valid type — is never mentioned.

After

✖   "nope" is not a valid type.
      Valid types: add, improve, build, chore, ci, docs, feat, feature, fix, ...

It names the failing part and suggests a fix for the common near-misses:

Input Output
nope(PROJ-123): … "nope" is not a valid type + the valid list
feat(deps): … "deps" is not a valid scope + the three valid forms
feat(proj-123): … Task keys are uppercase - try "PROJ-123"
feat(NOTASK): … Write it exactly as NO-TASK
feat: No scope The scope is missing
feat(NO-TASK): The subject is missing

How

Diagnostics come from a linchpin-header rule registered via plugins — the only way a commitlint config can supply its own message text. type-empty and subject-empty are silenced, since they only ever fire as noise alongside the real diagnosis.

Because this ships in the shared package, all 71 repos in the rollout get it.

Verification

  • 28 tests pass (11 new, covering each diagnostic and that valid messages are unaffected)
  • All valid forms still pass cleanly: feat(PROJ-123):, fix(NO-TASK):, docs(#42):, add(…), remove(…), feature(…)
  • The release-please ignore from fix(NO-TASK): Ignore release-please release commits #5 still works

Task: NO-TASK

🤖 Generated with Claude Code

The config carried a top-level messages key that is not a commitlint option,
so none of it ever reached the user. What they saw instead was misleading:
when headerPattern fails to match, the parser extracts nothing, so a
misspelled type reported as type-empty and subject-empty - two errors that
never mention the real problem.

Diagnostics now come from a linchpin-header rule registered as a plugin,
which is the only way a config can supply its own message text. It names the
part that failed and suggests a fix for the common near-misses: a lowercase
task key, NOTASK for NO-TASK, and a missing scope or subject.

type-empty and subject-empty are silenced because they only ever fire as
noise alongside the real diagnosis.

  nope(PROJ-123): Bad type here
    before: subject may not be empty / type may not be empty
    after:  "nope" is not a valid type. Valid types: add, improve, ...
@aaronware
aaronware merged commit 7bb9fc2 into main Aug 8, 2026
5 checks passed
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