Skip to content
Open
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
1 change: 1 addition & 0 deletions @commitlint/cli/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ test("should print help", async () => {
-q, --quiet toggle console output [boolean] [default: false]
-t, --to upper end of the commit range to lint; applies if edit=false [string]
-V, --verbose enable verbose output for reports without problems [boolean]
--legacy-output use the legacy input output format (single-line 'input: ...') [boolean]
-s, --strict enable strict mode; result code 2 for warnings, 3 for errors [boolean]
--options path to a JSON file or Common.js module containing CLI options
-v, --version display version information [boolean]
Expand Down
6 changes: 6 additions & 0 deletions @commitlint/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ const cli = yargs(process.argv.slice(2))
type: "boolean",
description: "enable verbose output for reports without problems",
},
"legacy-output": {
description:
"use the legacy input output format (single-line 'input: ...')",
type: "boolean",
},
Comment thread
knocte marked this conversation as resolved.
strict: {
alias: "s",
type: "boolean",
Expand Down Expand Up @@ -398,6 +403,7 @@ async function main(args: MainArgs): Promise<void> {
color: flags.color,
verbose: flags.verbose,
helpUrl,
legacyOutput: flags["legacy-output"],
});

if (!flags.quiet && output !== "") {
Expand Down
1 change: 1 addition & 0 deletions @commitlint/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface CliFlags {
/** @type {'' | 'text' | 'json'} */
"print-config"?: string;
strict?: boolean;
"legacy-output"?: boolean;
_: (string | number)[];
$0: string;
}
9 changes: 6 additions & 3 deletions @commitlint/config-lerna-scopes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,19 @@ packages
└── web

❯ echo "build(api): change something in api's build" | commitlint
⧗ input: build(api): change something in api's build
⧗ --- input ---
build(api): change something in api's build
✔ found 0 problems, 0 warnings

Comment on lines 33 to 37
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

Like the other config READMEs, this shows output for a passing commit without --verbose, but commitlint is silent on success by default. Please align the example commands/output (e.g., add --verbose) so the documentation reflects real behavior.

Copilot uses AI. Check for mistakes.
❯ echo "test(foo): this won't pass" | commitlint
⧗ input: test(foo): this won't pass
⧗ --- input ---
test(foo): this won't pass
✖ scope must be one of [api, app, web] [scope-enum]
✖ found 1 problems, 0 warnings

❯ echo "ci: do some general maintenance" | commitlint
⧗ input: ci: do some general maintenance
⧗ --- input ---
ci: do some general maintenance
✔ found 0 problems, 0 warnings
```

Expand Down
9 changes: 6 additions & 3 deletions @commitlint/config-nx-scopes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,19 @@ packages
└── web

❯ echo "build(api): change something in api's build" | commitlint
⧗ input: build(api): change something in api's build
⧗ --- input ---
build(api): change something in api's build
✔ found 0 problems, 0 warnings

Comment on lines 99 to 103
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

The success-case examples here show output even though commitlint prints nothing for valid messages unless --verbose is provided. Consider adding --verbose to the example commands (or removing the success output) to avoid confusing users who copy/paste.

Copilot uses AI. Check for mistakes.
❯ echo "test(foo): this won't pass" | commitlint
⧗ input: test(foo): this won't pass
⧗ --- input ---
test(foo): this won't pass
✖ scope must be one of [api, app, web] [scope-enum]
✖ found 1 problems, 0 warnings

❯ echo "ci: do some general maintenance" | commitlint
⧗ input: ci: do some general maintenance
⧗ --- input ---
ci: do some general maintenance
✔ found 0 problems, 0 warnings
```

Expand Down
9 changes: 6 additions & 3 deletions @commitlint/config-pnpm-scopes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,19 @@ packages
└── web

❯ echo "build(api): change something in api's build" | commitlint
⧗ input: build(api): change something in api's build
⧗ --- input ---
build(api): change something in api's build
✔ found 0 problems, 0 warnings
Comment on lines 30 to 33
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

These examples include output for passing commits without showing --verbose, but commitlint suppresses output on success by default. Please update the commands to include --verbose (or adjust the shown output) so the README matches actual CLI behavior.

Copilot uses AI. Check for mistakes.

❯ echo "test(foo): this won't pass" | commitlint
⧗ input: test(foo): this won't pass
⧗ --- input ---
test(foo): this won't pass
✖ scope must be one of [api, app, web] [scope-enum]
✖ found 1 problems, 0 warnings

❯ echo "ci: do some general maintenance" | commitlint
⧗ input: ci: do some general maintenance
⧗ --- input ---
ci: do some general maintenance
✔ found 0 problems, 0 warnings
```

Expand Down
9 changes: 6 additions & 3 deletions @commitlint/config-rush-scopes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,19 @@ packages
└── web

❯ echo "build(api): change something in api's build" | commitlint
⧗ input: build(api): change something in api's build
⧗ --- input ---
build(api): change something in api's build
✔ found 0 problems, 0 warnings
Comment on lines 30 to 33
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

These examples show output for a successful lint ("found 0 problems") but the CLI doesn't print anything on success unless --verbose is used (see docs/guides/local-setup.md). To keep the README accurate, either add --verbose to the example commands or remove the success output blocks.

Copilot uses AI. Check for mistakes.

❯ echo "test(foo): this won't pass" | commitlint
⧗ input: test(foo): this won't pass
⧗ --- input ---
test(foo): this won't pass
✖ scope must be one of [api, app, web] [scope-enum]
✖ found 1 problems, 0 warnings

❯ echo "ci: do some general maintenance" | commitlint
⧗ input: ci: do some general maintenance
⧗ --- input ---
ci: do some general maintenance
✔ found 0 problems, 0 warnings
```

Expand Down
83 changes: 83 additions & 0 deletions @commitlint/format/src/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,94 @@ test("returns empty summary with full commit message if verbose", () => {
},
);

expect(actual).toStrictEqual(
"⧗ --- input ---\nfeat(cli): this is a valid header\n\nThis is a valid body\n\nSigned-off-by: tester\n✔ found 0 problems, 0 warnings",
);
});

