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
Extensive git integration including commit creation, tag management, branch operations, repository status checking, and smart file handling with EOL support. Commitizen provides comprehensive git operations that handle edge cases and provide robust integration with git workflows.
Core data structures representing git objects with metadata.
class GitObject:
"""Base class for git objects."""
def __init__(self, rev: str):
"""
Initialize git object.
Parameters:
- rev: Git revision identifier
"""
class GitCommit(NamedTuple):
"""Git commit representation with metadata."""
rev: str # Commit SHA hash
title: str # Commit title (first line)
body: str # Commit body (remaining lines)
author: str # Author name
author_email: str # Author email
date: str # Commit date (ISO format)
class GitTag(NamedTuple):
"""Git tag representation with metadata."""
name: str # Tag name
rev: str # Tagged commit SHA
date: str # Tag creation dateSupport for different end-of-line formats in text files.
class EOLTypes(Enum):
"""End-of-line type enumeration."""
LF = "lf" # Unix line endings (\n)
CRLF = "crlf" # Windows line endings (\r\n)
NATIVE = "native" # Platform-specific line endingsCheck repository state and validate git project status.
def is_git_project(path: str = ".") -> bool:
"""
Check if directory is a git repository.
Parameters:
- path: Directory path to check
Returns:
True if directory contains a git repository
"""
def find_git_project_root(path: str = ".") -> Path:
"""
Find the root directory of the git repository.
Searches upward from the given path to find .git directory.
Parameters:
- path: Starting directory path
Returns:
Path to git repository root
Raises:
NotAGitProjectError: If not in a git repository
"""
def is_staging_clean(check_untracked_files: bool = False) -> bool:
"""
Check if git staging area is clean.
Parameters:
- check_untracked_files: Include untracked files in check
Returns:
True if staging area has no changes
"""Add files to staging area and manage working directory.
def add(pathspecs: list[str]) -> Command:
"""
Add files to git staging area.
Parameters:
- pathspecs: List of file paths or patterns to add
Returns:
Command execution result
Raises:
GitCommandError: If git add command fails
"""Create git commits with various options and validation.
def commit(message: str, args: str = "") -> Command:
"""
Create git commit with message.
Parameters:
- message: Commit message text
- args: Additional git commit arguments
Returns:
Command execution result
Raises:
GitCommandError: If commit creation fails
CommitMessageLengthError: If message exceeds limits
"""Execute shell commands with proper error handling and result capture.
def run(cmd: str, env: dict[str, str] | None = None) -> Command:
"""
Execute shell command and return result.
Parameters:
- cmd: Shell command to execute
- env: Environment variables for command execution
Returns:
Command object with return_code, stdout, and stderr
Raises:
CommandExecutionError: If command execution fails
"""Create and manage git tags with signing support.
def tag(
name: str,
message: str = "",
signed: bool = False,
annotated: bool = True
) -> Command:
"""
Create git tag.
Parameters:
- name: Tag name
- message: Tag message (for annotated tags)
- signed: Create GPG signed tag
- annotated: Create annotated tag (default)
Returns:
Command execution result
Raises:
GitCommandError: If tag creation fails
"""
def tag_exist(tag: str) -> bool:
"""
Check if git tag exists.
Parameters:
- tag: Tag name to check
Returns:
True if tag exists in repository
"""
def is_signed_tag(tag_name: str) -> bool:
"""
Check if tag is GPG signed.
Parameters:
- tag_name: Name of tag to check
Returns:
True if tag has valid GPG signature
"""
def get_latest_tag_name(pattern: str = "*") -> str | None:
"""
Get the most recent tag name.
Parameters:
- pattern: Tag name pattern filter
Returns:
Latest tag name or None if no tags exist
"""Retrieve and analyze commit history with filtering options.
def get_commits(
start: str = "",
end: str = "",
rev: str = "",
paths: list[str] = []
) -> list[GitCommit]:
"""
Get git commit history.
Parameters:
- start: Starting revision (exclusive)
- end: Ending revision (inclusive)
- rev: Specific revision or range
- paths: Limit to changes in specific paths
Returns:
List of GitCommit objects in chronological order
Raises:
GitCommandError: If git log command fails
"""
def get_filenames_in_commit(rev: str) -> list[str]:
"""
Get list of files changed in specific commit.
Parameters:
- rev: Commit revision identifier
Returns:
List of file paths modified in the commit
"""Retrieve tag information and metadata.
def get_tags() -> list[GitTag]:
"""
Get all git tags in repository.
Returns:
List of GitTag objects sorted by creation date
Raises:
GitCommandError: If git tag command fails
"""Intelligent file handling with git configuration awareness.
def smart_open(
filename: str,
encoding: str = "utf-8",
eol: str = ""
) -> TextIOWrapper:
"""
Open file with git-aware line ending handling.
Respects git configuration for core.autocrlf and core.eol settings.
Handles different line ending conventions appropriately.
Parameters:
- filename: Path to file
- encoding: Text encoding (default: utf-8)
- eol: End-of-line format override
Returns:
Text file handle with appropriate line ending handling
Raises:
FileNotFoundError: If file doesn't exist
UnicodeDecodeError: If encoding is incorrect
"""from commitizen import git
# Check if in git repository
if git.is_git_project():
print("In git repository")
root = git.find_git_project_root()
print(f"Repository root: {root}")
# Check staging area status
if git.is_staging_clean():
print("No staged changes")
# Add files and commit
git.add(["src/", "tests/"])
result = git.commit("feat: add new feature")
print(f"Commit created: {result.return_code == 0}")
# Create signed tag
git.tag("v1.0.0", "Release version 1.0.0", signed=True)from commitizen import git
# Get all commits since last tag
commits = git.get_commits(start="v0.9.0", end="HEAD")
for commit in commits:
print(f"{commit.rev[:8]}: {commit.title}")
print(f"Author: {commit.author} <{commit.author_email}>")
print(f"Date: {commit.date}")
# Get files changed in commit
files = git.get_filenames_in_commit(commit.rev)
print(f"Files: {', '.join(files)}")
print()
# Get commits in specific path
src_commits = git.get_commits(
start="v0.9.0",
end="HEAD",
paths=["src/"]
)
print(f"Commits affecting src/: {len(src_commits)}")from commitizen import git
# Get all tags
tags = git.get_tags()
for tag in tags:
print(f"{tag.name} -> {tag.rev[:8]} ({tag.date})")
# Check if tag exists
if git.tag_exist("v1.0.0"):
print("Tag v1.0.0 exists")
# Check if signed
if git.is_signed_tag("v1.0.0"):
print("Tag is GPG signed")
# Get latest tag
latest = git.get_latest_tag_name()
print(f"Latest tag: {latest}")
# Get latest tag matching pattern
latest_stable = git.get_latest_tag_name("v*.*.*")
print(f"Latest stable: {latest_stable}")from commitizen import git
# Open file with git-aware line ending handling
with git.smart_open("CHANGELOG.md", encoding="utf-8") as f:
content = f.read()
# The file is opened with appropriate line endings based on:
# - Git configuration (core.autocrlf, core.eol)
# - Platform defaults
# - Repository .gitattributes settings
# Write file with consistent line endings
with git.smart_open("VERSION", encoding="utf-8", eol="lf") as f:
f.write("1.0.0\n")from commitizen import git
from commitizen.exceptions import (
NotAGitProjectError,
GitCommandError,
CommitMessageLengthError
)
try:
# Check repository status
if not git.is_git_project():
raise NotAGitProjectError("Not in git repository")
# Attempt to commit
result = git.commit("Very long commit message that exceeds the recommended length...")
except NotAGitProjectError as e:
print(f"Git error: {e}")
except CommitMessageLengthError as e:
print(f"Commit message too long: {e}")
except GitCommandError as e:
print(f"Git command failed: {e}")
print(f"Return code: {e.return_code}")
print(f"Error output: {e.stderr}")from commitizen import git
from commitizen.cmd import run
# Custom git operations using command runner
def get_current_branch() -> str:
"""Get current git branch name."""
result = run("git branch --show-current")
if result.return_code != 0:
raise GitCommandError("Failed to get current branch")
return result.out.strip()
def get_remote_url() -> str:
"""Get remote origin URL."""
result = run("git remote get-url origin")
if result.return_code != 0:
raise GitCommandError("Failed to get remote URL")
return result.out.strip()
# Repository information
try:
branch = get_current_branch()
remote = get_remote_url()
print(f"Current branch: {branch}")
print(f"Remote URL: {remote}")
# Check if branch is up to date
if git.is_staging_clean():
print("Working directory is clean")
# Get commits on current branch
commits = git.get_commits(rev=f"origin/{branch}..HEAD")
print(f"Commits ahead: {len(commits)}")
except GitCommandError as e:
print(f"Git operation failed: {e}")from commitizen import git
from pathlib import Path
def install_commit_msg_hook():
"""Install commit message validation hook."""
hooks_dir = git.find_git_project_root() / ".git" / "hooks"
hook_file = hooks_dir / "commit-msg"
hook_content = """#!/bin/sh
# Commitizen commit message validation
exec commitizen check --commit-msg-file $1
"""
hook_file.write_text(hook_content)
hook_file.chmod(0o755)
print("Commit message hook installed")
def install_pre_push_hook():
"""Install pre-push validation hook."""
hooks_dir = git.find_git_project_root() / ".git" / "hooks"
hook_file = hooks_dir / "pre-push"
hook_content = """#!/bin/sh
# Commitizen branch validation
exec commitizen check --rev-range origin/main..HEAD
"""
hook_file.write_text(hook_content)
hook_file.chmod(0o755)
print("Pre-push hook installed")Install with Tessl CLI
npx tessl i tessl/pypi-commitizen