-
Notifications
You must be signed in to change notification settings - Fork 0
ci: add conventional commits guardrail #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||||
| /** | ||||||
| * Conventional Commits grammar used by the Conventional Commits CI guardrail. | ||||||
| * | ||||||
| * Extends @commitlint/config-conventional and keeps its remaining defaults | ||||||
| * (type/subject/scope casing, subject-full-stop), with these policy overrides: | ||||||
| * | ||||||
| * - type-enum: the project allowlist (see CONTRIBUTING.md). | ||||||
| * - header/body/footer length limits are disabled; the grammar does not | ||||||
| * enforce message lengths. | ||||||
| * - A custom rule enforces a well-formed breaking-change marker on commit | ||||||
| * messages: any line whose token is a spelling/case variant of | ||||||
| * BREAKING CHANGE / BREAKING-CHANGE must be exactly | ||||||
| * `BREAKING CHANGE: <non-empty explanation>` or | ||||||
| * `BREAKING-CHANGE: <non-empty explanation>` (exact-case token, colon, | ||||||
| * non-empty explanation; the explanation may continue on following lines). | ||||||
| */ | ||||||
| export default { | ||||||
| extends: ['@commitlint/config-conventional'], | ||||||
| plugins: [ | ||||||
| { | ||||||
| rules: { | ||||||
| 'breaking-change-format': ({ raw }) => { | ||||||
| const lines = String(raw).split(/\r?\n/); | ||||||
| for (const [index, line] of lines.entries()) { | ||||||
| const token = line.replace(/^[ \t]+/, ''); | ||||||
| if (!/^breaking[\s_-]+change/i.test(token)) { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Add a boundary after The pattern matches valid body prose such as Proposed fix- if (!/^breaking[\s_-]+change/i.test(token)) {
+ if (!/^breaking[\s_-]+change\b/i.test(token)) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| continue; | ||||||
| } | ||||||
| const matches = token.match(/^BREAKING[ -]CHANGE:(.*)$/); | ||||||
| let explained = | ||||||
| matches !== null && /[^ \t]/.test(matches[1] ?? ''); | ||||||
| if (!explained) { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Reject an invalid marker before checking continuation lines. When Proposed fix const matches = token.match(/^BREAKING[ -]CHANGE:(.*)$/);
- let explained =
- matches !== null && /[^ \t]/.test(matches[1] ?? '');
+ if (matches === null) {
+ return [
+ false,
+ `breaking change marker must be "BREAKING CHANGE: <explanation>" or "BREAKING-CHANGE: <explanation>" with a non-empty explanation, found: ${JSON.stringify(token)}`,
+ ];
+ }
+ let explained = /[^ \t]/.test(matches[1]);🤖 Prompt for AI Agents |
||||||
| // The explanation may be continued on the following footer | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Superseded by KAZ-11 refinement KAZ-11 no longer requires bespoke validation of malformed |
||||||
| // lines; a blank line ends the footer paragraph. | ||||||
| for (let j = index + 1; j < lines.length; j++) { | ||||||
| if (lines[j].trim() === '') { | ||||||
| break; | ||||||
| } | ||||||
| if (/[^ \t]/.test(lines[j])) { | ||||||
| explained = true; | ||||||
| break; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| if (!explained) { | ||||||
| return [ | ||||||
| false, | ||||||
| `breaking change marker must be "BREAKING CHANGE: <explanation>" or "BREAKING-CHANGE: <explanation>" with a non-empty explanation, found: ${JSON.stringify(token)}`, | ||||||
| ]; | ||||||
| } | ||||||
| } | ||||||
| return [true, '']; | ||||||
| }, | ||||||
| }, | ||||||
| }, | ||||||
| ], | ||||||
| rules: { | ||||||
| 'type-enum': [ | ||||||
| 2, | ||||||
| 'always', | ||||||
| [ | ||||||
| 'feat', | ||||||
| 'fix', | ||||||
| 'perf', | ||||||
| 'refactor', | ||||||
| 'docs', | ||||||
| 'test', | ||||||
| 'build', | ||||||
| 'ci', | ||||||
| 'chore', | ||||||
| 'revert', | ||||||
| ], | ||||||
| ], | ||||||
| 'breaking-change-format': [2, 'always'], | ||||||
| 'header-max-length': [0], | ||||||
| 'body-max-line-length': [0], | ||||||
| 'footer-max-line-length': [0], | ||||||
| }, | ||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * Title-only lint configuration: the Conventional Commits workflow checks the | ||
| * pull-request title through stdin, and commitlint's default ignore wildcards | ||
| * ("Merge ...", "Revert ...", ...) also filter stdin reads. Git-generated | ||
| * merge/revert lines are valid commit-message forms that must be skipped in | ||
| * commit-range reads, but a PR *title* adopting those forms must fail the | ||
| * grammar. This config therefore keeps every grammar rule from the shared | ||
| * configuration while disabling the default ignores for the title read. | ||
| */ | ||
| import baseConfig from './commitlint.config.mjs'; | ||
|
|
||
| export default { | ||
| ...baseConfig, | ||
| defaultIgnores: false, | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Superseded by KAZ-11 refinement
The ticket has been simplified after review: KAZ-11 now explicitly prefers standard
@commitlint/config-conventionalbehavior with minimal project-specific overrides. This finding was based on the earlier custom grammar contract and is no longer a blocker by itself. Keep the preset unless there is a specific style rule we deliberately do not want.