!/usr/bin/env python3
from __future__ import annotations
import argparse
import datetime
import os
import re
import subprocess
import sys
import tempfile
from dataclasses import dataclass
from haloreader import __version__, version
EDITOR = os.environ.get("EDITOR", "vi")
CHANGELOG_FNAME = "CHANGELOG.md"
VERSION_FNAME = version.__file__
REPOSITORY_URL = "https://github.com/actris-cloudnet/halo-reader"
dataclass(init=False)
class Version:
major: int
minor: int
patch: int
def __init__(self, ver: str):
self.major, self.minor, self.patch = (int(x) for x in ver.split("."))
def major_update(self) -> Version:
self.major = self.major + 1
self.minor = 0
self.patch = 0
return self
def minor_update(self) -> Version:
self.minor = self.minor + 1
self.patch = 0
return self
def patch_update(self) -> Version:
self.patch = self.patch + 1
return self
def update(self, update_type: str) -> Version:
match update_type:
case "major":
return self.major_update()
case "minor":
return self.minor_update()
case "patch":
return self.patch_update()
def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.patch}"
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument("update_type", type=str, choices=("major", "minor", "patch"))
return parser.parse_args()
def get_changelog_subsections() -> str:
return "\n\n".join(
[f" {t}" for t in ("Added", "Changed", "Deprecated", "Removed", "Fixed")]
)
def get_new_changelog(ver: Version, fname: str) -> str:
with open(fname, "r", encoding="utf-8") as f:
changelog = f.read()
date = datetime.date.today()
subsects = get_changelog_subsections()
changelog = changelog.replace(
" [Unreleased]", f" [Unreleased]\n\n{subsects}\n\n [{ver}] - {date}"
).strip()
changelog += f"\n[{ver}]: {REPOSITORY_URL}/releases/tag/v{ver}"
with tempfile.NamedTemporaryFile(suffix=".md") as temp:
temp.write(changelog.encode())
temp.flush()
subprocess.run([EDITOR, temp.name], check=True)
with open(temp.name, encoding="utf-8") as temp_f:
new_changelog = temp_f.read()
return new_changelog
def update_changelog(new_changelog: str, fname: str) -> None:
with open(fname, "w", encoding="utf-8") as f:
f.write(new_changelog)
def update_version_file(v: Version, fname: str):
with open(fname, "r", encoding="utf-8") as f:
content = f.read()
new_content = re.sub(
r'^(__version__ *= *)"\d\.\d\.\d"$', f'__version__ = "{v}"', content
)
with open(fname, "w", encoding="utf-8") as f:
f.write(new_content)
def main():
branch = (
subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
.decode()
.strip()
)
if branch != "main":
sys.exit(1)
args = get_args()
ver = Version(__version__)
ver.update(args.update_type)
new_changelog_str = get_new_changelog(ver, CHANGELOG_FNAME)
print("*" * 10 + f" {CHANGELOG_FNAME} " + "*" * 10)
print(new_changelog_str)
print("*" * 35)
if input(f"Release: {ver}? [y/N] ").lower() in ["y"]:
update_changelog(new_changelog_str, CHANGELOG_FNAME)
update_version_file(ver, VERSION_FNAME)
subprocess.run(
[
"pre-commit",
"run",
"--files",
CHANGELOG_FNAME,
VERSION_FNAME,
">/dev/null",
"2>&1",
],
check=False,
)
subprocess.run(["git", "add", CHANGELOG_FNAME, VERSION_FNAME], check=True)
subprocess.run(["pre-commit", "run", "--all"], check=True)
subprocess.run(["git", "commit", "-m", f"Release version {ver}"], check=True)
subprocess.run(["git", "push"], check=True)
subprocess.run(
["git", "tag", "-a", f"v{ver}", "-m", f"Release version {ver}"], check=True
)
subprocess.run(["git", "push", "--tags"], check=True)
if __name__ == "__main__":
main()