home / reference / versioning
Versioning¶
This document outlines Tux's Semantic Versioning 2.0.0 implementation, version detection system, and release process.
Semantic Versioning¶
Tux follows SemVer 2.0.0 with version format MAJOR.MINOR.PATCH:
- MAJOR (
X.y.z): Breaking API changes (command syntax, config formats, plugin interfaces) - MINOR (
x.Y.z): Backward-compatible additions (new commands, features, options) - PATCH (
x.y.Z): Backward-compatible fixes (bugs, security patches)
Public API includes: Discord commands, configuration schemas, plugin APIs, and database compatibility.
Pre-releases: 1.0.0-alpha, 1.0.0-rc.1 (lower precedence than releases) Build metadata: 1.0.0+build.123 (ignored in comparisons)
Version System¶
Tux uses a unified version system (src/tux/shared/version.py) that provides:
- Multi-source detection: Environment variables, VERSION file, git tags with clear priority
- Full SemVer support: Validation, comparison, and parsing using official regex patterns
- Performance optimized: Version detected once and cached for the application lifetime
- Robust error handling: Graceful fallbacks ensure the app always starts
- Build metadata: Git SHA, Python version, and other build information
Version Detection¶
Version is determined dynamically at runtime (pyproject.toml uses placeholder 0.0.0). Priority order:
TUX_VERSIONenv var: Runtime override for testing/deploymentsVERSIONfile: Docker containers and production buildsgit describe --tags --always: Development with git history (supports pre-releases)"dev"fallback: Ensures app always starts
Git tags automatically strip v prefix and handle pre-release versions (v1.2.3-alpha → 1.2.3-alpha).
API Reference¶
from tux.shared.version import (
# Core functions
get_version(), # Get current detected version
get_build_info(), # Get build metadata
# Validation & comparison
is_semantic_version(v), # Validate semver format
compare_versions(v1, v2), # Compare versions (-1, 0, 1)
satisfies_constraint(v, constraint), # Check semver constraints (>, >=, <, <=, ==, !=)
# Version manipulation
bump_version(v, 'major'|'minor'|'patch'), # Increment versions
get_version_info(v), # Parse version components
# Build metadata
generate_build_metadata(sha, date), # Create build metadata strings
)
Features: Full SemVer 2.0.0 compliance, automatic normalization, basic constraint checking (comparison operators), version bumping utilities.
SemVer Implementation Notes¶
- Pre-1.0.0: API may change at any time (SemVer item 4)
- 1.0.0: Defines stable public API with strict SemVer compliance
- Version precedence:
1.0.0-alpha < 1.0.0 < 2.0.0 - Build metadata: Parsed and generated via
generate_build_metadata()(format:sha.{short-sha}.{YYYYMMDD})
Release Cycle and Git Tagging¶
The release process is centered around Git tags and follows semantic versioning principles. All releases must be tagged with proper SemVer versions.
Creating Releases¶
To create a new version, create and push an annotated Git tag:
# Patch release (bug fixes)
git tag -a v1.2.3 -m "Release v1.2.3: Fix user permission bug"
# Minor release (new features)
git tag -a v1.3.0 -m "Release v1.3.0: Add new moderation commands"
# Major release (breaking changes)
git tag -a v2.0.0 -m "Release v2.0.0: Complete config format overhaul"
git push origin v1.2.3
Creating Pre-release Tags¶
Use proper SemVer pre-release identifiers for unstable releases:
# Release candidates
git tag -a v1.2.3-rc.1 -m "Release candidate v1.2.3-rc.1"
git push origin v1.2.3-rc.1
# Beta versions
git tag -a v1.2.3-beta.1 -m "Beta v1.2.3-beta.1"
# Alpha versions
git tag -a v1.2.3-alpha.1 -m "Alpha v1.2.3-alpha.1"
Pre-release Precedence
Pre-release versions have lower precedence than normal versions. For example, 1.2.3-alpha < 1.2.3.
Development Versions¶
Between releases, any new commits will result in a development version string (e.g., 1.2.3-5-g567def8), indicating the number of commits since the last tag. These are automatically generated by git describe and follow SemVer conventions.
Tag Naming Convention¶
- Always prefix with
v(e.g.,v1.2.3, not1.2.3) - Use valid SemVer identifiers only
- Include descriptive commit messages
- Push tags immediately after creation
Release Guidelines¶
Reaching 1.0.0¶
Release when the public API (commands, configs, plugins) is stable and production-ready. Pre-1.0.0 allows any changes.
Breaking Changes¶
Require major version bump. Always deprecate first (minor release) before removal (major release). Even small API changes need major bumps.
Deprecation Process¶
- Add deprecation warnings in minor release
- Document migration path
- Remove deprecated features in next major release
Docker Image Tagging¶
Our Docker build process is designed to bake the version directly into the image, ensuring traceability and consistency with the unified version system.
Build Process¶
The Containerfile uses build arguments to create a VERSION file inside the image:
ARG VERSION=""
ARG GIT_SHA=""
ARG BUILD_DATE=""
RUN set -eux; \
if [ -n "$VERSION" ]; then \
echo "Using provided version: $VERSION"; \
echo "$VERSION" > /app/VERSION; \
else \
echo "No version provided, using fallback"; \
echo "dev" > /app/VERSION; \
fi; \
echo "Building version: $(cat /app/VERSION)"
Building Versioned Images¶
To build a versioned image, pass the VERSION argument:
# Recommended command to build a production image
docker build \
--build-arg VERSION=$(git describe --tags --always) \
--target production \
-t your-registry/tux:latest .
You can also tag the image with the specific version:
# Tag with the specific version for better tracking
VERSION_TAG=$(git describe --tags --always)
docker build \
--build-arg VERSION=$VERSION_TAG \
--target production \
-t your-registry/tux:$VERSION_TAG \
-t your-registry/tux:latest .
Note: The version system automatically handles the v prefix from git tags (e.g., v1.2.3 becomes 1.2.3) to ensure clean, semver-compatible version strings.
GitHub Actions Integration¶
Our GitHub Actions workflows automatically handle version generation:
- PR Builds: Generate versions like
pr-123-abc1234 - Release Builds: Use the git tag version (e.g.,
1.2.3) - Docker Builds: Pass the generated version as build arguments
This ensures that even in a detached production environment without Git, the application reports the correct version it was built from.
Testing the Version System¶
The version system includes comprehensive tests (tests/unit/test_version_system.py) that cover:
- Version detection from all sources
- Priority order validation
- Edge cases and error handling
- Semantic version validation
- Build information generation
- Integration with other components
Run the tests with:
uv run pytest tests/unit/test_version_system.py -v
Troubleshooting¶
Common Issues¶
- Version shows as "dev":
- Check if you're in a git repository
- Verify the VERSION file exists and contains a valid version
-
Ensure TUX_VERSION environment variable is not set to an empty value
-
Git describe fails:
- Ensure you have at least one git tag
- Check git repository integrity
-
Verify git is available in the environment
-
Docker version mismatch:
- Ensure VERSION build arg is passed correctly
- Check that the VERSION file is created in the container
- Verify the Containerfile version generation logic
Debugging¶
You can debug version detection by checking the version system directly:
from tux.shared.version import VersionManager
manager = VersionManager()
print(f"Detected version: {manager.get_version()}")
print(f"Build info: {manager.get_build_info()}")
print(f"Is semantic version: {manager.is_semantic_version()}")
This unified version system ensures consistent, reliable versioning across all environments while maintaining the flexibility needed for different deployment scenarios.