152 lines
4.5 KiB
Python
152 lines
4.5 KiB
Python
"""Sync version from __init__.py to changelog.
|
||
|
||
This script reads the version from src/webdrop_bridge/__init__.py and
|
||
updates the CHANGELOG.md. Config and pyproject.toml automatically read
|
||
from __init__.py, so no manual sync needed for those files.
|
||
|
||
This script uses shared version utilities (build/scripts/version_utils.py)
|
||
to ensure consistent version reading across all build scripts.
|
||
|
||
Usage:
|
||
python scripts/sync_version.py [--version VERSION]
|
||
|
||
Examples:
|
||
python scripts/sync_version.py # Use version from __init__.py
|
||
python scripts/sync_version.py --version 2.0.0 # Override with new version
|
||
"""
|
||
|
||
import argparse
|
||
import re
|
||
import sys
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
|
||
# Import shared version utilities
|
||
sys.path.insert(0, str(Path(__file__).parent.parent / "build" / "scripts"))
|
||
from version_utils import get_current_version, get_project_root
|
||
|
||
PROJECT_ROOT = get_project_root()
|
||
|
||
|
||
def get_current_version_from_init() -> str:
|
||
"""Get version from __init__.py using shared utility.
|
||
|
||
Returns:
|
||
Current version string from __init__.py
|
||
|
||
Raises:
|
||
ValueError: If __version__ cannot be found
|
||
"""
|
||
return get_current_version()
|
||
|
||
|
||
def update_init_version(version: str) -> None:
|
||
"""Update version in __init__.py.
|
||
|
||
Args:
|
||
version: New version string to set
|
||
"""
|
||
init_file = PROJECT_ROOT / "src/webdrop_bridge/__init__.py"
|
||
content = init_file.read_text()
|
||
new_content = re.sub(
|
||
r'__version__\s*=\s*["\'][^"\']+["\']',
|
||
f'__version__ = "{version}"',
|
||
content,
|
||
)
|
||
init_file.write_text(new_content)
|
||
print(f"✓ Updated src/webdrop_bridge/__init__.py to {version}")
|
||
|
||
|
||
def update_env_example(version: str) -> None:
|
||
"""Update APP_VERSION in .env.example (optional).
|
||
|
||
Note: config.py now reads from __init__.py by default.
|
||
Only update if .env.example explicitly sets APP_VERSION for testing.
|
||
|
||
Args:
|
||
version: New version string to set
|
||
"""
|
||
env_file = PROJECT_ROOT / ".env.example"
|
||
if env_file.exists():
|
||
content = env_file.read_text()
|
||
# Only update if APP_VERSION is explicitly set
|
||
if 'APP_VERSION=' in content:
|
||
new_content = re.sub(
|
||
r'APP_VERSION=[^\n]+',
|
||
f'APP_VERSION={version}',
|
||
content,
|
||
)
|
||
env_file.write_text(new_content)
|
||
print(f"✓ Updated .env.example to {version}")
|
||
else:
|
||
print(
|
||
f"ℹ️ .env.example does not override APP_VERSION "
|
||
f"(uses __init__.py)"
|
||
)
|
||
|
||
|
||
def update_changelog(version: str) -> None:
|
||
"""Add version header to CHANGELOG.md if not present.
|
||
|
||
Args:
|
||
version: New version string to add
|
||
"""
|
||
changelog = PROJECT_ROOT / "CHANGELOG.md"
|
||
if changelog.exists():
|
||
content = changelog.read_text()
|
||
if f"## [{version}]" not in content and f"## {version}" not in content:
|
||
date_str = datetime.now().strftime("%Y-%m-%d")
|
||
header = (
|
||
f"## [{version}] - {date_str}\n\n"
|
||
"### Added\n\n### Changed\n\n### Fixed\n\n"
|
||
)
|
||
new_content = header + content
|
||
changelog.write_text(new_content)
|
||
print(f"✓ Added version header to CHANGELOG.md for {version}")
|
||
|
||
|
||
def main() -> int:
|
||
"""Sync version across project.
|
||
|
||
Updates __init__.py (source of truth) and changelog.
|
||
Config and pyproject.toml automatically read from __init__.py.
|
||
|
||
Returns:
|
||
0 on success, 1 on error
|
||
"""
|
||
parser = argparse.ArgumentParser(
|
||
description="Sync version from __init__.py to dependent files"
|
||
)
|
||
parser.add_argument(
|
||
"--version",
|
||
type=str,
|
||
help="Version to set (if not provided, reads from __init__.py)",
|
||
)
|
||
args = parser.parse_args()
|
||
|
||
try:
|
||
if args.version:
|
||
if not re.match(r"^\d+\.\d+\.\d+", args.version):
|
||
print(
|
||
"❌ Invalid version format. Use semantic versioning"
|
||
" (e.g., 1.2.3)"
|
||
)
|
||
return 1
|
||
version = args.version
|
||
update_init_version(version)
|
||
else:
|
||
version = get_current_version_from_init()
|
||
print(f"📍 Current version from __init__.py: {version}")
|
||
|
||
update_env_example(version)
|
||
update_changelog(version)
|
||
print(f"\n✅ Version sync complete: {version}")
|
||
return 0
|
||
|
||
except Exception as e:
|
||
print(f"❌ Error: {e}")
|
||
return 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|