Skip to main content

A Python tool for incrementing semantic version tags with GitHub Actions support

Project description

Semantic Tag Increment

A simple, focused tool for incrementing semantic version tags. This tool takes an explicit semantic version tag as input and increments it according to semantic versioning rules.

semantic-tag-increment

Features

  • String-based tag incrementing: Provide a semantic version tag and increment type
  • Semantic versioning compliant: Follows SemVer specification
  • Complex pre-release support: Handles compound pre-release identifiers
  • GitHub Actions integration: Easy to use in CI/CD workflows
  • Conflict detection: Optional checking against existing Git tags
  • Flexible output formats: Full version with prefix or numeric output

Supported Version Patterns

The tool supports standard semantic versioning patterns:

  • Basic versions: 1.0.0, v2.1.3
  • Pre-release versions: 1.0.0-alpha.1, v2.1.0-beta.2, 1.5.0-rc.1
  • Development versions: 1.0.0-dev.1, v1.2.3-dev.5
  • Custom pre-release types: 1.0.0-snapshot.1, v1.0.0-nightly.1
  • Build metadata: 1.0.0+20230101 (configurable preservation)
  • Mixed case prefixes: V1.0.0, v1.0.0

Installation

From PyPI (when published)

pip install semantic-tag-increment

From Source

Install uv then run:

git clone https://github.com/lfreleng-actions/semantic-tag-increment.git
cd semantic-tag-increment
uv sync

Note: After uv sync, use uv run to invoke commands (e.g. uv run semantic-tag-increment --help), or activate the virtual environment first with source .venv/bin/activate.

Development Installation

Install uv then run:

git clone https://github.com/lfreleng-actions/semantic-tag-increment.git
cd semantic-tag-increment
uv sync --all-extras

Note: Prefix commands with uv run (e.g. uv run semantic-tag-increment, uv run pytest), or activate the virtual environment first with source .venv/bin/activate.

Usage

Command Line Interface

The tool provides a simple command-line interface for incrementing version tags:

# Increment patch version
semantic-tag-increment --tag "v1.2.3" --increment "patch"
# Output: v1.2.4

# Increment minor version
semantic-tag-increment --tag "v1.2.3" --increment "minor"
# Output: v1.3.0

# Increment major version
semantic-tag-increment --tag "v1.2.3" --increment "major"
# Output: v2.0.0

# Add pre-release version
semantic-tag-increment --tag "v1.2.3" --increment "prerelease"
# Output: v1.2.4-dev.1

# Increment with custom pre-release type
semantic-tag-increment --tag "v1.2.3" --increment "prerelease" \
  --prerelease-type "alpha"
# Output: v1.2.4-alpha.1

# Preserve build metadata during increment
semantic-tag-increment --tag "v1.2.3+build.123" --increment "patch" \
  --preserve-metadata
# Output: v1.2.4+build.123

# Strip build metadata (default behavior)
semantic-tag-increment --tag "v1.2.3+build.123" --increment "patch"
# Output: v1.2.4

Understanding Increment Types

  • patch: Increments the patch version (1.2.3 → 1.2.4)
  • minor: Increments the minor version and resets patch (1.2.3 → 1.3.0)
  • major: Increments the major version and resets minor/patch (1.2.3 → 2.0.0)
  • prerelease/dev: Adds or increments pre-release version (1.2.3 → 1.2.4-dev.1)

Validation Mode

Use the --validate flag to check if a tag is a valid semantic version without incrementing:

# Check basic version
semantic-tag-increment --tag "v1.2.3" --validate

# Check complex version with prerelease and metadata
semantic-tag-increment --tag "v1.2.3-alpha.1+build.123" --validate

Version Validation

# Check a semantic version
semantic-tag-increment --tag "v1.2.3-alpha.1" --validate

Get Version Suggestions

Use the --suggest flag to list candidate next versions:

# Get suggestions for prerelease versions (default when using --suggest)
semantic-tag-increment --tag "v1.2.3" --suggest

# Get suggestions for specific increment type
semantic-tag-increment --tag "v1.2.3" --increment "prerelease" --suggest

# See suggestions for other increment types
semantic-tag-increment --tag "v1.2.3" --increment "patch" --suggest

