Skip to main content

A Python implementation of commitlint for validating conventional commit messages.

Project description

python-commitlint

A pure-Python implementation of commitlint for validating Conventional Commits. No Node.js required.

CI Release Coverage Badge Python License: MIT Ruff Coverage


Table of Contents


Features

  • Full Conventional Commits specification support
  • Drop-in replacement for @commitlint/cli and @commitlint/config-conventional
  • YAML-based configuration — no JavaScript
  • 32 built-in validation rules covering type, scope, subject, header, body, and footer
  • Multiple output formats: human-readable text and JSON
  • Stdin support for use as a git commit-msg hook
  • JS config converter (commitlint.config.js.commitlintrc.yaml)
  • Zero Node.js dependencies

Requirements

  • Python 3.12 or newer
  • uv (recommended) or pip for installation
  • For development: uv sync --extra dev installs ruff, pytest, pytest-cov, pytest-mock, and invoke

Installation

pip install python-commitlint

Or with uv:

uv add python-commitlint

Quick Start

# Validate a commit message
commitlint lint "feat: add user authentication"

# Read from stdin (git hook usage)
echo "feat: add user authentication" | commitlint lint --stdin

# Use a custom config file
commitlint lint "fix: resolve timeout" --config .commitlintrc.yaml

# Output as JSON
commitlint lint "feat: add feature" --format json

Usage

commitlint lint

Usage: commitlint lint [OPTIONS] [MESSAGE]

Options:
  -c, --config PATH          Path to configuration file
  --stdin                    Read commit message from stdin
  --format [text|json]       Output format (default: text)
  -q, --quiet                Suppress output except for errors
  -h, --help                 Show this message and exit

Examples

# Argument
commitlint lint "feat(api): add pagination support"

# Stdin
git log -1 --pretty=%B | commitlint lint --stdin

# Quiet mode for CI (exit code only)
commitlint lint --quiet --stdin < .git/COMMIT_EDITMSG

# JSON output for tooling
commitlint lint --format json "fix: resolve null pointer"

JSON output shape

{
  "valid": false,
  "errors": [
    {
      "rule": "type-case",
      "message": "type must be lower-case",
      "severity": "error",
      "line": 1,
      "column": 0
    }
  ],
  "warnings": []
}

commitlint convert

Converts a commitlint.config.js file to a .commitlintrc.yaml file.

Usage: commitlint convert [OPTIONS] INPUT_FILE

Options:
  -o, --output PATH   Output file path (default: .commitlintrc.yaml)
  --dry-run           Print converted config without writing to disk
  -h, --help          Show this message and exit
# Convert and write to .commitlintrc.yaml
commitlint convert commitlint.config.js

# Preview without writing
commitlint convert --dry-run commitlint.config.js

# Write to a custom path
commitlint convert commitlint.config.js -o config/commitlint.yaml

Configuration

By default, commitlint lint looks for a config file in the current directory using these names (in order):

  1. .commitlintrc.yaml
  2. .commitlintrc.yml
  3. commitlint.yaml
  4. commitlint.yml

If no file is found, the built-in conventional preset is used.

Using the conventional preset

# .commitlintrc.yaml
extends: conventional

Custom rules

# .commitlintrc.yaml
extends: conventional

rules:
  type-enum:
    severity: error
    condition: always
    value:
      - feat
      - fix
      - docs
      - chore
      - hotfix

  header-max-length:
    severity: error
    condition: always
    value: 72

  scope-enum:
    severity: error
    condition: always
    value:
      - api
      - ui
      - db
      - auth

Rule format

Each rule entry accepts:

Field Values
severity error, warning, disabled
condition always, never
value rule-specific (string, number, or list)

Rules also support the numeric array format used by the original commitlint:

rules:
  type-enum: [2, always, [feat, fix, docs]]
  header-max-length: [2, always, 72]

Built-in Rules

Type

Rule Description
type-empty Require or disallow an empty type
type-case Enforce case style for the type
type-enum Restrict type to an allowed set
type-min-length Minimum character length for type
type-max-length Maximum character length for type

Scope

Rule Description
scope-empty Require or disallow an empty scope
scope-case Enforce case style for the scope
scope-enum Restrict scope to an allowed set
scope-min-length Minimum character length for scope
scope-max-length Maximum character length for scope

Subject

Rule Description
subject-empty Require or disallow an empty subject
subject-case Enforce case style for the subject
subject-full-stop Require or disallow a trailing punctuation character
subject-min-length Minimum character length for subject
subject-max-length Maximum character length for subject

Header

Rule Description
header-max-length Maximum character length for the header line
header-min-length Minimum character length for the header line
header-trim Disallow leading or trailing whitespace in the header
header-full-stop Require or disallow a trailing punctuation character
header-case Enforce case style for the full header

Body

