# Simplified Versioning System ## Problem Solved Previously, the application version had to be manually updated in **multiple places**: 1. `src/webdrop_bridge/__init__.py` - source of truth 2. `pyproject.toml` - package version 3. `.env.example` - environment example 4. Run `scripts/sync_version.py` - manual sync step This was error-prone and tedious. ## Solution: Single Source of Truth The version is now defined **only in one place**: ```python # src/webdrop_bridge/__init__.py __version__ = "1.0.0" ``` All other components automatically read from this single source. ## How It Works ### 1. **pyproject.toml** (Automatic) ```toml [tool.setuptools.dynamic] version = {attr = "webdrop_bridge.__version__"} [project] name = "webdrop-bridge" dynamic = ["version"] # Reads from __init__.py ``` When you build the package, setuptools automatically extracts the version from `__init__.py`. ### 2. **config.py** (Automatic - with ENV override) ```python # Lazy import to avoid circular imports if not os.getenv("APP_VERSION"): from webdrop_bridge import __version__ app_version = __version__ else: app_version = os.getenv("APP_VERSION") ``` The config automatically reads from `__init__.py`, but can be overridden with the `APP_VERSION` environment variable if needed. ### 3. **sync_version.py** (Simplified) The script now only handles: - Updating `__init__.py` with a new version - Updating `CHANGELOG.md` with a new version header - Optional: updating `.env.example` if it explicitly sets `APP_VERSION` It **no longer** needs to manually sync pyproject.toml or config defaults. ## Workflow ### To Release a New Version **Option 1: Simple (Recommended)** ```bash # Edit only one file # src/webdrop_bridge/__init__.py: __version__ = "1.1.0" # Change this # Then run sync script to update changelog python scripts/sync_version.py ``` **Option 2: Using the Sync Script** ```bash python scripts/sync_version.py --version 1.1.0 ``` The script will: - ✅ Update `__init__.py` - ✅ Update `CHANGELOG.md` - ✅ (Optional) Update `.env.example` if it has `APP_VERSION=` ### What Happens Automatically When you run your application: 1. Config loads and checks environment for `APP_VERSION` 2. If not set, it imports `__version__` from `__init__.py` 3. The version is displayed in the UI 4. Update checks use the correct version When you build with `pip install`: 1. setuptools reads `__version__` from `__init__.py` 2. Package metadata is set automatically 3. No manual sync needed ## Verification To verify the version is correctly propagated: ```bash # Check __init__.py python -c "from webdrop_bridge import __version__; print(__version__)" # Check config loading python -c "from webdrop_bridge.config import Config; c = Config.from_env(); print(c.app_version)" # Check package metadata (after building) pip show webdrop-bridge ``` All should show the same version. ## Best Practices 1. **Always edit `__init__.py` first** - it's the single source of truth 2. **Run `sync_version.py` to update changelog** - keeps release notes organized 3. **Use environment variables only for testing** - don't hardcode overrides 4. **Run tests after version changes** - config tests verify version loading ## Migration Notes If you had other places where version was defined: - ❌ Remove version from `pyproject.toml` `[project]` section - ✅ Add `dynamic = ["version"]` instead - ❌ Don't manually edit `.env.example` for version - ✅ Let `sync_version.py` handle it - ❌ Don't hardcode version in config.py defaults - ✅ Use lazy import from `__init__.py` ## Testing the System Run the config tests to verify everything works: ```bash pytest tests/unit/test_config.py -v ``` All tests should pass, confirming version loading works correctly. --- **Result**: One place to change, multiple places automatically updated. Simple, clean, professional.