CLI Options

  • --tag, -t: The existing semantic tag to increment (required)
  • --increment, -i: Increment type: major, minor, patch, prerelease, dev (defaults: dev for increment, prerelease for --suggest, not required with --validate)
  • --prerelease-type, -p: Custom prerelease identifier (alpha, beta, rc, etc.)
  • --preserve-metadata/--no-preserve-metadata: Preserve or strip build metadata during increments (default: strip)
  • --validate: Check the semantic version tag format without incrementing
  • --suggest: List candidate next versions for the given increment type
  • --check-conflicts/--no-check-conflicts: Enable/disable Git tag conflict checking
  • --output-format, -f: Output format: full, numeric, both (default: full)
  • --path: Directory for Git operations (default: current directory)
  • --debug: Enable debug logging

GitHub Actions

Basic Usage

name: Increment Version
on:
  push:
    branches: [main]

jobs:
  increment-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Increment patch version
        id: increment
        uses: lfreleng-actions/semantic-tag-increment@v1
        with:
          tag: 'v1.2.3'
          increment: 'patch'

      - name: Use new version
        run: |
          echo "New version: ${{ steps.increment.outputs.tag }}"
          echo "Numeric: ${{ steps.increment.outputs.numeric_tag }}"

Advanced Examples

# Increment with pre-release type
- name: Create alpha release
  uses: lfreleng-actions/semantic-tag-increment@v1
  with:
    tag: 'v1.2.3'
    increment: 'prerelease'
    prerelease_type: 'alpha'

# Increment with conflict checking disabled
- name: Fast increment
  uses: lfreleng-actions/semantic-tag-increment@v1
  with:
    tag: 'v1.2.3'
    increment: 'minor'
    check_tags: 'false'

# Increment in a subdirectory
- name: Increment with custom path
  uses: lfreleng-actions/semantic-tag-increment@v1
  with:
    tag: 'v1.2.3'
    increment: 'patch'
    path: './project-subdirectory'

# Preserve build metadata during increment
- name: Increment preserving metadata
  uses: lfreleng-actions/semantic-tag-increment@v1
  with:
    tag: 'v1.2.3+build.123'
    increment: 'patch'
    preserve_metadata: 'true'
    # Output: v1.2.4+build.123

Action Inputs

Input Description Required Default
tag The existing semantic tag for incrementing Yes -
increment Increment type: major, minor, patch, prerelease, dev No dev
prerelease_type Prerelease type (alpha, beta, rc, etc.) No -
path Directory location for git operations No .
debug Enable verbose debug output No false
check_tags Check against existing repository tags No true
preserve_metadata Preserve build metadata during increments No false

Action Outputs

Output Description
tag The incremented tag string with any original prefix
numeric_tag Numeric tag stripped of any v/V prefix

Implementation Details

Architecture

The tool uses a modular architecture:

  • Parser: Robust semantic version parsing with prefix preservation
  • Incrementer: Core increment logic with conflict resolution
  • Git Operations: Optional integration with Git for tag conflict checking
  • CLI Interface: Clean command-line interface using Typer
  • GitHub Actions: Native GitHub Actions integration

Smart Pre-release Handling

The tool intelligently handles pre-release versions:

  • Automatically detects existing pre-release components
  • Increments numeric components when present
  • Preserves custom pre-release identifiers
  • Supports complex pre-release patterns like 1.0.0-alpha.1.beta.2

Build Metadata Handling

The tool provides configurable handling of build metadata:

  • Default behavior: Build metadata gets stripped during increments
    • v1.2.3+build.123v1.2.4 (when incrementing patch)
  • Preserve metadata: Use --preserve-metadata flag to maintain build metadata
    • v1.2.3+build.123v1.2.4+build.123 (when incrementing patch with preservation)
  • Semantic versioning compliance: Build metadata doesn't affect version precedence
  • CI/CD flexibility: Choose behavior based on your workflow needs

Why Strip Metadata by Default?

Build metadata is typically specific to a particular build and becomes outdated when the version gets incremented. The default behavior of stripping metadata follows common practices where:

  • New versions get fresh build metadata from the current build
  • Outdated build information doesn't carry forward
  • Clean version increments without stale metadata

When to Preserve Metadata?

Preserve metadata when:

  • The metadata contains persistent information (not build-specific)
  • Your workflow requires maintaining certain metadata across increments
  • You have custom metadata that should persist through version changes

Version Comparison

With conflict checking enabled, the tool:

  • Fetches existing Git tags from the repository
  • Compares semantic versions semantically (not lexicographically)
  • Finds the next available version to avoid conflicts
  • Respects semantic versioning precedence rules

