Version Management in Caracal Core
Overview
Caracal Core uses a centralized version management system where the VERSION file at the root of the project serves as the single source of truth for all version references.
Architecture
Single Source of Truth
The VERSION file contains only the version number (e.g., 0.4.0) and is used by:
- Python Package (
pyproject.toml,setup.py) - Runtime Code (
caracal/_version.py,caracal/__init__.py) - Docker Images (via build scripts)
- Helm Charts (
helm/caracal/Chart.yaml) - Kubernetes Manifests (all
*.yamlfiles ink8s/)
How It Works
Python Package
pyproject.toml:
[project]
name = "caracal-core"
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {file = ["VERSION"]}
setup.py:
from pathlib import Path
from setuptools import setup
version_file = Path(__file__).parent / "VERSION"
version = version_file.read_text().strip()
setup(version=version)
caracal/_version.py:
from pathlib import Path
def get_version() -> str:
version_file = Path(__file__).parent.parent / "VERSION"
if version_file.exists():
return version_file.read_text().strip()
return "unknown"
__version__ = get_version()
caracal/init.py:
from caracal._version import __version__
__all__ = ["__version__"]
Docker Images
Docker images are built with version tags read from the VERSION file:
VERSION=$(cat VERSION | tr -d '[:space:]')
docker build -t caracal-gateway:v$VERSION -f Dockerfile.gateway .
Helm Charts
The update-version.sh script updates Helm Chart.yaml:
VERSION=$(cat VERSION | tr -d '[:space:]')
sed -i "s/^version: .*/version: $VERSION/" helm/caracal/Chart.yaml
sed -i "s/^appVersion: .*/appVersion: \"$VERSION\"/" helm/caracal/Chart.yaml
Kubernetes Manifests
All Kubernetes manifests use version labels that are updated by the script:
metadata:
labels:
app.kubernetes.io/version: "0.4.0" # Updated by script
Usage
Updating the Version
-
Edit VERSION file:
echo "0.4.0" > VERSION -
Update all references:
./scripts/update-version.sh -
Verify changes:
git diff -
Commit changes:
git add VERSION pyproject.toml helm/ k8s/
git commit -m "Bump version to 0.4.0"
Automated Release
Use the release script for a complete release process:
./scripts/release.sh
This will:
- Update all version references
- Create git tag (optional)
- Build Docker images (optional)
- Package Helm chart (optional)
- Publish to PyPI (optional)
Manual Release Steps
If you prefer manual control:
# 1. Update version
echo "0.4.0" > VERSION
# 2. Update references
./scripts/update-version.sh
# 3. Commit changes
git add VERSION pyproject.toml helm/ k8s/
git commit -m "Bump version to 0.4.0"
# 4. Create tag
git tag -a v0.4.0 -m "Release v0.4.0"
git push origin main
git push origin v0.4.0
# 5. Build Docker images
./scripts/build-images.sh
# 6. Package Helm chart
cd helm
helm package caracal
helm push caracal-0.4.0.tgz oci://registry.example.com/charts
# 7. Publish to PyPI
cd ..
python -m build
twine upload dist/*
Version Format
Caracal Core follows Semantic Versioning:
- MAJOR.MINOR.PATCH (e.g.,
0.4.0) - MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Version Prefixes
- Git tags: Use
vprefix (e.g.,v0.4.0) - Docker images: Use
vprefix (e.g.,caracal-gateway:v0.4.0) - Helm charts: No
vprefix (e.g.,version: 0.4.0) - Python package: No
vprefix (e.g.,version = "0.4.0") - Kubernetes labels: No
vprefix (e.g.,app.kubernetes.io/version: "0.4.0")
Files Updated by Scripts
update-version.sh
helm/caracal/Chart.yaml(version and appVersion)- All
k8s/**/*.yamlfiles (app.kubernetes.io/version labels)
build-images.sh
Builds Docker images with version tags:
caracal-gateway:v{VERSION}caracal-mcp-adapter:v{VERSION}caracal-consumer:v{VERSION}caracal-cli:v{VERSION}
release.sh
Orchestrates the entire release process by calling other scripts and performing git operations.
Accessing Version at Runtime
Python Code
import caracal
print(caracal.__version__) # e.g., "0.4.0"
CLI
caracal --version
Docker Container
docker run caracal-gateway:v0.4.0 caracal --version
Kubernetes
kubectl get deployment caracal-gateway -o jsonpath='{.metadata.labels.app\.kubernetes\.io/version}'
Best Practices
- Always update VERSION file first before running scripts
- Run update-version.sh after changing VERSION file
- Commit VERSION file changes with all updated references
- Use semantic versioning for version numbers
- Tag releases with
vprefix (e.g.,v0.4.0) - Test locally before pushing tags
- Document changes in RELEASE_NOTES.md
Troubleshooting
Version Mismatch
If you see version mismatches:
# Re-run update script
./scripts/update-version.sh
# Verify all files are updated
git diff
Python Package Version
If Python package shows wrong version:
# Rebuild package
python -m build
# Check version
python -c "import caracal; print(caracal.__version__)"
Docker Image Version
If Docker images have wrong tags:
# Rebuild images
./scripts/build-images.sh
# Verify tags
docker images | grep caracal
Migration from Hardcoded Versions
If you're migrating from hardcoded versions:
- Create VERSION file with current version
- Update pyproject.toml to use dynamic versioning
- Update setup.py to read from VERSION file
- Create _version.py module
- Update init.py to import from _version.py
- Run update-version.sh to update all references
- Test that version is correctly read everywhere