Skip to content

feat(cz-commitlint): add exclamation mark support for breaking changes#4655

Merged
escapedcat merged 1 commit intoconventional-changelog:masterfrom
mrt181:feat/exclamation-mark-breaking-change
Mar 13, 2026
Merged

feat(cz-commitlint): add exclamation mark support for breaking changes#4655
escapedcat merged 1 commit intoconventional-changelog:masterfrom
mrt181:feat/exclamation-mark-breaking-change

Conversation

@mrt181
Copy link
Copy Markdown
Contributor

@mrt181 mrt181 commented Mar 12, 2026

Description

Add opt-in prompt.settings.useExclamationMark setting that appends ! after the type/scope prefix in the commit header when a breaking change is indicated (e.g. feat!: or feat(api)!:).
Opt-in via prompt.settings.useExclamationMark (default: false).

Motivation and Context

The Conventional Commits 1.0.0 spec defines ! after the type/scope as a way to draw attention to breaking changes. Currently @commitlint/cz-commitlint only adds BREAKING CHANGE: to the footer but never modifies the header.

Usage examples

// commitlint.config.js
module.exports = {
  extends: ["@commitlint/config-conventional"],
  prompt: {
    settings: {
      useExclamationMark: true,
    },
  },
};

// .commintlintrc.json
{
  "extends": ["@commitlint/config-conventional"],
  "prompt": {
    "settings": {
      "useExclamationMark": true
    }
  }
}
echo "feat(cz-commitlint): add exclamation mark support for breaking changes" | commitlint # passes

How Has This Been Tested?

5 new test cases in SectionHeader.test.ts covering:

  • ! after type with breaking + enabled
  • ! after scope with breaking + enabled
  • No ! when breaking but disabled (default)
  • No ! when enabled but not breaking
  • ! without subject when breaking + enabled

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Add exclamation mark support for breaking changes in commit headers

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add opt-in useExclamationMark setting for breaking change notation
• Appends ! after type/scope in commit header per Conventional Commits spec
• Includes comprehensive test coverage for all scenarios
• Updates type definitions and documentation
Diagram
flowchart LR
  A["User enables useExclamationMark setting"] --> B["combineCommitMessage function"]
  C["isBreaking flag set to true"] --> B
  B --> D["Append ! after type/scope"]
  D --> E["feat!: or feat(scope)!: format"]
Loading

Grey Divider

File Changes

1. @commitlint/cz-commitlint/src/SectionHeader.ts ✨ Enhancement +4/-2

Implement exclamation mark logic in message builder

• Extract isBreaking from answers parameter
• Add logic to conditionally append ! based on useExclamationMark setting
• Include breaking mark in prefix construction

@commitlint/cz-commitlint/src/SectionHeader.ts


2. @commitlint/cz-commitlint/src/SectionHeader.test.ts 🧪 Tests +69/-0

Add comprehensive test coverage for exclamation mark feature

• Add 5 new test cases covering breaking change scenarios
• Test ! placement after type and scope
• Verify default disabled behavior
• Test edge cases with empty subject

@commitlint/cz-commitlint/src/SectionHeader.test.ts


3. @commitlint/cz-commitlint/src/store/defaultPromptConfigs.ts ⚙️ Configuration changes +1/-0

Add default configuration for exclamation mark setting

• Add useExclamationMark setting with default value of false
• Maintain backward compatibility with opt-in approach

@commitlint/cz-commitlint/src/store/defaultPromptConfigs.ts


View more (2)
4. @commitlint/types/src/prompt.ts ✨ Enhancement +1/-0

Update type definitions for exclamation mark setting

• Add useExclamationMark boolean property to PromptConfig settings type
• Extend type definitions to support new feature

@commitlint/types/src/prompt.ts


5. docs/reference/prompt.md 📝 Documentation +1/-0

Document exclamation mark configuration option

• Document new useExclamationMark setting and its behavior
• Explain default disabled state and Conventional Commits compliance

docs/reference/prompt.md


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Header length off-by-one 🐞 Bug ✓ Correctness
Description
HeaderQuestion.beforeQuestionStart() computes remaining header length using
combineCommitMessage(answers) before isBreaking is asked, so it may allow a subject that fits
without ! but produces a final header exceeding header-max-length once isBreaking becomes
true. This can lead to generated commit messages that violate commitlint header length rules despite
the prompt’s length validation.
Code

@commitlint/cz-commitlint/src/SectionHeader.ts[R30-33]

+	const { type = "", scope = "", subject = "", isBreaking } = answers;
+	const breakingMark =
+		isBreaking && getPromptSettings()["useExclamationMark"] ? "!" : "";
+	const prefix = `${type}${scope ? `(${scope})` : ""}${breakingMark}`;
Evidence
The header prompt enforces input lengths using HeaderQuestion.beforeQuestionStart() and
Question.validate(). The new combineCommitMessage() adds a ! only when answers.isBreaking is
true, but isBreaking is collected later because the prompt question order is header -> body ->
footer; therefore, during header prompting answers.isBreaking is still unset and the computed
remaining length does not reserve space for a later !.

