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, useuv runto invoke commands (e.g.uv run semantic-tag-increment --help), or activate the virtual environment first withsource .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 withsource .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.123→v1.2.4(when incrementing patch)
- Preserve metadata: Use
--preserve-metadataflag to maintain build metadatav1.2.3+build.123→v1.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 --upgradeto rebuild and update theuv.lockfile with the latest compatible versions - Add new dependencies: Add to
pyproject.tomlthen runuv lockto update the lock file - Install from lock file:
uv syncwill use the exact versions fromuv.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
- Semantic Versioning specification
- Python packaging community for best practices
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: This README and inline code documentation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6057c47142da1ce001aad0f0e3611e987ce010102e94e15c51a647fe3b60abd
|
|
| MD5 |
eb4f2cea7f64b70402477dec2474d47f
|
|
| BLAKE2b-256 |
b1d7237ab4c07753a652b1a653721f4524f7b1ce34d0f2d4f441ed62fad75ee1
|
File details
Details for the file semantic_tag_increment-0.1.1-py3-none-any.whl.
File metadata
- Download URL: semantic_tag_increment-0.1.1-py3-none-any.whl
- Upload date:
- Size: 43.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7fa82504b314da86c6c67e06ae9ca19099a6e57b42be39e2439aafe4ec32f16
|
|
| MD5 |
a5c4f026ce6feb67532d15c6598de38e
|
|
| BLAKE2b-256 |
d4ce47df7253cf554bc99767d642eb117978d892f655b5159f7841d292fd1652
|