Versioning
Consistent versioning enables reliable deployments and rollbacks. This guide covers semantic versioning, automatic and manual version bumps, and creating GitHub releases.
What You'll Learn
- Semantic versioning strategy for the platform
- Automatic patch versions on merge
- Manual minor/major releases with cut-tag workflows
- Creating GitHub releases with artifacts
Semantic Versioning
The platform uses Semantic Versioning (SemVer):
MAJOR.MINOR.PATCH
│ │ └── Bug fixes, no API changes
│ └──────── New features, backwards compatible
└────────────── Breaking changes
Examples:
1.0.0→1.0.1: Bug fix1.0.1→1.1.0: New feature added1.1.0→2.0.0: Breaking API change
Version Bump Strategy
The platform uses a two-tier approach to version management:
| Trigger | Version Bump | Automation |
|---|---|---|
| Merge to main | Patch (x.y.Z) | Automatic |
| Manual release | Minor (x.Y.0) or Major (X.0.0) | Manual workflow dispatch |
Automatic Patch Versions
Every merge to main automatically creates a patch release. This ensures:
- Every main branch commit has a version
- Continuous delivery to dev environment
- Traceable deployments
# In build.yml - runs after successful build on main
cut-patch:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: p6m-actions/python-uv-cut-tag@v1
with:
bump: patch
Manual Minor/Major Versions
For significant releases, use the cut-tag workflow with manual dispatch:
# cut-tag.yml
name: Cut Tag
on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
Cut-Tag Actions
Each language has a dedicated cut-tag action that understands its version file format:
| Language | Action | Version File |
|---|---|---|
| Python (uv) | python-uv-cut-tag | pyproject.toml |
| .NET | dotnet-cut-tag | *.csproj |
| Java | java-maven-cut-tag | pom.xml |
| Rust | rust-cut-tag | Cargo.toml |
| JavaScript | js-pnpm-cut-tag | package.json |
How Cut-Tag Works
- Read current version from language-specific file
- Calculate new version based on bump type
- Update version file with new version
- Commit the change to the repository
- Create Git tag (e.g.,
v1.2.3)
The Git tag created here is used later by the Promotion workflow to identify which release to deploy to staging and production.
Common Inputs
| Input | Description | Default |
|---|---|---|
bump | Version component to bump: patch, minor, major | patch |
prerelease | Prerelease identifier (e.g., alpha, beta, rc) | — |
push | Whether to push the tag | true |
Outputs
| Output | Description |
|---|---|
version | The new version number (e.g., 1.2.3) |
tag | The Git tag created (e.g., v1.2.3) |
previous-version | The version before bumping |
Complete Cut-Tag Workflow
- Key Steps
- Complete Workflow
jobs:
cut-tag:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.tag.outputs.version }}
tag: ${{ steps.tag.outputs.tag }}
steps:
- uses: actions/checkout@v4
- name: Cut tag
id: tag
uses: p6m-actions/python-uv-cut-tag@v1
with:
bump: ${{ inputs.bump }}
- name: Build and publish
# Build with new version...
- name: Create GitHub release
uses: p6m-actions/repository-release@v1
with:
tag: ${{ steps.tag.outputs.tag }}
name: ${{ steps.tag.outputs.version }}
name: Cut Tag
on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
default: minor
env:
REGISTRY: ${{ vars.ARTIFACTORY_HOSTNAME }}/${{ vars.ARTIFACTORY_PROJECT }}-docker-local
IMAGE_NAME: applications/my-service
jobs:
cut-tag:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.tag.outputs.version }}
tag: ${{ steps.tag.outputs.tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python with uv
uses: p6m-actions/python-uv-setup@v1
- name: Configure Artifactory
uses: p6m-actions/python-uv-repository-login@v1
with:
artifactory-hostname: ${{ vars.ARTIFACTORY_HOSTNAME }}
artifactory-project: ${{ vars.ARTIFACTORY_PROJECT }}
artifactory-username: ${{ secrets.ARTIFACTORY_USERNAME }}
artifactory-token: ${{ secrets.ARTIFACTORY_IDENTITY_TOKEN }}
- name: Cut tag
id: tag
uses: p6m-actions/python-uv-cut-tag@v1
with:
bump: ${{ inputs.bump }}
- name: Build
uses: p6m-actions/python-uv-build@v1
- name: Set up Docker Buildx
uses: p6m-actions/docker-buildx-setup@v1
- name: Login to Docker registry
uses: p6m-actions/docker-repository-login@v1
with:
registry: ${{ vars.ARTIFACTORY_HOSTNAME }}
username: ${{ secrets.ARTIFACTORY_USERNAME }}
password: ${{ secrets.ARTIFACTORY_IDENTITY_TOKEN }}
- name: Build and push Docker image
id: docker
uses: p6m-actions/python-uv-docker-publish@v1
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
${{ steps.tag.outputs.version }}
latest
platforms: linux/amd64,linux/arm64
- name: Publish Python package
uses: p6m-actions/python-uv-repository-publish@v1
- name: Save digest
run: echo "${{ steps.docker.outputs.digest }}" > digest.txt
- name: Create GitHub release
uses: p6m-actions/repository-release@v1
with:
tag: ${{ steps.tag.outputs.tag }}
name: Release ${{ steps.tag.outputs.version }}
generate-release-notes: true
make-latest: true
artifacts: digest.txt
GitHub Releases
After cutting a tag, create a GitHub release to record the version with artifacts and release notes. See GitHub Releases for details on:
- Creating releases with the
repository-releaseaction - Configuring automatic release notes
- Handling prerelease versions (alpha, beta, rc)
Version Flow Example
main branch: v1.0.0
│
├── PR merged → v1.0.1 (auto patch)
│
├── PR merged → v1.0.2 (auto patch)
│
├── Manual "minor" release → v1.1.0
│
├── PR merged → v1.1.1 (auto patch)
│
└── Manual "major" release → v2.0.0
Best Practices
Commit Messages
Use conventional commit messages for better release notes:
feat: add user authentication endpoint
fix: resolve timeout in batch processing
docs: update API reference
chore: upgrade dependencies
Branch Protection
Configure branch protection rules on main:
- Require pull request reviews
- Require status checks to pass
- Require branches to be up to date
This ensures all changes go through CI before versioning.
Tag Naming
The cut-tag actions create tags with v prefix by default:
- Tag:
v1.2.3 - Version:
1.2.3
This convention distinguishes version tags from other tags.
Related
- GitHub Releases — Creating releases with artifacts
- CI/CD Overview — Build pipeline architecture
- Containerization — Image tagging strategies
- Promotion — Deploying specific versions