14 KiB
ADR-008: Versioning Strategy
Status
Accepted
Context
StarPunk is an IndieWeb CMS currently in active development, working toward its first production release. We need a comprehensive versioning strategy that:
- Communicates clearly what type of changes each release contains
- Works with Python ecosystem tools (pip, uv, PyPI compatibility)
- Aligns with IndieWeb values of simplicity and sustainability
- Supports the project lifecycle from development through maintenance
- Enables dependency management for users who may build on StarPunk
- Provides predictability for users about what to expect in updates
Current State
The project currently uses informal version terminology:
- "V1" for the overall first release goal
- "Phase 1.1", "Phase 1.2" for development milestones
- "v1.1", "v2.0" for future iteration references
This works for internal planning but lacks the precision needed for:
- Public releases
- Dependency management
- Communicating breaking changes
- Git tagging and release management
Requirements
- Version number format that indicates change severity
- Python ecosystem compliance (PEP 440)
- Git workflow integration (tagging, branching)
- Changelog format for human-readable history
- Pre-release versioning for alphas/betas if needed
- Upgrade communication strategy
- Simplicity appropriate for an indie project
Decision
We will adopt Semantic Versioning 2.0.0 (SemVer) with Python PEP 440 compliance for all StarPunk releases.
Version Number Format
Structure: MAJOR.MINOR.PATCH[-PRERELEASE]
Examples:
0.1.0- Development version (Phase 1.1 complete)0.2.0- Development version (Phase 1.2 complete)1.0.0- First stable release (all V1 features complete)1.0.1- Bug fix release1.1.0- Feature release (backward compatible)2.0.0- Major release (breaking changes)1.0.0a1- Alpha pre-release (PEP 440 format)1.0.0b2- Beta pre-release (PEP 440 format)1.0.0rc1- Release candidate (PEP 440 format)
Version Component Rules
MAJOR version - Increment when making incompatible changes:
- Breaking API changes
- Database schema changes requiring migration
- Configuration file format changes requiring user intervention
- Removal of deprecated features
- Major architectural changes
MINOR version - Increment when adding functionality in backward-compatible manner:
- New features
- New API endpoints
- Non-breaking enhancements
- Optional new configuration parameters
- Significant performance improvements
PATCH version - Increment for backward-compatible bug fixes:
- Bug fixes
- Security patches
- Documentation corrections
- Minor performance improvements
- Dependency updates (without feature changes)
Development Phase (0.x.y)
During development (pre-1.0), we use 0.MINOR.PATCH:
- MINOR increments for phase completions (Phase 1.1 → 0.1.0, Phase 1.2 → 0.2.0)
- PATCH increments for bug fixes during development
- Breaking changes are allowed without major version increment
- Public API is not considered stable
Git Tagging Convention
Format: vMAJOR.MINOR.PATCH[-PRERELEASE]
Examples:
v0.1.0- Development version tagv1.0.0- Stable release tagv1.0.1- Bug fix release tagv1.0.0-alpha.1- Alpha pre-release tag (Git format)
Tag type: Annotated tags (not lightweight)
- Contains tagger, date, message
- Can include release notes
- Can be GPG signed
Version Storage
Primary source of truth: starpunk/__init__.py
__version__ = "1.0.0"
__version_info__ = (1, 0, 0)
Secondary locations:
pyproject.toml- Package metadata (if used)- Git tags - Release markers
CHANGELOG.md- Human-readable history
Synchronization: Manual for V1 (simple, no automation dependencies)
Changelog Format
File: CHANGELOG.md
Format: Based on Keep a Changelog
Categories:
- Added - New features
- Changed - Changes to existing functionality
- Deprecated - Features that will be removed
- Removed - Features that have been removed
- Fixed - Bug fixes
- Security - Security vulnerability fixes
Example:
## [1.0.0] - 2024-11-18
### Added
- IndieAuth authentication via IndieLogin
- Micropub endpoint for publishing
- RSS feed generation
- File-based note storage
### Security
- Implemented path traversal protection
- Added CSRF protection for authentication flows
Pre-Release Versioning
Format: PEP 440 compliant
- Alpha:
1.0.0a1,1.0.0a2 - Beta:
1.0.0b1,1.0.0b2 - Release Candidate:
1.0.0rc1,1.0.0rc2
Git tags use hyphen: v1.0.0-alpha.1 (for readability)
Python __version__ uses PEP 440: 1.0.0a1 (for pip compatibility)
Phase-to-Version Mapping
Implementation phases (internal planning) map to version numbers (public releases):
Phase 1.1 complete → Version 0.1.0
Phase 1.2 complete → Version 0.2.0
Phase 1.3 complete → Version 0.3.0
Phase 2.1 complete → Version 0.4.0
All V1 complete → Version 1.0.0
V1.1 features → Version 1.1.0
V2 features → Version 2.0.0
Clarification:
- "V1" refers to feature scope, not version number
- Version 1.0.0 implements the "V1 feature set"
- Phases are development milestones, versions are public releases
Rationale
Why Semantic Versioning?
- Industry Standard: Used by Flask, Django, Requests, and most Python packages
- Clear Communication: Version number immediately conveys impact of changes
- Predictable: Users know what to expect from each version increment
- Dependency Management: Works seamlessly with pip version specifiers
- Simple: Easy to understand and apply without complex rules
Why Not Calendar Versioning (CalVer)?
CalVer (e.g., 2024.11.18) was considered but rejected:
Pros:
- Shows when software was released
- No ambiguity about version order
Cons:
- Doesn't communicate impact of changes (patch vs breaking change)
- Less common in Python ecosystem
- Doesn't help users assess upgrade risk
- Overkill for indie project release cadence
Conclusion: SemVer's semantic meaning is more valuable than date information
Why Not ZeroVer (0.x forever)?
Some projects stay at 0.x.y indefinitely to signal "still evolving". Rejected because:
- Creates uncertainty about production readiness
- Version 1.0.0 signals "ready for production use"
- We have a clear 1.0 feature scope (V1)
- Users deserve clarity about stability
Why PEP 440 Compliance?
PEP 440 is Python's version identification standard:
- Required for PyPI publication (if we ever publish)
- Compatible with pip, uv, and all Python package managers
- Slightly different pre-release format than SemVer (e.g.,
1.0.0a1vs1.0.0-alpha.1) - Used by all major Python frameworks
Decision: Use PEP 440 format in Python code, SemVer-style in Git tags (Git tags are more flexible)
Why Manual Version Management (V1)?
Considered automation tools:
bump2version- Automates version bumpingpython-semantic-release- Determines version from commit messagessetuptools_scm- Derives version from Git tags
Decision: Manual for V1 because:
- Simple - no extra dependencies
- Full control - explicit about versions
- Aligns with indie philosophy - minimal tooling
- Can add automation later if needed
Why Annotated Tags?
Annotated tags vs lightweight tags:
Annotated tags:
- Contain metadata (tagger, date, message)
- Can include release notes
- Can be GPG signed
- Treated as full objects in Git
Decision: Always use annotated tags for releases
Why CHANGELOG.md?
Changelog provides human-readable release history:
- Users can quickly see what changed
- Easier to read than Git commits
- Standard location (
CHANGELOG.md) - Standard format (Keep a Changelog)
- Can be generated from commits or written manually
Decision: Maintain manually for V1 (precise control over messaging)
Consequences
Positive
- Clear Communication: Users know exactly what each version means
- Ecosystem Compatibility: Works with all Python tools
- Predictable Upgrades: Users can assess risk before upgrading
- Professional Image: Signals mature, well-maintained software
- Dependency Management: Other projects can depend on StarPunk versions
- Git Integration: Clean tagging and release workflow
- Flexible: Can add automation later without changing format
- Standards-Based: Uses established, documented standards
Negative
- Manual Effort: Requires discipline to update version in multiple places
- Coordination: Must remember to update version, changelog, and tag
- Breaking Change Discipline: Must carefully evaluate what constitutes breaking change
- Learning Curve: Contributors need to understand SemVer rules
Neutral
- 0.x Signals Development: May discourage early adopters who want "1.0" stability
- Commitment to Backward Compatibility: Once at 1.0, breaking changes require major version
- Changelog Maintenance: Ongoing effort to document changes
Mitigations
For manual effort:
- Document clear release process in
versioning-strategy.md - Create release checklist
- Consider automation in V2+ if needed
For breaking change discipline:
- Deprecate features one version before removal when possible
- Document breaking changes prominently
- Provide upgrade guides for major versions
For 0.x concerns:
- Clearly communicate that 0.x is pre-production
- Move to 1.0.0 once V1 features are complete and tested
- Don't stay at 0.x longer than necessary
Implementation
Immediate Actions
- Set current version:
0.1.0(Phase 1.1 development) - Create
starpunk/__init__.py:__version__ = "0.1.0" __version_info__ = (0, 1, 0) - Create
CHANGELOG.mdwith[Unreleased]section - Update README.md with version information
- Tag current state:
git tag -a v0.1.0 -m "Development version 0.1.0"
Release Workflow
When ready to release:
- Update
starpunk/__init__.pywith new version - Update
CHANGELOG.mdwith release date - Commit:
git commit -m "Bump version to X.Y.Z" - Tag:
git tag -a vX.Y.Z -m "Release X.Y.Z: [description]" - Push:
git push origin main vX.Y.Z
Documentation
- Create comprehensive
docs/standards/versioning-strategy.md - Document examples, decision tree, and FAQ
- Include upgrade guide template
- Reference in README.md
Future Enhancements
V2+ Considerations:
- Add
bump2versionfor automation if manual process becomes tedious - Consider API versioning if need to support multiple incompatible API versions
- Add database schema versioning if migrations become complex
- Automated changelog generation from commit messages
Alternatives Considered
Alternative 1: Calendar Versioning (CalVer)
Format: YYYY.MM.PATCH (e.g., 2024.11.0)
Pros:
- Shows release date
- Clear chronological order
- Used by Ubuntu, PyCharm
Cons:
- Doesn't communicate change impact
- Less common in Python web frameworks
- Doesn't indicate breaking changes
- Overkill for indie project cadence
Rejected: Semantic meaning more important than date
Alternative 2: Simple Integer Versioning
Format: 1, 2, 3 (e.g., like TeX: 3.14159...)
Pros:
- Extremely simple
- No ambiguity
Cons:
- No information about change severity
- Doesn't work with Python dependency tools
- Not standard in Python ecosystem
- Too minimalist for practical use
Rejected: Too simplistic, poor ecosystem fit
Alternative 3: Modified SemVer (Django-style)
Format: MAJOR.FEATURE.PATCH (e.g., Django's 4.2.7)
Pros:
- Used by Django
- Separates features from bug fixes
Cons:
- Non-standard SemVer interpretation
- Confusing: when to increment feature vs major?
- Doesn't clearly indicate breaking changes
- Less predictable
Rejected: Standard SemVer is clearer
Alternative 4: ZeroVer (0.x forever)
Format: Stay at 0.x.y indefinitely
Pros:
- Signals "always evolving"
- No commitment to stability
Cons:
- Users can't tell when production-ready
- Doesn't signal stability improvements
- Version 1.0.0 has meaning: "ready to use"
Rejected: We have clear 1.0 goals, should signal when achieved
Alternative 5: Hybrid SemVer + CalVer
Format: YYYY.MINOR.PATCH (e.g., 2024.1.0)
Pros:
- Combines date and semantic information
Cons:
- Unusual, confusing
- Not standard
- Year increments don't mean anything semantically
Rejected: Combines worst of both approaches
References
Standards
- Semantic Versioning 2.0.0 - Official SemVer specification
- PEP 440 - Version Identification - Python version numbering standard
- Keep a Changelog - Changelog format standard
- Calendar Versioning - CalVer specification (considered but not adopted)
Examples from Python Ecosystem
- Flask Versioning - Uses SemVer
- Django Release Process - Modified SemVer
- Requests Versioning - Uses SemVer
- FastAPI Versioning - Uses SemVer
Tools
- bump2version - Version bump automation
- python-semantic-release - Automated semantic releases
- setuptools_scm - SCM-based versioning
Internal Documentation
- Versioning Strategy - Complete versioning specification
- Architecture Overview - System architecture
- Development Setup - Development workflow
ADR: 008 Date: 2024-11-18 Status: Accepted Decision: Adopt Semantic Versioning 2.0.0 with PEP 440 compliance Supersedes: None