diff --git a/versioning.py b/versioning.py index 9c40e02..3c47f37 100644 --- a/versioning.py +++ b/versioning.py @@ -1,5 +1,3 @@ -# versioning.py - import re import subprocess from pathlib import Path @@ -12,13 +10,11 @@ CHANGELOG_FILE = Path("CHANGELOG.md") VERSION_FILE = Path("__version__.py") VERSION_PATTERN = r"## \[v?(\d+\.\d+\.\d+)\]" - def get_latest_version(): content = CHANGELOG_FILE.read_text(encoding="utf-8") matches = re.findall(VERSION_PATTERN, content) return matches[0] if matches else "0.0.0" - def bump_version(version: str, level: str = "patch") -> str: major, minor, patch = map(int, version.split(".")) if level == "major": @@ -27,132 +23,40 @@ def bump_version(version: str, level: str = "patch") -> str: return f"{major}.{minor + 1}.0" return f"{major}.{minor}.{patch + 1}" - def write_version_file(version: str): VERSION_FILE.write_text(f"VERSION = \"{version}\"\n", encoding="utf-8") - typer.echo(f"🔢 __version__.py aktualisiert auf {version}") - -def prepend_changelog(version: str): - today = datetime.today().strftime("%Y-%m-%d") - new_entry = f"\n\n## [v{version}] – {today}\n\n### 💡 Neue Funktionen\n- \n\n### 🔧 Änderungen & Fixes\n- \n\n### 📦 Internes\n- " - original = CHANGELOG_FILE.read_text(encoding="utf-8") - CHANGELOG_FILE.write_text(new_entry + original, encoding="utf-8") - typer.echo(f"📝 Neuer Eintrag für v{version} zu CHANGELOG.md hinzugefügt") - - -def validate_changelog(version: str) -> bool: +def update_changelog(version: str): + date = datetime.now().strftime("%Y-%m-%d") + new_entry = f"## [{version}] - {date}\n\n- Beschreibung...\n\n" content = CHANGELOG_FILE.read_text(encoding="utf-8") - pattern = rf"## \[v?{re.escape(version)}\](.*?)^## \[" - match = re.search(pattern, content + "\n## [", re.DOTALL | re.MULTILINE) - if match: - section = match.group(1).strip() - if any(line.strip() != "-" for line in section.splitlines() if line.strip()): - return True - typer.echo("⚠️ CHANGELOG-Eintrag ist noch leer oder unvollständig.") - return False + CHANGELOG_FILE.write_text(new_entry + content, encoding="utf-8") - -def tag_exists(tag: str) -> bool: - result = subprocess.run(["git", "tag"], capture_output=True, text=True) - return tag in result.stdout.splitlines() - - -def ensure_branch(expected_branch="main"): - result = subprocess.run(["git", "rev-parse", "--abbrev-ref", "HEAD"], capture_output=True, text=True) - branch = result.stdout.strip() - if branch != expected_branch: - typer.echo(f"⛔ Du befindest dich auf Branch '{branch}', erwartet wird '{expected_branch}'") - raise typer.Exit(code=1) - - -def extract_changelog_entry(version: str) -> str: - content = CHANGELOG_FILE.read_text(encoding="utf-8") - pattern = rf"## \[v?{re.escape(version)}\](.*?)^## \[" - match = re.search(pattern, content + "\n## [", re.DOTALL | re.MULTILINE) - return match.group(1).strip() if match else "" - - -def create_git_tag(version: str): - try: - if tag_exists(f"v{version}"): - typer.echo(f"⚠️ Tag v{version} existiert bereits.") - return - - subprocess.run(["git", "add", "."], check=True) - subprocess.run(["git", "commit", "-m", f"🔖 Release v{version}"], check=True) - subprocess.run(["git", "tag", f"v{version}"], check=True) - typer.echo(f"🏷️ Git-Tag 'v{version}' erstellt und commit durchgeführt.") - except subprocess.CalledProcessError: - typer.echo("⚠️ Git-Fehler beim Taggen oder Committen. Bitte manuell prüfen.") - - -def push_to_github(): - try: - subprocess.run(["git", "push"], check=True) - subprocess.run(["git", "push", "--tags"], check=True) - typer.echo("🚀 Änderungen und Tags an GitHub gepusht.") - except subprocess.CalledProcessError: - typer.echo("⚠️ Fehler beim Pushen zu GitHub. Bitte Zugang oder Netzwerk prüfen.") - - -@app.command() -def list(): - "Listet alle verfügbaren Versionen aus dem CHANGELOG" - typer.echo("\n📚 Verfügbare Versionen im CHANGELOG:") - content = CHANGELOG_FILE.read_text(encoding="utf-8") - versions = re.findall(VERSION_PATTERN, content) - for v in versions: - typer.echo(f"- v{v}") - - -@app.command() -def rollback(): - "Letzte Version zurückrollen (Tag löschen + Commit zurücknehmen)" - last_version = get_latest_version() - if typer.confirm(f"⚠️ Letzte Version 'v{last_version}' wirklich zurücknehmen?"): - try: - subprocess.run(["git", "tag", "-d", f"v{last_version}"], check=True) - subprocess.run(["git", "reset", "--hard", "HEAD~1"], check=True) - typer.echo(f"🔙 Version 'v{last_version}' wurde zurückgerollt.") - except subprocess.CalledProcessError: - typer.echo("❌ Rollback fehlgeschlagen.") +def create_git_tag(version: str, signed: bool = True): + tag_args = ["git", "tag"] + if signed: + tag_args.append("-s") # signierter Tag else: - typer.echo("⛔ Abgebrochen.") + tag_args.append("-a") # un-signierter, annotierter Tag + tag_args += [f"v{version}", "-m", f"Release v{version}"] + subprocess.run(tag_args, check=True) +def push_git_tag(version: str): + subprocess.run(["git", "push"], check=True) + subprocess.run(["git", "push", "origin", f"v{version}"], check=True) @app.command() -def create(level: str = typer.Option("patch", help="Versionstyp: patch, minor oder major"), - push: bool = typer.Option(False, help="Änderungen direkt an GitHub pushen")): - "Neue Version erstellen inkl. CHANGELOG, Git-Tag und optional Push" - ensure_branch() - - current_version = get_latest_version() - next_version = bump_version(current_version, level) - - typer.echo(f"💡 Aktuelle Version: {current_version}") - typer.echo(f"🚀 Neue Version: {next_version}") - - if typer.confirm("Version übernehmen und eintragen?"): - write_version_file(next_version) - prepend_changelog(next_version) - - typer.echo("\nBitte CHANGELOG.md bearbeiten und danach fortfahren.") - typer.prompt("Drücke Enter, sobald du den neuen Abschnitt ausgefüllt hast") - - if not validate_changelog(next_version): - typer.echo("❌ Release abgebrochen: Bitte fülle den CHANGELOG-Eintrag aus.") - raise typer.Exit(code=1) - - create_git_tag(next_version) - - if push: - push_to_github() - - typer.echo(f"✅ Version {next_version} erfolgreich erstellt.") - else: - typer.echo("❌ Abgebrochen.") - +def create(level: str = "patch", push: bool = False, unsigned: bool = False): + current = get_latest_version() + new_version = bump_version(current, level) + write_version_file(new_version) + update_changelog(new_version) + subprocess.run(["git", "add", "."], check=True) + subprocess.run(["git", "commit", "-m", f"Bump version to v{new_version}"], check=True) + create_git_tag(new_version, signed=not unsigned) + if push: + push_git_tag(new_version) + typer.echo(f"✅ Version {new_version} erstellt und getaggt{' (unsigned)' if unsigned else ' (signed)'}.") if __name__ == "__main__": app()