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.
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Usage
- Configuration
- Built-in Rules
- CI/CD Integration
- Development
- Valid Commit Examples
- Invalid Commit Examples
- Contributing
- License
Features
- Full Conventional Commits specification support
- Drop-in replacement for
@commitlint/cliand@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) orpipfor installation- For development:
uv sync --extra devinstallsruff,pytest,pytest-cov,pytest-mock, andinvoke
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):
.commitlintrc.yaml.commitlintrc.ymlcommitlint.yamlcommitlint.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.3 → 1.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:
- Fork the repo and create a branch from
main - Run
uv sync --extra devto install development dependencies - Write tests for any new behavior — the project follows test-driven development
- Ensure
uv run pytest,uv run ruff check ., anduv run ruff format --check .all pass - Use Conventional Commits for commit messages — they're enforced by this very tool, and the release workflow uses them to compute the next version
- Open a pull request against
mainwith 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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d20587cbc034a3f3b67812dfafec51898a9ff87ae61879136bfbcdf5d513ec6
|
|
| MD5 |
8715b333cdbecc0c7afbeb3b96824e14
|
|
| BLAKE2b-256 |
d4faa6f2e35176d65f51de02aa5ac36f6fd0d86dc042c1cfc2f7dc03914a0d64
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97d1d2f1dc7bdf01f633adadcd81b74bf55d94b31f7d4650caa1d0db80974fd1
|
|
| MD5 |
6cc863f9cce084b44024203856eda04c
|
|
| BLAKE2b-256 |
e479809028161f28126f1bc4f78cda9a5405fd4cea5902b2407d2724b209fedc
|