68 lines
2.0 KiB
Python
68 lines
2.0 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import re
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
ROOT = Path(__file__).resolve().parents[1]
|
||
|
|
VERSION_FILE = ROOT / "VERSION"
|
||
|
|
CHANGELOG_FILE = ROOT / "CHANGELOG.md"
|
||
|
|
|
||
|
|
|
||
|
|
def parse_version(raw: str) -> tuple[int, int, int]:
|
||
|
|
match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)", raw.strip())
|
||
|
|
if not match:
|
||
|
|
raise ValueError(f"Invalid version: {raw!r}")
|
||
|
|
return tuple(int(part) for part in match.groups())
|
||
|
|
|
||
|
|
|
||
|
|
def format_version(parts: tuple[int, int, int]) -> str:
|
||
|
|
return ".".join(str(part) for part in parts)
|
||
|
|
|
||
|
|
|
||
|
|
def bump(parts: tuple[int, int, int], level: str) -> tuple[int, int, int]:
|
||
|
|
major, minor, patch = parts
|
||
|
|
if level == "patch":
|
||
|
|
return major, minor, patch + 1
|
||
|
|
if level == "minor":
|
||
|
|
return major, minor + 1, 0
|
||
|
|
if level == "major":
|
||
|
|
return major + 1, 0, 0
|
||
|
|
raise ValueError(f"Unsupported bump level: {level}")
|
||
|
|
|
||
|
|
|
||
|
|
def ensure_changelog_entry(version: str) -> None:
|
||
|
|
text = CHANGELOG_FILE.read_text(encoding="utf-8")
|
||
|
|
if re.search(rf"^## {re.escape(version)} - ", text, flags=re.MULTILINE):
|
||
|
|
return
|
||
|
|
heading = f"## {version} - TBD"
|
||
|
|
lines = text.splitlines()
|
||
|
|
if not lines:
|
||
|
|
updated = f"# Changelog\n\n{heading}\n\n- TBD\n"
|
||
|
|
else:
|
||
|
|
updated = "\n".join([lines[0], "", heading, "", "- TBD", "", *lines[1:]]) + "\n"
|
||
|
|
CHANGELOG_FILE.write_text(updated, encoding="utf-8")
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
if len(sys.argv) != 2:
|
||
|
|
raise SystemExit("Usage: python scripts/bump_version.py [patch|minor|major|X.Y.Z]")
|
||
|
|
|
||
|
|
current = parse_version(VERSION_FILE.read_text(encoding="utf-8"))
|
||
|
|
arg = sys.argv[1].strip()
|
||
|
|
|
||
|
|
if re.fullmatch(r"\d+\.\d+\.\d+", arg):
|
||
|
|
new_version = arg
|
||
|
|
else:
|
||
|
|
new_version = format_version(bump(current, arg))
|
||
|
|
|
||
|
|
VERSION_FILE.write_text(new_version + "\n", encoding="utf-8")
|
||
|
|
ensure_changelog_entry(new_version)
|
||
|
|
print(f"Bumped version: {format_version(current)} -> {new_version}")
|
||
|
|
print("Next step: python scripts/sync_version.py")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|