Semantic Versioning Guide¶
This project follows Semantic Versioning 2.0.0.
Automated Versioning (Primary Method)¶
The project uses automated PR-based versioning where every merged pull request automatically increments the version and publishes to PyPI. See AUTOMATED_VERSIONING.md for the complete guide.
Quick summary:
- PR labels, title, or branch prefix determine version bump type
- Major (breaking changes): major, breaking labels or feat!: title
- Minor (new features): minor, feature labels or feat: title
- Patch (bug fixes): patch, fix labels or fix: title (default)
Manual Release Process (Alternative)¶
If you need to release manually without the automated system:
Version Format¶
- MAJOR: Breaking API changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
- PRERELEASE: alpha, beta, rc (optional)
- BUILD: Build metadata (optional)
Release Process¶
Automated Release (Primary Method)¶
The project uses automated PR-based versioning. When a PR is merged to main:
- Auto-Version Workflow Triggers
auto-version-release.ymlautomatically runs-
Determines version bump from PR labels, title, or branch prefix
-
Version Bump PR Created
- The workflow creates a PR with version updates
- Updates
pyproject.tomlandCHANGELOG.md -
Auto-merge is enabled
-
Automatic Tag Creation
-
When the version bump PR merges, a git tag is created (e.g.,
v1.2.3) -
CI/CD Pipeline Runs Automatically
- Build Python package
- Publish to PyPI
- Build container images
- Generate SBOM
- Create GitHub Release with artifacts
See AUTOMATED_VERSIONING.md for complete details.
Manual Release Process¶
If you need to release manually:
1. Update Version¶
Edit pyproject.toml:
2. Update Changelog¶
Edit CHANGELOG.md following Keep a Changelog:
## [1.2.3] - 2024-01-15
### Added
- New feature descriptions
### Changed
- Modified behavior descriptions
### Fixed
- Bug fix descriptions
### Security
- Security fix descriptions
3. Commit Changes¶
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 1.2.3"
git push origin main
4. Create Release Tag (Manual Process Only)¶
Note: This step is automated when using the Automated Release workflow.
# Create annotated tag
git tag -a v1.2.3 -m "Release version 1.2.3"
# Push tag to trigger release
git push origin v1.2.3
5. Automated CI/CD Pipeline¶
The CI/CD pipeline will automatically:
- Validate version - Verifies tag matches
pyproject.toml - Run tests - Ensures all tests pass
- Build package - Creates wheel and source distribution
- Publish to PyPI - Uploads package automatically
- Build containers - Creates multi-platform images with semantic version tags:
ghcr.io/owner/repo:1.2.3(exact version)ghcr.io/owner/repo:1.2(minor version)ghcr.io/owner/repo:1(major version)ghcr.io/owner/repo:latest(if not a prerelease)- Create GitHub Release - Publishes release with artifacts
Version Increment Guidelines¶
MAJOR Version (X.0.0)¶
Increment when making breaking changes:
- Removing endpoints or parameters
- Changing response formats
- Renaming models or fields
- Changing error codes
- Removing deprecated features
- Changing authentication methods
Example:
# Before (v1.x.x)
@app.route('/weather/<city>')
def get_weather(city):
return {"city": city, "temp": 20}
# After (v2.0.0) - Breaking change: response format changed
@app.route('/weather/<city>')
def get_weather(city):
return {"location": {"name": city}, "current": {"temperature": 20}}
MINOR Version (0.X.0)¶
Increment when adding new features (backward compatible):
- Adding new endpoints
- Adding optional parameters
- Adding new response fields (without removing old ones)
- Adding new models
- Deprecating features (but not removing)
- Performance improvements
Example:
# v1.1.0 - Added new optional parameter
@app.route('/weather/<city>')
def get_weather(city, units='metric'): # New optional parameter
return {"city": city, "temp": 20, "units": units}
PATCH Version (0.0.X)¶
Increment when fixing bugs (backward compatible):
- Bug fixes
- Documentation fixes
- Internal refactoring
- Security patches
- Dependency updates (patch level)
Example:
# v1.0.1 - Bug fix
@app.route('/weather/<city>')
def get_weather(city):
city = city.strip() # Fix: handle whitespace in city names
return {"city": city, "temp": 20}
Prerelease Versions¶
Use prerelease identifiers for testing:
Alpha (Early Testing)¶
- Unstable, may have missing features
- For internal testing only
- Not recommended for production
Beta (Feature Complete)¶
- Feature complete but may have bugs
- For wider testing
- Not recommended for production
Release Candidate (Final Testing)¶
- Nearly production-ready
- Only critical bug fixes
- Ready for production testing
Container Image Tags¶
The Docker workflow automatically creates multiple tags:
| Tag Pattern | Example | Purpose |
|---|---|---|
X.Y.Z |
1.2.3 |
Exact version (immutable) |
X.Y |
1.2 |
Latest patch in minor version |
X |
1 |
Latest minor in major version |
latest |
latest |
Latest stable release |
X.Y.Z-alpha.N |
1.2.0-alpha.1 |
Alpha prerelease |
X.Y.Z-beta.N |
1.2.0-beta.1 |
Beta prerelease |
X.Y.Z-rc.N |
1.2.0-rc.1 |
Release candidate |
Usage Examples¶
# Pin to exact version (recommended for production)
docker pull ghcr.io/owner/msn-weather-wrapper:1.2.3
# Use latest patch version (auto-updates with patches)
docker pull ghcr.io/owner/msn-weather-wrapper:1.2
# Use latest minor version (auto-updates with new features)
docker pull ghcr.io/owner/msn-weather-wrapper:1
# Use latest stable (not recommended for production)
docker pull ghcr.io/owner/msn-weather-wrapper:latest
# Test prerelease
docker pull ghcr.io/owner/msn-weather-wrapper:1.2.0-rc.1
PyPI Publishing¶
Packages are automatically published to PyPI on tagged releases.
Required Secret¶
Configure the PYPI_TOKEN secret in your repository:
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
PYPI_TOKEN - Value: Your PyPI API token
- Click Add secret
Getting a PyPI Token¶
- Go to PyPI Account Settings
- Scroll to API tokens
- Click Add API token
- Name:
msn-weather-wrapper-github-actions - Scope: Project: msn-weather-wrapper (after first manual upload) or Entire account
- Click Add token
- Copy the token (starts with
pypi-)
First Release Setup¶
For the first release, you need to manually upload a package to claim the project name:
# Build package
python -m build
# Upload to PyPI (you'll be prompted for credentials)
python -m twine upload dist/*
After the first manual upload, all subsequent releases will be automated.
Version Validation¶
The CI/CD pipeline validates:
- Tag format - Must match
vX.Y.ZorvX.Y.Z-prerelease.N - Version consistency - Tag must match
pyproject.tomlversion - Semantic versioning - Follows semver rules
- Unique version - Version doesn't exist on PyPI
If validation fails, the release is aborted with a clear error message.
Troubleshooting¶
Version Mismatch Error¶
Error: Version mismatch!
Git tag: v1.2.3
pyproject.toml: 1.2.2
Please update pyproject.toml version to match the tag
Solution: Update pyproject.toml to match the tag:
# Fix the version
vim pyproject.toml # Change version to 1.2.3
# Amend the commit
git add pyproject.toml
git commit --amend --no-edit
git push origin main --force
# Delete and recreate the tag
git tag -d v1.2.3
git push origin :refs/tags/v1.2.3
git tag -a v1.2.3 -m "Release version 1.2.3"
git push origin v1.2.3
PyPI Upload Fails¶
Check:
- Is
PYPI_TOKENconfigured correctly? - Does the version already exist on PyPI?
- Is the package name available?
Test locally:
# Build package
python -m build
# Check package validity
python -m twine check dist/*
# Upload to TestPyPI first
python -m twine upload --repository testpypi dist/*
Container Build Fails¶
Check:
- Does the Containerfile exist?
- Are there syntax errors in the Containerfile?
- Check the Docker workflow logs for details
Best Practices¶
- Never reuse versions - Once published, a version is immutable
- Test prereleases - Use alpha/beta/rc for testing
- Update changelog - Document all changes before releasing
- Pin dependencies - Use exact versions in production
- Automate everything - Let CI/CD handle releases
- Validate locally - Test builds before pushing tags
- Communicate changes - Write clear release notes
Examples¶
Patch Release (Bug Fix)¶
# 1. Fix the bug
vim src/msn_weather_wrapper/client.py
# 2. Update version
vim pyproject.toml # 1.0.0 → 1.0.1
# 3. Update changelog
vim CHANGELOG.md
# Add:
# ## [1.0.1] - 2024-01-15
# ### Fixed
# - Fixed city name whitespace handling
# 4. Commit and tag
git add .
git commit -m "fix: handle whitespace in city names"
git push origin main
git tag -a v1.0.1 -m "Release version 1.0.1"
git push origin v1.0.1
Minor Release (New Feature)¶
# 1. Implement feature
vim src/msn_weather_wrapper/client.py
# 2. Update version
vim pyproject.toml # 1.0.1 → 1.1.0
# 3. Update changelog
vim CHANGELOG.md
# Add:
# ## [1.1.0] - 2024-01-20
# ### Added
# - Added forecast endpoint with 7-day predictions
# 4. Commit and tag
git add .
git commit -m "feat: add 7-day weather forecast endpoint"
git push origin main
git tag -a v1.1.0 -m "Release version 1.1.0"
git push origin v1.1.0
Major Release (Breaking Change)¶
# 1. Implement breaking changes
vim src/msn_weather_wrapper/client.py
# 2. Update version
vim pyproject.toml # 1.1.0 → 2.0.0
# 3. Update changelog
vim CHANGELOG.md
# Add:
# ## [2.0.0] - 2024-02-01
# ### Changed
# - **BREAKING**: Changed response format for weather endpoints
# - **BREAKING**: Renamed `temp` field to `temperature`
# - See MIGRATION.md for upgrade guide
# 4. Create migration guide
vim docs/MIGRATION.md
# 5. Commit and tag
git add .
git commit -m "feat!: redesign API response format"
git push origin main
git tag -a v2.0.0 -m "Release version 2.0.0"
git push origin v2.0.0