Rule Description
body-empty Require or disallow an empty body
body-leading-blank Require a blank line between header and body
body-max-length Maximum total character length for the body
body-max-line-length Maximum character length per body line (URLs are exempt)
body-min-length Minimum total character length for the body
body-full-stop Require or disallow a trailing punctuation character
body-case Enforce case style for the body

Footer

Rule Description
footer-empty Require or disallow an empty footer
footer-leading-blank Require a blank line before the footer
footer-max-length Maximum total character length for the footer
footer-max-line-length Maximum character length per footer line
footer-min-length Minimum total character length for the footer

CI/CD Integration

Git commit-msg hook

Create .git/hooks/commit-msg and make it executable:

#!/bin/sh
commitlint lint --stdin < "$1"
chmod +x .git/hooks/commit-msg

GitHub Actions

This repository ships its own composite action — no separate install step required.

Validate a pull request title:

on:
  pull_request:
    types: [opened, edited, synchronize]

jobs:
  lint-pr-title:
    runs-on: ubuntu-latest
    steps:
      - uses: jedi-knights/python-commitlint@v0
        with:
          message: ${{ github.event.pull_request.title }}

Validate the latest commit on a push:

on: push

jobs:
  lint-commit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: jedi-knights/python-commitlint@v0

Inputs:

Name Description Default
message Commit message to validate. If omitted, the last commit on HEAD is used. ""
config-path Path to a .commitlintrc.yaml file. ""
format Output format printed to the workflow log: text or json. text
fail-on-warnings Exit non-zero when warnings are present. false
version Version of python-commitlint to install from PyPI. auto tracks the action ref tag (e.g. @v1.2.31.2.3); falls back to the latest release on PyPI for branch refs. auto

Outputs:

Name Description
valid "true" if validation passed, otherwise "false".
result-json Full lint result as a JSON document.

The action assumes Python 3.12+ is available on the runner (true for ubuntu-latest). For other runners, run actions/setup-python first.

Or invoke the CLI directly:

- name: Validate commit message
  run: git log -1 --pretty=%B | commitlint lint --stdin

GitLab CI

commitlint:
  script:
    - git log -1 --pretty=%B | commitlint lint --stdin

Development

# Clone the repo
git clone https://github.com/jedi-knights/python-commitlint
cd python-commitlint

# Install dependencies (including dev extras)
uv sync --extra dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov --cov-report=term-missing

# Lint
uv run ruff check .

# Format
uv run ruff format .

Valid Commit Examples

feat: add user authentication
fix(api): resolve timeout on large payloads
docs: update installation guide
chore(deps): upgrade ruamel.yaml to 0.18
refactor: extract validation logic into separate module
test: add integration tests for scope rules
ci: add GitHub Actions workflow
build!: drop support for Python 3.12

Invalid Commit Examples

Feature: wrong type format          # type not lowercase
FEAT: uppercase type                # type must be lower-case
feat: subject ending in period.     # trailing period not allowed
feat:missing space after colon      # malformed header
just a message                      # missing type and colon

Contributing

Contributions are welcome. Before opening a pull request:

  1. Fork the repo and create a branch from main
  2. Run uv sync --extra dev to install development dependencies
  3. Write tests for any new behavior — the project follows test-driven development
  4. Ensure uv run pytest, uv run ruff check ., and uv run ruff format --check . all pass
  5. Use Conventional Commits for commit messages — they're enforced by this very tool, and the release workflow uses them to compute the next version
  6. Open a pull request against main with a clear description of the change and its motivation

For bugs and feature requests, file an issue at https://github.com/jedi-knights/python-commitlint/issues.


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_commitlint-0.3.0.tar.gz (33.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

python_commitlint-0.3.0-py3-none-any.whl (35.2 kB view details)

Uploaded Python 3

File details

Details for the file python_commitlint-0.3.0.tar.gz.

File metadata

  • Download URL: python_commitlint-0.3.0.tar.gz
  • Upload date:
  • Size: 33.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for python_commitlint-0.3.0.tar.gz
Algorithm Hash digest
SHA256 6d20587cbc034a3f3b67812dfafec51898a9ff87ae61879136bfbcdf5d513ec6
MD5 8715b333cdbecc0c7afbeb3b96824e14
BLAKE2b-256 d4faa6f2e35176d65f51de02aa5ac36f6fd0d86dc042c1cfc2f7dc03914a0d64

See more details on using hashes here.

File details

Details for the file python_commitlint-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: python_commitlint-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 35.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for python_commitlint-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97d1d2f1dc7bdf01f633adadcd81b74bf55d94b31f7d4650caa1d0db80974fd1
MD5 6cc863f9cce084b44024203856eda04c
BLAKE2b-256 e479809028161f28126f1bc4f78cda9a5405fd4cea5902b2407d2724b209fedc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page