Skip to content

fix: pin auto-installed @commitlint/* configs to engine major#38

Merged
mridang merged 1 commit into
masterfrom
fix/pin-commitlint-config-major
Jun 14, 2026
Merged

fix: pin auto-installed @commitlint/* configs to engine major#38
mridang merged 1 commit into
masterfrom
fix/pin-commitlint-config-major

Conversation

@mridang

@mridang mridang commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Description

A declarative commitlint config that extends a @commitlint/* preset without pinning a version (e.g. extends: ["@commitlint/config-conventional"]) was written into the generated package.json as *, so npm installed the latest major. The action bundles the commitlint engine (@commitlint/lint/load) at ^19, and @commitlint/config-conventional@20 is ESM-only with a parserPreset the v19 engine does not load. The conventional parser then falls back to the default parser, which does not understand the breaking-change !, so a perfectly valid feat!: … commit parses as an empty header and fails with type may not be empty / subject may not be empty.

This pins detected @commitlint/* configs to the bundled engine's major (^19) when no explicit version is given; every other package still defaults to *.

Related Issue

Closes #37

Motivation and Context

The action's code did not change — @commitlint/config-conventional published a v20 major and the action installed @latest, so the runtime drifted under stable code. Any repository using a feat!:/fix!: breaking-change commit started failing the lint with a misleading "empty type/subject" error. Pinning the install to the engine major restores correct parsing and keeps the resolved config ABI-compatible with the bundled engine.

How Has This Been Tested?

  • Added a unit test asserting an unversioned @commitlint/config-conventional is written as ^19 (not *).
  • npm test (84 tests) passes; npm run build, npm run lint, and npm run format:check are clean.
  • Reproduced the original failure with the prior dist against a live feat!: PR and confirmed the rebuilt dist resolves config-conventional ^19 and parses the breaking-change header correctly.

Documentation:

N/A — internal dependency-resolution fix; no user-facing API or input changes.

Checklist:

  • I have updated the documentation accordingly.
  • I have assigned the correct milestone or created one if non-existent.
  • I have correctly labeled this pull request.
  • I have linked the corresponding issue in this description.
  • I have requested a review from at least 2 reviewers
  • I have checked the base branch of this pull request
  • I have checked my code for any possible security vulnerabilities

A declarative config that extends a @commitlint/* preset without an
explicit version was installed as latest. config-conventional@20 is
ESM-only and its parser preset is not loaded by the bundled v19 engine,
so the breaking-change "!" parses as an empty header and fails with
"type/subject may not be empty". Pin the @commitlint scope to the
engine major (^19); other packages still default to latest.

Closes #37
@mridang mridang merged commit 01d562c into master Jun 14, 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.

Auto-installed @commitlint/config-conventional@20 breaks parsing of breaking-change ! (false "type/subject may not be empty")

1 participant