Python commitizen client tool for standardized commit conventions and automated version management
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive version management with support for semantic versioning, PEP 440, automatic file updates, and multiple version schemes. Commitizen provides intelligent version bumping based on commit history analysis and supports various versioning standards used across different ecosystems.
Analyzes commit history to determine appropriate version increment based on commit message patterns.
def find_increment(
commits: list[GitCommit],
regex: Pattern[str],
incremental_rev: str = ""
) -> str:
"""
Determine version increment type from commit history.
Analyzes commits using the provided regex pattern to identify
BREAKING changes, features, and fixes to determine if version
should be bumped MAJOR, MINOR, or PATCH.
Parameters:
- commits: List of git commits to analyze
- regex: Compiled regex pattern for parsing commit messages
- incremental_rev: Starting revision for analysis
Returns:
Version increment type: "MAJOR", "MINOR", "PATCH", or None
"""Updates version information across multiple files in the project automatically.
def update_version_in_files(
current_version: str,
new_version: str,
files: list[str]
) -> None:
"""
Update version strings in specified files.
Supports various file formats and version string patterns:
- Python files: __version__ = "1.0.0"
- JSON files: "version": "1.0.0"
- TOML files: version = "1.0.0"
- Plain text files: version replacement
Parameters:
- current_version: Current version string to replace
- new_version: New version string
- files: List of file paths, optionally with specific keys (file.json:version)
"""Normalizes git tag names according to configured format templates.
def normalize_tag(tag: str, tag_format: str) -> str:
"""
Normalize tag name according to format template.
Converts between different tag formats and ensures consistency
with configured tag_format setting.
Parameters:
- tag: Original tag name
- tag_format: Tag format template (e.g., "v$version", "$version")
Returns:
Normalized tag name
"""Interface definition for all version scheme implementations.
class VersionProtocol(Protocol):
"""Protocol defining the interface for version schemes."""
def parse(self, version: str) -> Any:
"""
Parse version string into version object.
Parameters:
- version: Version string to parse
Returns:
Parsed version object
"""
def bump(self, version: Any, increment: str) -> Any:
"""
Bump version by specified increment.
Parameters:
- version: Parsed version object
- increment: Increment type (MAJOR, MINOR, PATCH)
Returns:
Bumped version object
"""
def serialize(self, version: Any) -> str:
"""
Serialize version object to string.
Parameters:
- version: Version object to serialize
Returns:
Version string
"""Abstract base implementation providing common version functionality.
class BaseVersion:
"""Abstract base class for version implementations."""
def __init__(self, version_string: str):
"""
Initialize version from string.
Parameters:
- version_string: Version string to parse
"""
def bump(self, increment: str) -> "BaseVersion":
"""
Create new version with specified increment.
Parameters:
- increment: Increment type (MAJOR, MINOR, PATCH)
Returns:
New version instance
"""
def __str__(self) -> str:
"""Return string representation of version."""
def __eq__(self, other: Any) -> bool:
"""Compare versions for equality."""
def __lt__(self, other: Any) -> bool:
"""Compare versions for ordering."""Python ecosystem version scheme following PEP 440 specification.
class Pep440(BaseVersion):
"""
PEP 440 version scheme for Python packages.
Supports development releases, pre-releases, post-releases, and local versions.
Format examples: 1.0.0, 1.0.0a1, 1.0.0b2, 1.0.0rc1, 1.0.0.post1, 1.0.0+local
"""
def parse(self, version: str) -> dict[str, Any]:
"""
Parse PEP 440 version string.
Returns:
Dictionary with version components (major, minor, patch, pre, post, local)
"""
def bump(self, version: dict[str, Any], increment: str) -> dict[str, Any]:
"""
Bump PEP 440 version.
Handles pre-release and post-release versioning according to PEP 440.
"""
def serialize(self, version: dict[str, Any]) -> str:
"""Serialize PEP 440 version to string."""Standard semantic versioning scheme (semver.org).
class SemVer(BaseVersion):
"""
Semantic versioning scheme (semver.org).
Format: MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]
Example: 1.0.0, 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0+build.1
"""
def parse(self, version: str) -> dict[str, Any]:
"""
Parse semantic version string.
Returns:
Dictionary with version components (major, minor, patch, prerelease, build)
"""
def bump(self, version: dict[str, Any], increment: str) -> dict[str, Any]:
"""
Bump semantic version.
Follows semantic versioning rules for pre-release handling.
"""
def serialize(self, version: dict[str, Any]) -> str:
"""Serialize semantic version to string."""Alternative semantic versioning implementation with different pre-release handling.
class SemVer2(BaseVersion):
"""
Alternative semantic versioning with different pre-release rules.
Similar to SemVer but with alternative handling of pre-release versions.
"""
def parse(self, version: str) -> dict[str, Any]:
"""Parse alternative semantic version string."""
def bump(self, version: dict[str, Any], increment: str) -> dict[str, Any]:
"""Bump alternative semantic version."""
def serialize(self, version: dict[str, Any]) -> str:
"""Serialize alternative semantic version to string."""KNOWN_SCHEMES: dict[str, type[BaseVersion]]
"""Dictionary of available version schemes."""
DEFAULT_SCHEME: str
"""Default version scheme name."""
def get_version_scheme(name: str = "pep440") -> VersionProtocol:
"""
Get version scheme instance by name.
Parameters:
- name: Version scheme name (pep440, semver, semver2)
Returns:
Version scheme instance implementing VersionProtocol
Raises:
ValueError: If version scheme is not found
"""Increment = Literal["MAJOR", "MINOR", "PATCH"]
"""Type alias for version increment types."""
Prerelease = Literal["alpha", "beta", "rc"]
"""Type alias for pre-release identifiers."""from commitizen.bump import find_increment, update_version_in_files
from commitizen.version_schemes import get_version_scheme
from commitizen.git import get_commits
import re
# Analyze commits for version increment
commits = get_commits(start="v1.0.0", end="HEAD")
pattern = re.compile(r"^(feat|fix|BREAKING)")
increment = find_increment(commits, pattern)
print(f"Recommended increment: {increment}") # "MINOR"
# Update version in files
update_version_in_files(
current_version="1.0.0",
new_version="1.1.0",
files=[
"src/__version__.py",
"pyproject.toml:version",
"package.json:version"
]
)from commitizen.version_schemes import get_version_scheme
# PEP 440 version scheme
pep440 = get_version_scheme("pep440")
version = pep440.parse("1.0.0")
new_version = pep440.bump(version, "MINOR")
print(pep440.serialize(new_version)) # "1.1.0"
# Semantic versioning
semver = get_version_scheme("semver")
version = semver.parse("1.0.0-alpha.1")
new_version = semver.bump(version, "PATCH")
print(semver.serialize(new_version)) # "1.0.0"
# Pre-release versions
version = semver.parse("1.0.0")
prerelease = semver.bump(version, "PRERELEASE")
print(semver.serialize(prerelease)) # "1.0.1-alpha.1"from commitizen.version_schemes import BaseVersion
from typing import Any
class CustomVersion(BaseVersion):
"""Custom version scheme for internal projects."""
def parse(self, version: str) -> dict[str, Any]:
# Parse custom format: YEAR.MONTH.BUILD
parts = version.split('.')
return {
"year": int(parts[0]),
"month": int(parts[1]),
"build": int(parts[2]) if len(parts) > 2 else 0
}
def bump(self, version: dict[str, Any], increment: str) -> dict[str, Any]:
from datetime import datetime
now = datetime.now()
if increment == "MAJOR":
return {"year": now.year, "month": now.month, "build": 0}
elif increment == "MINOR":
return {
"year": version["year"],
"month": now.month,
"build": 0
}
else: # PATCH
return {
"year": version["year"],
"month": version["month"],
"build": version["build"] + 1
}
def serialize(self, version: dict[str, Any]) -> str:
return f"{version['year']}.{version['month']}.{version['build']}"
# Register custom scheme
custom = CustomVersion("2024.1.0")
new_version = custom.bump(custom.parse("2024.1.5"), "PATCH")
print(str(new_version)) # "2024.1.6"from commitizen.providers import get_provider
# Get version from different sources
poetry_provider = get_provider("poetry")
current_version = poetry_provider.get_version()
npm_provider = get_provider("npm")
npm_version = npm_provider.get_version()
# Update version in provider
poetry_provider.set_version("2.0.0")
npm_provider.set_version("2.0.0")[tool.commitizen]
version_scheme = "semver"
version_files = [
"src/__version__.py",
"pyproject.toml:version",
"package.json:version",
"VERSION"
]
# Custom bump patterns
bump_pattern = "^(feat|fix|BREAKING|perf)"
bump_map = {
"BREAKING" = "MAJOR",
"feat" = "MINOR",
"fix" = "PATCH",
"perf" = "PATCH"
}
# Major version zero handling
major_version_zero = true
bump_map_major_version_zero = {
"BREAKING" = "MINOR",
"feat" = "PATCH",
"fix" = "PATCH"
}Install with Tessl CLI
npx tessl i tessl/pypi-commitizen