feat(cli): add --default-config flag to lint without a config file#4805
Conversation
When config resolution yields no rules, --default-config falls back to
the built-in default config (@commitlint/config-conventional) instead
of failing with empty-rules:
echo "feat: add new feature" | npx commitlint --default-config
This makes commitlint usable without any setup, e.g. for one-off checks
or server-side pre-receive hooks where installing a shareable config is
not practical. A configuration file with rules always takes precedence
over the flag, and configs passed via --extends are kept and override
the default config when the fallback applies.
The empty-rules error message now also points to the new flag, and the
CLI reference docs are re-synced with the actual --help output (which
was missing --legacy-output).
Closes #3662
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review Summary by QodoAdd --default-config flag to lint without configuration file
WalkthroughsDescription• Add --default-config flag to use built-in conventional config fallback • Enables commitlint usage without configuration file setup • Preserves user-supplied --extends configs when fallback applies • Updates error messages and CLI documentation with new flag • Adds comprehensive test coverage for default config behavior Diagramflowchart LR
A["CLI invocation with --default-config"] --> B["Load config from file/extends"]
B --> C{"Rules found?"}
C -->|Yes| D["Use loaded config"]
C -->|No| E["Fallback to @commitlint/config-conventional"]
E --> F["Merge with user extends"]
F --> G["Lint commit message"]
D --> G
File Changes1. @commitlint/cli/src/cli.ts
|
Code Review by Qodo
Context used 1. --default-config gates default fallback
|
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in CLI fallback that makes @commitlint/cli usable without any local configuration by introducing --default-config, which loads the built-in conventional ruleset when config resolution yields no rules.
Changes:
- Add
--default-configflag that falls back to@commitlint/config-conventionalwhen resolved rules are empty, while preserving--extendsprecedence. - Improve the empty-rules guidance message to mention the new flag.
- Re-sync CLI reference docs with
--helpoutput and add documentation for linting without a config; add fixtures + tests for the new behavior.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
@commitlint/cli/src/cli.ts |
Adds --default-config option, implements loadConfig() fallback logic, reuses module-resolution logic, and updates empty-rules messaging. |
@commitlint/cli/src/types.ts |
Extends CLI flags typing to include "default-config". |
@commitlint/cli/src/cli.test.ts |
Adds coverage for no-config scenarios, fallback behavior, precedence rules, and --print-config with fallback. |
@commitlint/cli/package.json |
Adds workspace dependency on @commitlint/config-conventional to ensure fallback is available. |
@commitlint/cli/fixtures/no-config/package.json |
Adds a no-config fixture for tests. |
@commitlint/cli/fixtures/no-config/helpurl-only.js |
Adds a shareable config fixture with helpUrl but no rules to test fallback + extends behavior. |
docs/reference/cli.md |
Updates CLI help output, documents --default-config, and adds a “Lint without a config file” section. |
docs/guides/local-setup.md |
Adds a tip showing how to try commitlint without a config using --default-config. |
pnpm-lock.yaml |
Updates lockfile for the new CLI dependency. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // `--default-config` falls back to the built-in default config when | ||
| // config resolution yields no rules (e.g. no config file was found). | ||
| // The default config is prepended so user-supplied --extends configs | ||
| // keep precedence over it. | ||
| if (flags["default-config"] && Object.keys(loaded.rules).length === 0) { | ||
| const extendsWithDefault = [resolveDefaultConfig(flags), ...(flags.extends || [])]; | ||
| return load(getSeed({ ...flags, extends: extendsWithDefault }), { | ||
| cwd: flags.cwd, | ||
| file: flags.config, | ||
| }); | ||
| } |
There was a problem hiding this comment.
1. --default-config gates default fallback 📎 Requirement gap ≡ Correctness
The CLI only loads the built-in default config when --default-config is explicitly provided, so running commitlint with no config file still resolves to empty rules and errors. This violates the requirement to automatically use the built-in default configuration when no commitlint config file is found.
Agent Prompt
## Issue description
The built-in default config is only applied when the user passes `--default-config`, but the compliance requirement expects commitlint to automatically fall back to the built-in default configuration when no commitlint config file is present.
## Issue Context
`loadConfig()` currently checks `flags["default-config"]` before prepending `@commitlint/config-conventional`, so config-less invocations still end up with `loaded.rules` empty and hit the empty-rules error path.
## Fix Focus Areas
- @commitlint/cli/src/cli.ts[495-505]
- @commitlint/cli/src/cli.test.ts[217-231]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@commitlint/cli](https://commitlint.js.org/) ([source](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli)) | [`21.0.1` → `21.1.0`](https://renovatebot.com/diffs/npm/@commitlint%2fcli/21.0.1/21.1.0) |  |  | | [@commitlint/config-conventional](https://commitlint.js.org/) ([source](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional)) | [`21.0.1` → `21.1.0`](https://renovatebot.com/diffs/npm/@commitlint%2fconfig-conventional/21.0.1/21.1.0) |  |  | --- ### Release Notes <details> <summary>conventional-changelog/commitlint (@​commitlint/cli)</summary> ### [`v21.1.0`](https://github.com/conventional-changelog/commitlint/blob/HEAD/@​commitlint/cli/CHANGELOG.md#2110-2026-06-23) [Compare Source](conventional-changelog/commitlint@v21.0.2...v21.1.0) ##### Features - **cli:** add --default-config flag to lint without a config file ([#​4805](conventional-changelog/commitlint#4805)) ([7af27ba](conventional-changelog/commitlint@7af27ba)), closes [#​3662](conventional-changelog/commitlint#3662) #### [21.0.2](conventional-changelog/commitlint@v21.0.1...v21.0.2) (2026-05-29) ##### Bug Fixes - disallow same commit hash for --from and --to ([#​4773](conventional-changelog/commitlint#4773)) ([121005e](conventional-changelog/commitlint@121005e)) #### [21.0.1](conventional-changelog/commitlint@v21.0.0...v21.0.1) (2026-05-12) **Note:** Version bump only for package [@​commitlint/cli](https://github.com/commitlint/cli) ### [`v21.0.2`](https://github.com/conventional-changelog/commitlint/blob/HEAD/@​commitlint/cli/CHANGELOG.md#2102-2026-05-29) [Compare Source](conventional-changelog/commitlint@v21.0.1...v21.0.2) ##### Bug Fixes - disallow same commit hash for --from and --to ([#​4773](conventional-changelog/commitlint#4773)) ([121005e](conventional-changelog/commitlint@121005e)) </details> <details> <summary>conventional-changelog/commitlint (@​commitlint/config-conventional)</summary> ### [`v21.1.0`](https://github.com/conventional-changelog/commitlint/blob/HEAD/@​commitlint/config-conventional/CHANGELOG.md#2110-2026-06-23) [Compare Source](conventional-changelog/commitlint@v21.0.2...v21.1.0) **Note:** Version bump only for package [@​commitlint/config-conventional](https://github.com/commitlint/config-conventional) #### [21.0.2](conventional-changelog/commitlint@v21.0.1...v21.0.2) (2026-05-29) **Note:** Version bump only for package [@​commitlint/config-conventional](https://github.com/commitlint/config-conventional) #### [21.0.1](conventional-changelog/commitlint@v21.0.0...v21.0.1) (2026-05-12) **Note:** Version bump only for package [@​commitlint/config-conventional](https://github.com/commitlint/config-conventional) ### [`v21.0.2`](https://github.com/conventional-changelog/commitlint/blob/HEAD/@​commitlint/config-conventional/CHANGELOG.md#2102-2026-05-29) [Compare Source](conventional-changelog/commitlint@v21.0.1...v21.0.2) **Note:** Version bump only for package [@​commitlint/config-conventional](https://github.com/commitlint/config-conventional) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi44MS4zIiwidXBkYXRlZEluVmVyIjoiNDIuODEuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Reviewed-on: https://git.3caravelle.net/3Caravelle/renovate/pulls/37 Co-authored-by: Renovate Bot <renovate-bot@3caravelle.com> Co-committed-by: Renovate Bot <renovate-bot@3caravelle.com>
When config resolution yields no rules, --default-config falls back to the built-in default config (@commitlint/config-conventional) instead of failing with empty-rules:
This makes commitlint usable without any setup, e.g. for one-off checks or server-side pre-receive hooks where installing a shareable config is not practical. A configuration file with rules always takes precedence over the flag, and configs passed via --extends are kept and override the default config when the fallback applies.
The empty-rules error message now also points to the new flag, and the CLI reference docs are re-synced with the actual --help output (which was missing --legacy-output).
Closes #3662