Development

Setting Up Development Environment

# Clone the repository
git clone https://github.com/lfreleng-actions/semantic-tag-increment.git
cd semantic-tag-increment

# Install in development mode with all dependencies
uv sync --all-extras

# Set up pre-commit hooks
uv run pre-commit install

Dependency management

  • Update dependencies: Use uv lock --upgrade to rebuild and update the uv.lock file with the latest compatible versions
  • Add new dependencies: Add to pyproject.toml then run uv lock to update the lock file
  • Install from lock file: uv sync will use the exact versions from uv.lock

Testing

# Run unit tests
uv run pytest

# Run with coverage
uv run pytest --cov=semantic_tag_increment

# Run integration tests
uv run pytest tests/test_integration.py

# Run performance tests
uv run pytest tests/test_performance_optimizations.py

Code Quality

# Format code
uv run ruff format src/ tests/

# Lint code
uv run ruff check .

# Type checking
uv run mypy src/

# Security checks
uv run ruff check --select=S src/

Performance

The tool optimizes for performance:

  • Efficient regex-based version parsing
  • Minimal Git operations with conflict checking enabled
  • Lazy loading of dependencies
  • Optimized for CI/CD environments

Examples

Real-world Release Workflow

name: Release Workflow
on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Get current version
        id: current
        run: |
          CURRENT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
          echo "tag=$CURRENT_TAG" >> $GITHUB_OUTPUT

      - name: Increment version
        id: increment
        uses: lfreleng-actions/semantic-tag-increment@v1
        with:
          tag: ${{ steps.current.outputs.tag }}
          increment: 'patch'

      - name: Create and push tag
        run: |
          git tag ${{ steps.increment.outputs.tag }}
          git push origin ${{ steps.increment.outputs.tag }}

      - name: Create GitHub release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ steps.increment.outputs.tag }}
          release_name: Release ${{ steps.increment.outputs.tag }}

Complex Pre-release Patterns

# Start with a base version
semantic-tag-increment --tag "v1.0.0" --increment "prerelease" \
  --prerelease-type "alpha"
# Output: v1.0.1-alpha.1

# Increment the alpha
semantic-tag-increment --tag "v1.0.1-alpha.1" --increment "prerelease"
# Output: v1.0.1-alpha.2

# Move to beta
semantic-tag-increment --tag "v1.0.1-alpha.2" \
  --increment "prerelease" --prerelease-type "beta"
# Output: v1.0.1-beta.1

# Move to release candidate
semantic-tag-increment --tag "v1.0.1-beta.1" \
  --increment "prerelease" --prerelease-type "rc"
# Output: v1.0.1-rc.1

# Final release
semantic-tag-increment --tag "v1.0.1-rc.1" --increment "patch"
# Output: v1.0.1

Contributing

We welcome contributions! See our Contributing Guide for details.

Code Standards

  • Follow PEP 8 style
  • Use type hints for all public APIs
  • Write comprehensive tests for new features
  • Update documentation for user-facing changes

License

This project uses the Apache License 2.0 - see the LICENSE file for details.

Acknowledgments

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

semantic_tag_increment-0.1.1.tar.gz (102.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

semantic_tag_increment-0.1.1-py3-none-any.whl (43.0 kB view details)

Uploaded Python 3

File details

Details for the file semantic_tag_increment-0.1.1.tar.gz.

File metadata

  • Download URL: semantic_tag_increment-0.1.1.tar.gz
  • Upload date:
  • Size: 102.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for semantic_tag_increment-0.1.1.tar.gz
Algorithm Hash digest
SHA256 b6057c47142da1ce001aad0f0e3611e987ce010102e94e15c51a647fe3b60abd
MD5 eb4f2cea7f64b70402477dec2474d47f
BLAKE2b-256 b1d7237ab4c07753a652b1a653721f4524f7b1ce34d0f2d4f441ed62fad75ee1

See more details on using hashes here.

File details

Details for the file semantic_tag_increment-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for semantic_tag_increment-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f7fa82504b314da86c6c67e06ae9ca19099a6e57b42be39e2439aafe4ec32f16
MD5 a5c4f026ce6feb67532d15c6598de38e
BLAKE2b-256 d4ce47df7253cf554bc99767d642eb117978d892f655b5159f7841d292fd1652

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page