rss-news/versioning.py

135 lines
5.2 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
import subprocess
from pathlib import Path
from datetime import datetime
import typer
import os
CHANGELOG_FILE = Path("CHANGELOG.md")
VERSION_FILE = Path("__version__.py")
VERSION_PATTERN = r"## \[v?(\d+\.\d+\.\d+)\]"
def get_latest_version():
try:
# Zuerst versuchen, Git-Tag auszulesen
tag = subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"], stderr=subprocess.DEVNULL)
return tag.decode("utf-8").strip().lstrip("v")
except subprocess.CalledProcessError:
# Fallback auf CHANGELOG.md
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":
return f"{major + 1}.0.0"
elif level == "minor":
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")
def is_ssh_signing_available() -> bool:
return Path("~/.ssh/id_ed25519").expanduser().exists()
def is_gpg_available() -> bool:
try:
output = subprocess.check_output(["gpg", "--list-secret-keys"], stderr=subprocess.DEVNULL)
return bool(output.strip())
except Exception:
return False
def configure_signing(use_ssh: bool):
if use_ssh:
subprocess.run(["git", "config", "--global", "gpg.format", "ssh"], check=True)
subprocess.run(["git", "config", "--global", "user.signingkey", "~/.ssh/id_ed25519.pub"], check=True)
else:
subprocess.run(["git", "config", "--global", "gpg.format", "openpgp"], check=True)
subprocess.run(["git", "config", "--global", "commit.gpgsign", "true"], check=True)
def create(
level: str = "patch",
push: bool = False,
no_sign: bool = False,
dry_run: bool = False
):
"""
Erstellt eine neue Version mit optional signiertem Commit & Tag.
Optional: --push, --no-sign, --dry-run
"""
current = get_latest_version()
new_version = bump_version(current, level)
if dry_run:
typer.secho("🔍 Dry-Run aktiviert keine Dateien oder Git-Kommandos werden ausgeführt.\n", fg=typer.colors.YELLOW)
typer.echo(f"➡️ Aktuelle Version: {current}")
typer.echo(f"➡️ Neue Version: {new_version}")
typer.echo(f"➡️ Commit-Level: {level}")
typer.echo(f"➡️ Push nach GitHub: {'Ja' if push else 'Nein'}")
typer.echo(f"➡️ Signieren: {'Nein' if no_sign else 'Automatisch (SSH > GPG)'}")
date = datetime.now().strftime("%Y-%m-%d")
typer.echo("\n📄 Vorschlag für CHANGELOG-Eintrag:")
typer.echo(f"\n## [{new_version}] - {date}\n\n- Beschreibung...\n")
typer.secho("🚫 Dry-Run beendet.\n", fg=typer.colors.YELLOW)
return
# Update version file
write_version_file(new_version)
# Prepare or check changelog entry
date = datetime.now().strftime("%Y-%m-%d")
new_entry = f"## [{new_version}] - {date}\n\n- Beschreibung...\n\n"
content = CHANGELOG_FILE.read_text(encoding="utf-8")
if f"## [{new_version}]" in content:
typer.secho(f" Version {new_version} ist bereits im CHANGELOG.md vorhanden. Kein Eintrag hinzugefügt.", fg=typer.colors.BLUE)
else:
CHANGELOG_FILE.write_text(new_entry + content, encoding="utf-8")
typer.secho(f"📄 CHANGELOG.md wurde vorbereitet für Version {new_version}.", fg=typer.colors.MAGENTA)
typer.echo("")
typer.secho("✏️ Bitte jetzt den Eintrag in CHANGELOG.md überprüfen oder anpassen.", fg=typer.colors.CYAN)
input("⏸️ Drücke [Enter], um fortzufahren...")
subprocess.run(["git", "add", "."], check=True)
use_signing = False
signing_method = "none"
if not no_sign:
if is_ssh_signing_available():
configure_signing(use_ssh=True)
use_signing = True
signing_method = "ssh"
elif is_gpg_available():
configure_signing(use_ssh=False)
use_signing = True
signing_method = "gpg"
commit_cmd = ["git", "commit", "-m", f"Bump version to v{new_version}"]
if use_signing:
commit_cmd.append("-S")
subprocess.run(commit_cmd, check=True)
if use_signing:
subprocess.run(["git", "tag", "-s", f"v{new_version}", "-m", f"Release v{new_version}"], check=True)
else:
subprocess.run(["git", "tag", "-a", f"v{new_version}", "-m", f"Release v{new_version} (unsigned)"], check=True)
if push:
subprocess.run(["git", "push"], check=True)
subprocess.run(["git", "push", "origin", f"v{new_version}"], check=True)
if use_signing:
if signing_method == "ssh":
typer.secho(f"✅ Version {new_version} erstellt und signiert mit SSH 🔐", fg=typer.colors.GREEN)
elif signing_method == "gpg":
typer.secho(f"✅ Version {new_version} erstellt und signiert mit GPG 🔏", fg=typer.colors.CYAN)
else:
typer.secho(f"⚠️ Version {new_version} wurde ohne Signatur erstellt", fg=typer.colors.YELLOW)
if __name__ == "__main__":
typer.run(create)