@commitlint/cz-commitlint/src/SectionHeader.ts[21-39]
@commitlint/cz-commitlint/src/Process.ts[26-38]
@commitlint/cz-commitlint/src/SectionFooter.ts[41-83]
@commitlint/cz-commitlint/src/Question.ts[137-156]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`combineCommitMessage()` now adds an exclamation mark based on `answers.isBreaking`, but `isBreaking` is answered in the footer section after header questions. Header input max-length is computed during header prompting via `HeaderQuestion.beforeQuestionStart()`, so it can’t account for the later `!`, allowing a subject that later produces an over-long header.

## Issue Context
The prompt pipeline in `Process.ts` asks header questions before footer questions, and `Question.validate()` enforces max length based on the per-question `maxLength` computed in `beforeQuestionStart()`.

## Fix Focus Areas
- @commitlint/cz-commitlint/src/SectionHeader.ts[21-39]
- @commitlint/cz-commitlint/src/Process.ts[26-38]
- @commitlint/cz-commitlint/src/SectionFooter.ts[41-83]

## Suggested direction
Implement one of:
1) Conservative reservation: when `getPromptSettings().useExclamationMark` is true and the `isBreaking` question exists but `answers.isBreaking` is still `undefined`, reserve 1 char in header remaining length computations.
2) Reorder questions so `isBreaking` is asked before validating the `subject` question’s max length (e.g., insert `isBreaking` immediately after `type/scope` and before `subject`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. PromptConfig type is breaking 🐞 Bug ⛯ Reliability
Description
@commitlint/types adds useExclamationMark as a required property on the exported
PromptConfig.settings type, which can break TypeScript consumers that construct PromptConfig
objects without this field. Runtime behavior is safe due to defaults, but downstream compilation can
fail without an update or a major version bump.
Code

@commitlint/types/src/prompt.ts[R19-23]

	settings: {
		scopeEnumSeparator: string;
		enableMultipleScopes: boolean;
+		useExclamationMark: boolean;
	};
Evidence
PromptConfig is exported from @commitlint/types and its settings object now requires
useExclamationMark. Although cz-commitlint provides a default value in defaultPromptConfigs,
TypeScript consumers who type objects as PromptConfig (not UserPromptConfig) must now add this
new field to compile.

@commitlint/types/src/prompt.ts[18-25]
@commitlint/cz-commitlint/src/store/defaultPromptConfigs.ts[1-7]
@commitlint/types/src/prompt.ts[54-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new required field `useExclamationMark` was added to the exported `PromptConfig.settings` type. This can break TypeScript consumers that construct `PromptConfig` literals without this field.

## Issue Context
Runtime defaults in `cz-commitlint` set `useExclamationMark: false`, so behavior is fine; the risk is compile-time compatibility for external TS users.

## Fix Focus Areas
- @commitlint/types/src/prompt.ts[18-24]
- @commitlint/cz-commitlint/src/store/defaultPromptConfigs.ts[1-7]

## Suggested direction
- Consider changing `useExclamationMark: boolean;` to `useExclamationMark?: boolean;` in `PromptConfig.settings`, keeping defaults so internal code still sees a boolean at runtime; OR
- If `PromptConfig` is intentionally strict, document and ship under a major version bump.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci Bot commented Mar 12, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Comment thread @commitlint/cz-commitlint/src/SectionHeader.ts
@mrt181 mrt181 force-pushed the feat/exclamation-mark-breaking-change branch from 1d5727b to a2b22de Compare March 12, 2026 18:00
@escapedcat escapedcat requested a review from Copilot March 12, 2026 21:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in prompt setting to format Conventional Commits breaking changes with an exclamation mark (!) in the header (e.g., feat(api)!: ...) for @commitlint/cz-commitlint.

Changes:

  • Introduces settings.useExclamationMark in the prompt config types, defaults, and docs.
  • Updates header composition to append ! when isBreaking is true and the setting is enabled.
  • Adjusts header length calculation and extends test coverage for the new formatting/length behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
docs/reference/prompt.md Documents the new useExclamationMark setting.
@commitlint/types/src/prompt.ts Extends PromptConfig.settings with useExclamationMark.
@commitlint/cz-commitlint/src/store/defaultPromptConfigs.ts Adds the default value for useExclamationMark (false).
@commitlint/cz-commitlint/src/SectionHeader.ts Appends ! for breaking changes and reserves header length accordingly.
@commitlint/cz-commitlint/src/SectionHeader.test.ts Adds tests for ! formatting and header length reservation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread @commitlint/cz-commitlint/src/SectionHeader.ts Outdated
Comment thread @commitlint/cz-commitlint/src/SectionHeader.ts Outdated
Comment thread @commitlint/types/src/prompt.ts
Comment thread @commitlint/cz-commitlint/src/SectionHeader.test.ts Outdated
@mrt181 mrt181 force-pushed the feat/exclamation-mark-breaking-change branch from a2b22de to d044471 Compare March 12, 2026 22:13
Opt-in via prompt.settings.useExclamationMark (default: false). This
reserves one header character for '!' during subject length validation,
regardless of the isBreaking answer.

See: https://www.conventionalcommits.org/en/v1.0.0/#summary
@mrt181 mrt181 force-pushed the feat/exclamation-mark-breaking-change branch from d044471 to 9ad6c95 Compare March 12, 2026 22:26
@escapedcat escapedcat merged commit 3b124a7 into conventional-changelog:master Mar 13, 2026
12 checks passed
@escapedcat
Copy link
Copy Markdown
Member

Thanks!

This was referenced Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants