CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-bump-my-version

Version-bump your software with a single command

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

hooks.mddocs/

Hook System

Pre-commit, post-commit, and setup hook system for extending bump-my-version functionality with custom automation workflows. Provides shell command execution at key points in the version bump process with full context access and error handling.

Capabilities

Hook Execution Functions

Functions for executing hooks at different stages of the version bump workflow.

def run_setup_hooks(
    config: Config, 
    current_version: Version, 
    dry_run: bool = False
) -> None:
    """
    Execute setup hooks before version processing begins.
    
    Runs configured setup hooks in sequence before any version analysis
    or file modifications. Useful for environment preparation or validation.
    
    Args:
        config: Configuration containing setup_hooks list
        current_version: Current Version object for context
        dry_run: Preview operations without executing
        
    Raises:
        HookError: Hook execution failed
    """

def run_pre_commit_hooks(
    config: Config,
    current_version: Version,
    new_version: Version,
    dry_run: bool = False
) -> None:
    """
    Execute pre-commit hooks before SCM operations.
    
    Runs configured pre-commit hooks after file modifications but before
    creating commits or tags. Ideal for formatting, linting, or testing.
    
    Args:
        config: Configuration containing pre_commit_hooks list
        current_version: Current Version object
        new_version: New Version object
        dry_run: Preview operations without executing
        
    Raises: 
        HookError: Hook execution failed
    """

def run_post_commit_hooks(
    config: Config,
    current_version: Version,
    new_version: Version,
    dry_run: bool = False
) -> None:
    """  
    Execute post-commit hooks after SCM operations complete.
    
    Runs configured post-commit hooks after all version bump operations
    including commits and tags. Perfect for deployment, notifications, or cleanup.
    
    Args:
        config: Configuration containing post_commit_hooks list
        current_version: Current Version object
        new_version: New Version object
        dry_run: Preview operations without executing
        
    Raises:
        HookError: Hook execution failed
    """

Hook Configuration

Hook settings are configured in the main bump-my-version configuration:

class Config(BaseSettings):
    # Hook configuration lists
    setup_hooks: List[str] = []
    pre_commit_hooks: List[str] = []
    post_commit_hooks: List[str] = []

Hook Types and Timing

Setup Hooks

Execute before any version processing begins:

[tool.bumpversion]
setup_hooks = [
    "echo 'Starting version bump process'",
    "uv sync --upgrade",
    "python -m pytest --no-cov -x",
    "pre-commit run --all-files"
]

Use Cases:

  • Environment validation and setup
  • Dependency updates
  • Pre-flight testing
  • Code formatting and linting
  • Documentation generation

Pre-commit Hooks

Execute after file modifications but before SCM operations:

[tool.bumpversion]
pre_commit_hooks = [
    "python setup.py check",
    "uv build",
    "twine check dist/*",
    "git add dist/",
    "git add CHANGELOG.md"
]

Use Cases:

  • Package building and validation
  • Additional file modifications
  • Staging extra files for commit
  • Running final tests
  • Documentation updates

Post-commit Hooks

Execute after all SCM operations complete:

[tool.bumpversion]
post_commit_hooks = [
    "git push origin main",
    "git push --tags",
    "gh release create {new_version} --generate-notes",
    "uv publish",
    "slack-notify 'Released {new_version}'"
]

Use Cases:

  • Pushing changes to remote repositories
  • Creating GitHub/GitLab releases
  • Publishing packages to registries
  • Sending notifications
  • Triggering CI/CD pipelines
  • Deployment automation

Hook Context and Templating

Hooks have access to the full template context including version information, timestamps, and SCM details:

Available Context Variables

context = {
    # Version information
    "current_version": "1.0.0",
    "new_version": "1.0.1", 
    "major": "1",
    "minor": "0",
    "patch": "1",
    
    # SCM information
    "commit_sha": "abc123...",
    "branch_name": "main",
    "tag_name": "v1.0.1",
    
    # Timestamps
    "now": datetime.now(),
    "utcnow": datetime.utcnow(),
    
    # Environment variables (BMP_* prefixed)
    "BMP_CUSTOM_VAR": "value"
}

