Version-bump your software with a single command
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Source control management integration supporting Git and Mercurial for automated commits, tagging, and repository state management. Provides comprehensive SCM operations with repository status checking, dirty state validation, and automated commit/tag workflows.
Classes for managing source control information and repository state.
class SCMInfo:
"""
Information about the current source code management system.
Provides comprehensive repository state including current commit,
branch information, tag distance, and version detection from SCM.
"""
def __init__(
self,
tool: Optional[str] = None,
commit_sha: Optional[str] = None,
distance_to_latest_tag: int = 0,
current_version: str = "0.0.0",
branch_name: Optional[str] = None,
repository_root: Optional[Path] = None,
short_branch_name: Optional[str] = None
) -> None:
"""
Initialize SCM information.
Args:
tool: SCM tool name ('git', 'hg', etc.)
commit_sha: Current commit SHA
distance_to_latest_tag: Number of commits since latest tag
current_version: Current version string
branch_name: Full branch name
repository_root: Path to repository root
short_branch_name: Short branch name
"""
@property
def is_dirty(self) -> bool:
"""Whether repository has uncommitted changes."""
@property
def latest_tag_info(self) -> Optional[LatestTagInfo]:
"""Information about the most recent tag."""
class LatestTagInfo:
"""
Information about the latest repository tag.
Contains tag name, commit SHA, and version information
extracted from the most recent repository tag.
"""
tag_name: str
commit_sha: str
version: Optional[str] = None
@property
def is_version_tag(self) -> bool:
"""Whether tag represents a version."""
class SCMConfig:
"""
Configuration for SCM operations.
Contains settings for commit behavior, tag creation,
message templates, and repository interaction options.
"""
commit: bool = False
tag: bool = False
commit_args: str = ""
message: str = "Bump version: {current_version} → {new_version}"
tag_name: str = "v{new_version}"
tag_message: str = "Bump version: {current_version} → {new_version}"
sign_tags: bool = False
allow_dirty: bool = FalseComprehensive Git integration with full repository management capabilities.
class Git:
"""
Git implementation for SCM operations.
Provides complete Git integration including repository status checking,
commit creation, tag management, and branch operations.
"""
def __init__(self, repo_root: Path) -> None:
"""
Initialize Git integration.
Args:
repo_root: Path to Git repository root
"""
def is_dirty(self) -> bool:
"""
Check if repository has uncommitted changes.
Returns:
True if repository has staged or unstaged changes
"""
def commit_and_tag(
self,
message: str,
tag_name: Optional[str] = None,
tag_message: Optional[str] = None,
sign_tags: bool = False,
commit_args: str = ""
) -> None:
"""
Create commit and optional tag for version changes.
Stages all modified files, creates commit with specified message,
and optionally creates annotated tag.
Args:
message: Commit message
tag_name: Tag name to create (optional)
tag_message: Tag annotation message
sign_tags: Whether to sign tags with GPG
commit_args: Additional arguments for git commit
Raises:
subprocess.CalledProcessError: Git command failed
"""
def get_current_info(self) -> SCMInfo:
"""
Get comprehensive repository information.
Returns:
SCMInfo object with current repository state
"""
def get_latest_tag_info(self) -> Optional[LatestTagInfo]:
"""
Get information about the most recent tag.
Returns:
LatestTagInfo object or None if no tags exist
"""
def get_branch_name(self) -> Optional[str]:
"""
Get current branch name.
Returns:
Current branch name or None if detached HEAD
"""
def add_path(self, path: Path) -> None:
"""
Add file or directory to Git staging area.
Args:
path: Path to add to staging area
"""
def tag_exists(self, tag_name: str) -> bool:
"""
Check if tag exists in repository.
Args:
tag_name: Tag name to check
Returns:
True if tag exists
"""
class Mercurial:
"""
Mercurial implementation for SCM operations.
Provides Mercurial integration with repository status checking,
commit creation, and tag management capabilities.
"""
def __init__(self, repo_root: Path) -> None:
"""Initialize Mercurial integration."""
def is_dirty(self) -> bool:
"""Check if repository has uncommitted changes."""
def commit_and_tag(
self,
message: str,
tag_name: Optional[str] = None,
tag_message: Optional[str] = None
) -> None:
"""Create commit and optional tag."""
def get_current_info(self) -> SCMInfo:
"""Get repository information."""Helper functions for SCM detection and management.
def get_scm_info(repo_path: Optional[Path] = None) -> Optional[SCMInfo]:
"""
Detect and get SCM information for repository.
Automatically detects Git or Mercurial repositories and returns
comprehensive information about repository state.
Args:
repo_path: Path to repository (defaults to current directory)
Returns:
SCMInfo object or None if no SCM detected
"""
def detect_scm_type(repo_path: Path) -> Optional[str]:
"""
Detect SCM type for repository.
Args:
repo_path: Path to check for SCM
Returns:
SCM type ('git', 'hg') or None
"""[tool.bumpversion]
current_version = "1.0.0"
commit = true
tag = true
allow_dirty = false
message = "Bump version: {current_version} → {new_version}"
tag_name = "v{new_version}"
tag_message = "Release {new_version}"
commit_args = "--no-verify"
sign_tags = false[tool.bumpversion]
# Commit settings
commit = true
commit_args = "--no-verify --gpg-sign"
message = """
Release version {new_version}
Changes:
- Updated version from {current_version} to {new_version}
- Automated by bump-my-version on {now:%Y-%m-%d}
"""
# Tag settings
tag = true
tag_name = "release-{new_version}"
tag_message = "Release {new_version} ({now:%Y-%m-%d})"
sign_tags = true
# Repository settings
allow_dirty = falsefrom bumpversion.config import get_configuration
# Load configuration
config = get_configuration()
# Only commit in CI environment
import os
if os.getenv("CI"):
config.commit = True
config.tag = True
else:
config.commit = False
config.tag = Falsefrom bumpversion.scm.git import Git
from pathlib import Path
# Initialize Git integration
git = Git(Path.cwd())
# Check repository status
if git.is_dirty():
print("Repository has uncommitted changes")
# Get repository information
scm_info = git.get_current_info()
print(f"Current branch: {scm_info.branch_name}")
print(f"Current commit: {scm_info.commit_sha}")
print(f"Distance to latest tag: {scm_info.distance_to_latest_tag}")
# Create commit and tag
git.commit_and_tag(
message="Bump version: 1.0.0 → 1.0.1",
tag_name="v1.0.1",
tag_message="Release version 1.0.1"
)from bumpversion.scm.models import SCMInfo
from bumpversion.scm.git import Git
# Get comprehensive repository information
git = Git(Path.cwd())
scm_info = git.get_current_info()
print(f"SCM Tool: {scm_info.tool}")
print(f"Repository Root: {scm_info.repository_root}")
print(f"Current Branch: {scm_info.branch_name}")
print(f"Is Dirty: {scm_info.is_dirty}")
# Check latest tag information
latest_tag = git.get_latest_tag_info()
if latest_tag:
print(f"Latest Tag: {latest_tag.tag_name}")
print(f"Tag Commit: {latest_tag.commit_sha}")
print(f"Is Version Tag: {latest_tag.is_version_tag}")from bumpversion.scm.git import Git
from bumpversion.context import get_context
from bumpversion.config import get_configuration
# Load configuration and create context
config = get_configuration()
context = get_context(config)
# Initialize Git
git = Git(Path.cwd())
# Check if repository is clean (if required)
if not config.allow_dirty and git.is_dirty():
raise DirtyWorkingDirectoryError("Repository has uncommitted changes")
# Format commit and tag messages
commit_message = config.message.format(**context)
tag_name = config.tag_name.format(**context) if config.tag else None
tag_message = config.tag_message.format(**context) if config.tag else None
# Create commit and tag
git.commit_and_tag(
message=commit_message,
tag_name=tag_name,
tag_message=tag_message,
sign_tags=config.sign_tags,
commit_args=config.commit_args
)from bumpversion.scm.git import Git
git = Git(Path.cwd())
# Get current branch
branch = git.get_branch_name()
print(f"Current branch: {branch}")
# Check if tag exists
tag_name = "v1.0.1"
if git.tag_exists(tag_name):
print(f"Tag {tag_name} already exists")
else:
print(f"Tag {tag_name} is available")
# Add specific files to staging
from pathlib import Path
git.add_path(Path("setup.py"))
git.add_path(Path("src/mypackage/__init__.py"))from bumpversion.config import get_configuration
from bumpversion.scm.git import Git
from bumpversion.context import get_context
# Load configuration with SCM settings
config = get_configuration(
commit=True,
tag=True,
message="Release {new_version}",
tag_name="v{new_version}",
allow_dirty=False
)
# Get SCM instance
git = Git(Path.cwd())
# Validate repository state
if not config.allow_dirty and git.is_dirty():
print("Repository must be clean for version bump")
exit(1)
# Get context for templating
context = get_context(config)
context.update({
"current_version": "1.0.0",
"new_version": "1.0.1"
})
# Execute SCM operations if configured
if config.commit or config.tag:
git.commit_and_tag(
message=config.message.format(**context),
tag_name=config.tag_name.format(**context) if config.tag else None,
tag_message=config.tag_message.format(**context) if config.tag else None,
sign_tags=config.sign_tags,
commit_args=config.commit_args
)from bumpversion.scm.git import Git
from bumpversion.exceptions import DirtyWorkingDirectoryError
import subprocess
try:
git = Git(Path.cwd())
# Check repository state
if git.is_dirty() and not allow_dirty:
raise DirtyWorkingDirectoryError(
"Repository has uncommitted changes. "
"Use --allow-dirty to override."
)
# Attempt SCM operations
git.commit_and_tag(
message="Bump version",
tag_name="v1.0.1",
tag_message="Release 1.0.1"
)
except subprocess.CalledProcessError as e:
print(f"Git command failed: {e}")
print(f"Command: {e.cmd}")
print(f"Output: {e.output}")
except DirtyWorkingDirectoryError as e:
print(f"Repository state error: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-bump-my-version