test("returns legacy output with full commit message if verbose and legacyOutput", () => {
const actual = format(
{
results: [
{
errors: [],
warnings: [],
input:
"feat(cli): this is a valid header\n\nThis is a valid body\n\nSigned-off-by: tester",
},
],
},
{
verbose: true,
color: false,
legacyOutput: true,
},
);

expect(actual).toStrictEqual(
"⧗ input: feat(cli): this is a valid header\n\nThis is a valid body\n\nSigned-off-by: tester\n✔ found 0 problems, 0 warnings",
);
});

test("returns input banner with errors and multi-line input", () => {
const actual = format(
{
results: [
{
errors: [
{
level: 2,
name: "type-enum",
message:
"type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test]",
},
],
warnings: [],
input:
"foo: this is an invalid header\n\nThis is a body\n\nSigned-off-by: tester",
},
],
},
{
color: false,
},
);

expect(actual).toStrictEqual(
"⧗ --- input ---\nfoo: this is an invalid header\n\nThis is a body\n\nSigned-off-by: tester\n✖ type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test] [type-enum]\n\n✖ found 1 problems, 0 warnings\n",
);
});

test("returns legacy input banner with errors and multi-line input", () => {
const actual = format(
{
results: [
{
errors: [
{
level: 2,
name: "type-enum",
message:
"type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test]",
},
],
warnings: [],
input:
"foo: this is an invalid header\n\nThis is a body\n\nSigned-off-by: tester",
},
],
},
{
color: false,
legacyOutput: true,
},
);

expect(actual).toStrictEqual(
"⧗ input: foo: this is an invalid header\n\nThis is a body\n\nSigned-off-by: tester\n✖ type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test] [type-enum]\n\n✖ found 1 problems, 0 warnings\n",
);
});
Comment thread
knocte marked this conversation as resolved.

test("returns a correct summary of empty .errors and .warnings", () => {
const actualError = format({
results: [
Expand Down
15 changes: 11 additions & 4 deletions @commitlint/format/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function formatInput(
result: FormattableResult & WithInput,
options: FormatOptions = {},
): string[] {
const { color: enabled = true } = options;
const { color: enabled = true, legacyOutput = false } = options;
const { errors = [], warnings = [], input = "" } = result;

if (!input) {
Expand All @@ -50,9 +50,16 @@ function formatInput(
const decoratedInput = enabled ? pc.bold(input) : input;
const hasProblems = errors.length > 0 || warnings.length > 0;

return options.verbose || hasProblems
? [`${decoration} input: ${decoratedInput}`]
: [];
if (!(options.verbose || hasProblems)) {
return [];
}

if (legacyOutput) {
// legacy: single line with 'input: ' prefix, no extra newlines or dashes
return [`${decoration} input: ${decoratedInput}`];
}

return [`${decoration} --- input ---\n${decoratedInput}`];
}

export function formatResult(
Expand Down
1 change: 1 addition & 0 deletions @commitlint/types/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ export interface FormatOptions {
colors?: readonly [PicocolorsColor, PicocolorsColor, PicocolorsColor];
verbose?: boolean;
helpUrl?: string;
legacyOutput?: boolean;
}
6 changes: 5 additions & 1 deletion docs/guides/local-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ You can test the hook by simply committing. You should see something like this i
git commit -m "foo: this will fail"
# husky > commit-msg
No staged files match any of provided globs.
⧗ input: foo: this will fail
⧗ --- input ---
foo: this will fail
✖ type must be one of [build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test] [type-enum]
Comment thread
knocte marked this conversation as resolved.

✖ found 1 problems, 0 warnings
Expand All @@ -290,4 +291,7 @@ No staged files match any of provided globs.
# husky > commit-msg
```

Since [v22.0.0](https://github.com/conventional-changelog/commitlint/releases/tag/v22.0.0) `commitlint` will output the commit message after a new line (EOL) instead of after a colon.\
(You can use the `--legacy-output` flag to get the previous output format used in older versions)
Comment on lines +294 to +295

Local linting is fine for fast feedback but can easily be tinkered with. To ensure all commits are linted you'll want to check commits on an automated CI Server too. Learn how to in the [CI Setup guide](/guides/ci-setup).