commitlint

Commitlint Tool Analysis

Overview

commitlint validates git commit messages against the Conventional Commits specification, enabling automated changelog generation and semantic versioning. This analysis documents how Lintro wraps the upstream @commitlint/cli binary.

Core Tool Capabilities

  • Validates commit-message format (type(scope): subject, body, footer)
  • Ships with a shareable ruleset via @commitlint/config-conventional
  • Highly configurable rules with two severity levels (warning = 1, error = 2)
  • Reads input from a commit range (--from/--to), the last commit (--last), a message file (--edit), or stdin
  • Requires a config file discovered via cosmiconfig (commitlint.config.js, .commitlintrc.*, or a commitlint key in package.json)

Installation

bun add -g @commitlint/cli @commitlint/config-conventional
# or
npm install -g @commitlint/cli @commitlint/config-conventional
# or
brew install commitlint

A config is required. The minimal conventional setup:

// commitlint.config.js
module.exports = { extends: ['@commitlint/config-conventional'] };

Commit-Message Scope (Design Decision)

Unlike every other Lintro tool, commitlint does not inspect files — it inspects git commit messages. To fit Lintro’s file-oriented plugin model the plugin mirrors the git-history-oriented gitleaks plugin:

  • file_patterns=["*"] keeps shared execution preparation from short-circuiting when no tool-specific files are discovered. The discovered file list is then intentionally ignored.
  • check() runs commitlint --last, validating the repository’s most recent commit message in the working directory.

--last was chosen as the least-surprising default because it is deterministic (no HEAD~1 edge case on a single-commit repo, no reliance on remote refs such as origin/main) and works in any git repository. commitlint cannot rewrite commit messages, so the plugin is check-only (can_fix=False); fix() raises NotImplementedError.

When no commitlint config is present, the plugin skips the tool as a non-error rather than failing the run (it detects commitlint’s exit code 9 and the “Please add rules” message).

Output Format and Parsing

commitlint does not emit SARIF, and it has no built-in JSON formatter — its --format flag loads an external formatter module that is not bundled. Lintro therefore parses commitlint’s default human-readable report:

⧗   --- input ---
bad commit message
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings

The parser (lintro/parsers/commitlint/commitlint_parser.py):

  • Splits the report into per-commit --- input --- blocks and captures each commit’s subject line (surfaced in the file display column for context).
  • Extracts each / violation line into a CommitlintIssue with the rule name (code), severity level (error/warning), and message.
  • Strips ANSI colour codes and ignores the trailing summary line.

SARIF Fidelity Note

Per the checklist in docs/design/sarif-ingestion-evaluation.md, the shared SARIF ingestion path is only appropriate for tools that emit SARIF natively and losslessly. commitlint emits no SARIF at all, so the shared parser is inapplicable and a native parser is required. There is nothing SARIF would “drop” because there is no SARIF source to ingest.

Common Rules

RuleLevelDescription
type-emptyerrorCommit type must not be empty
subject-emptyerrorCommit subject must not be empty
type-enumerrorType must be one of the allowed values
header-max-lengtherrorHeader must not exceed the configured length
body-leading-blankwarningBody must be preceded by a blank line
body-max-line-lengthwarningBody lines must not exceed the configured max

Integration with Git Hooks

commitlint is commonly wired into a commit-msg hook (e.g. via husky) to validate messages as they are written:

commitlint --edit "$1"

Lintro’s plugin instead validates the already-committed --last message, which suits CI and ad-hoc lintro check runs.

References

  • https://commitlint.js.org/
  • https://www.conventionalcommits.org/
  • https://github.com/conventional-changelog/commitlint