Template Usage in Hooks

[tool.bumpversion]
post_commit_hooks = [
    "echo 'Released version {new_version} on {now:%Y-%m-%d}'",
    "git tag -a archive-{current_version} -m 'Archive old version {current_version}'",
    "curl -X POST https://api.example.com/releases -d version={new_version}",
    "docker build -t myapp:{new_version} .",
    "docker push myapp:{new_version}"
]

Configuration Examples

Basic Hook Configuration

[tool.bumpversion]
current_version = "1.0.0"
commit = true
tag = true

# Simple hooks
setup_hooks = ["python -m pytest"]
pre_commit_hooks = ["python setup.py check"]
post_commit_hooks = ["git push --follow-tags"]

Advanced Hook Workflows

[tool.bumpversion]
current_version = "1.0.0"
commit = true
tag = true

# Comprehensive development workflow
setup_hooks = [
    "echo 'Starting release process for {current_version} → {new_version}'",
    "uv sync --upgrade",
    "python -m pytest --cov=src --cov-report=html",
    "pre-commit run --all-files",
    "python -c 'import sys; sys.exit(0 if \"{new_version}\" > \"{current_version}\" else 1)'"
]

pre_commit_hooks = [
    "uv build",
    "twine check dist/*",
    "python scripts/update_changelog.py {current_version} {new_version}",
    "git add CHANGELOG.md",
    "python scripts/update_docs.py {new_version}",
    "git add docs/"
]

post_commit_hooks = [
    "git push origin {branch_name}",
    "git push --tags", 
    "gh release create {new_version} dist/* --generate-notes",
    "uv publish --token $PYPI_TOKEN",
    "python scripts/notify_slack.py 'Released {new_version}'",
    "python scripts/update_dependencies.py {new_version}"
]

CI/CD Integration Hooks

[tool.bumpversion]
# Hooks for CI/CD pipeline integration
setup_hooks = [
    "echo 'CI Release Process Started'",
    "echo 'RELEASE_VERSION={new_version}' >> $GITHUB_ENV"
]

pre_commit_hooks = [
    "docker build -t myapp:{new_version} .",
    "docker run --rm myapp:{new_version} python -m pytest",
    "echo 'DOCKER_IMAGE=myapp:{new_version}' >> $GITHUB_ENV"
]  

post_commit_hooks = [
    "docker push myapp:{new_version}",
    "docker tag myapp:{new_version} myapp:latest",
    "docker push myapp:latest",
    "kubectl set image deployment/myapp myapp=myapp:{new_version}"
]

Usage Examples

Programmatic Hook Execution

from bumpversion.hooks import run_setup_hooks, run_pre_commit_hooks, run_post_commit_hooks
from bumpversion.config import get_configuration
from bumpversion.context import get_context

# Load configuration
config = get_configuration()

# Create context
context = get_context(config)
context.update({
    "current_version": "1.0.0",
    "new_version": "1.0.1"
})

# Create version objects
from bumpversion.versioning.models import Version
current_version = Version({"major": "1", "minor": "0", "patch": "0"}, None)
new_version = Version({"major": "1", "minor": "0", "patch": "1"}, None)

try:
    # Execute hooks in sequence
    run_setup_hooks(config, current_version, dry_run=False)
    print("Setup hooks completed successfully")
    
    # ... perform version bump operations ...
    
    run_pre_commit_hooks(config, current_version, new_version, dry_run=False)
    print("Pre-commit hooks completed successfully")
    
    # ... perform SCM operations ...
    
    run_post_commit_hooks(config, current_version, new_version, dry_run=False)
    print("Post-commit hooks completed successfully")
    
except HookError as e:
    print(f"Hook execution failed: {e}")
    print(f"Failed command: {e.command}")
    print(f"Exit code: {e.exit_code}")
    print(f"Output: {e.output}")

Custom Hook Runner

import subprocess
from typing import List, Dict, Any
from bumpversion.exceptions import HookError

def run_custom_hooks(
    hooks: List[str], 
    context: Dict[str, Any],
    cwd: Optional[Path] = None
) -> None:
    """
    Run custom hooks with enhanced error handling.
    
    Args:
        hooks: List of shell commands to execute
        context: Template context for command formatting
        cwd: Working directory for command execution
    """
    for hook in hooks:
        try:
            # Format command with context
            formatted_command = hook.format(**context)
            print(f"Executing hook: {formatted_command}")
            
            # Execute command
            result = subprocess.run(
                formatted_command,
                shell=True,
                cwd=cwd,
                capture_output=True,
                text=True,
                check=True
            )
            
            print(f"Hook output: {result.stdout}")
            
        except subprocess.CalledProcessError as e:
            raise HookError(
                f"Hook failed: {formatted_command}",
                command=formatted_command,
                exit_code=e.returncode,
                output=e.stderr
            )

Conditional Hook Execution

import os
from bumpversion.hooks import run_post_commit_hooks

# Only run deployment hooks in production environment
if os.getenv("ENVIRONMENT") == "production":
    config.post_commit_hooks.extend([
        "python scripts/deploy_production.py {new_version}",
        "python scripts/notify_team.py 'Production deployment of {new_version} complete'"
    ])

# Run different hooks based on version type
if context.get("patch") != "0":
    # Patch release
    config.post_commit_hooks.append("python scripts/hotfix_notification.py")
elif context.get("minor") != "0":
    # Minor release  
    config.post_commit_hooks.append("python scripts/feature_announcement.py")
else:
    # Major release
    config.post_commit_hooks.extend([
        "python scripts/major_release_blog.py {new_version}",
        "python scripts/social_media_announcement.py {new_version}"
    ])

Hook Error Handling

from bumpversion.hooks import run_pre_commit_hooks
from bumpversion.exceptions import HookError

try:
    run_pre_commit_hooks(config, current_version, new_version)
except HookError as e:
    print(f"Pre-commit hook failed: {e}")
    
    # Check if it's a specific type of failure
    if "pytest" in e.command:
        print("Tests failed - aborting release")
        sys.exit(1)
    elif "build" in e.command:
        print("Build failed - checking for dependency issues") 
        # Could implement recovery logic here
    else:
        print(f"Unknown hook failure: {e.command}")
        print(f"Exit code: {e.exit_code}")
        print(f"Error output: {e.output}")

Environment-Specific Hooks

[tool.bumpversion]
# Base configuration
current_version = "1.0.0"

# Development environment hooks
setup_hooks = [
    "python -c 'import os; print(f\"Environment: {os.getenv(\"ENVIRONMENT\", \"development\")}\")'",
    "if [ \"$ENVIRONMENT\" = \"development\" ]; then echo 'Dev mode - skipping some checks'; fi"
]

post_commit_hooks = [
    # Always push to origin
    "git push origin {branch_name}",
    "git push --tags",
    
    # Conditional publishing
    "if [ \"$ENVIRONMENT\" = \"production\" ]; then uv publish; fi",
    "if [ \"$ENVIRONMENT\" = \"staging\" ]; then uv publish --repository testpypi; fi"
]

Hook Best Practices

Error Handling

  • Always use proper exit codes in hook scripts
  • Provide meaningful error messages
  • Consider implementing rollback mechanisms
  • Log hook execution for debugging

Performance

  • Keep hooks lightweight and fast
  • Use parallel execution where possible
  • Cache dependencies and build artifacts
  • Avoid redundant operations

Security

  • Validate all inputs and context variables
  • Use secure credential management
  • Audit hook commands for security issues
  • Limit hook permissions appropriately

Testing

  • Test hooks in isolation
  • Use dry-run modes where available
  • Implement hook validation scripts
  • Test error conditions and recovery

Install with Tessl CLI

npx tessl i tessl/pypi-bump-my-version

docs

cli-commands.md

configuration.md

core-version-management.md

file-operations.md

hooks.md

index.md

scm-integration.md

tile.json