#!/usr/bin/env python3 """Prepare an explicit release by updating application version metadata.""" import argparse from datetime import datetime from pathlib import Path import re from zoneinfo import ZoneInfo VERSION_FILE = Path(__file__).resolve().parents[1] / "core" / "version.py" def bump_version(part="patch", *, version_file=VERSION_FILE, release_date=None): """Increment a semantic version and update its date; return the new version.""" if part not in {"major", "minor", "patch"}: raise ValueError("Choose major, minor, or patch.") content = version_file.read_text(encoding="utf-8") match = re.search(r'^__version__ = "(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)"$', content, re.MULTILINE) if not match or not re.search(r'^__release_date__ = "\d{4}-\d{2}-\d{2}"$', content, re.MULTILINE): raise ValueError("Expected semantic version and release date in the version file.") major, minor, patch = map(int, match.groups()) if part == "major": major, minor, patch = major + 1, 0, 0 elif part == "minor": minor, patch = minor + 1, 0 else: patch += 1 version = f"{major}.{minor}.{patch}" date = release_date or datetime.now(ZoneInfo("Europe/Zurich")).date() content = content[:match.start()] + f'__version__ = "{version}"' + content[match.end():] content = re.sub(r'^__release_date__ = ".*"$', f'__release_date__ = "{date.isoformat()}"', content, flags=re.MULTILINE) version_file.write_text(content, encoding="utf-8") return version def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("part", choices=("major", "minor", "patch"), nargs="?", default="patch") args = parser.parse_args() print(f"Prepared version {bump_version(args.part)}") if __name__ == "__main__": main()