diff --git a/help_scripts/manage_releases.py b/help_scripts/manage_releases.py new file mode 100644 index 0000000..55f8d18 --- /dev/null +++ b/help_scripts/manage_releases.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +manage_releases.py + +Automates synchronization of Git tags with GitHub releases. On each run it: + * Verifies the repository is clean and the current branch is fully pushed. + * Ensures HEAD is tagged by comparing the root version.nfo with existing + release tags and bumping/committing when required. + * Iterates over every tag in the repository, creating GitHub releases for any + missing entries and attaching per-directory ZIP archives (excluding + version.nfo files) that reflect the repository state for that tag. + +Dependencies: + - gh CLI (https://cli.github.com/) + - git available in PATH +""" + +from __future__ import annotations + +import argparse +import io +import os +import re +import shutil +import subprocess +import tarfile +import tempfile +import textwrap +from pathlib import Path +from typing import Dict, Iterable, List, Optional, Sequence, Tuple +from zipfile import ZIP_DEFLATED, ZipFile + + +def sh(args: Sequence[str], cwd: Path, check: bool = True) -> subprocess.CompletedProcess[str]: + """Run a subprocess and return the completed process.""" + result = subprocess.run( + list(args), + cwd=str(cwd), + text=True, + capture_output=True, + ) + if check and result.returncode != 0: + raise RuntimeError( + f"Command failed ({' '.join(args)}):\n" + f"{result.stdout}{result.stderr}" + ) + return result + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Synchronize Git tags with GitHub releases.") + parser.add_argument( + "--repo", + default=".", + help="Ścieżka do repozytorium git (domyślnie: bieżący katalog).", + ) + parser.add_argument( + "--remote", + default="origin", + help="Nazwa zdalnego repozytorium do pushowania commitów oraz tagów (domyślnie: origin).", + ) + parser.add_argument( + "--output-dir", + default="Release packs", + help="Katalog wyjściowy, w którym powstaną ZIP-y uploadowane do release (domyślnie: 'Release packs').", + ) + parser.add_argument( + "--notes-template", + default="Automated release for {tag}", + help="Szablon notatek release (dostępne pola: {tag}).", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Tylko plan – bez commitów, tagowania i publikacji release.", + ) + return parser.parse_args() + + +def read_text_if_exists(path: Path) -> Optional[str]: + if not path.is_file(): + return None + return path.read_text(encoding="utf-8").strip() + + +def parse_version(version: str) -> Optional[Tuple[int, ...]]: + if not version: + return None + if not re.fullmatch(r"\d+(?:\.\d+)*", version): + return None + return tuple(int(part) for part in version.split(".")) + + +def bump_version(version: str) -> str: + parts = parse_version(version) + if parts is None: + # fallback: append .1 to non-numeric strings + return f"{version}.1" + bumped = list(parts) + bumped[-1] += 1 + return ".".join(str(piece) for piece in bumped) + + +def sanitize_component(value: str) -> str: + value = value.strip() + if not value: + return "unknown" + return re.sub(r"[\\s/\\\\]+", "-", value) + + +class ReleaseManager: + def __init__(self, args: argparse.Namespace): + self.args = args + self.repo = Path(args.repo).resolve() + self.output_dir = (self.repo / args.output_dir).resolve() + + # ------------------------------------------------------------------ helpers + def git(self, *args: str, check: bool = True) -> subprocess.CompletedProcess[str]: + return sh(args, cwd=self.repo, check=check) + + def ensure_tooling(self) -> None: + sh(["gh", "--version"], cwd=self.repo, check=True) + + def ensure_repo(self) -> None: + if not (self.repo / ".git").exists(): + raise RuntimeError(f"{self.repo} nie jest repozytorium git.") + + def ensure_clean_state(self) -> None: + status = self.git("git", "status", "--porcelain", check=True).stdout.strip() + if status: + raise RuntimeError( + "Wykryto niezakomitowane zmiany. Ukończ commit lub stash przed publikacją release.\n" + "Release podpisany z nieczystego drzewa może wymagać resetu HEAD do taga." + ) + + upstream = self.git("git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}", check=False) + if upstream.returncode != 0: + raise RuntimeError( + "Brak skonfigurowanego upstreamu dla bieżącej gałęzi – nie można zweryfikować, " + "czy wszystkie commity zostały wypchnięte." + ) + ahead = self.git("git", "rev-list", "--count", "@{u}..HEAD", check=True).stdout.strip() + if ahead and int(ahead) > 0: + raise RuntimeError( + "Bieżąca gałąź zawiera niewypchnięte commity. Wypchnij zmiany zanim utworzysz release." + ) + + def get_head_tag(self) -> Optional[str]: + result = self.git("git", "describe", "--tags", "--exact-match", "HEAD", check=False) + tag = result.stdout.strip() + if result.returncode == 0 and tag: + return tag + return None + + def list_tags(self) -> List[str]: + tags = self.git("git", "tag", "--sort=creatordate", check=True).stdout.splitlines() + return [tag.strip() for tag in tags if tag.strip()] + + def list_version_tags(self) -> List[str]: + tags = [] + for tag in self.list_tags(): + if parse_version(tag): + tags.append(tag) + return tags + + def read_root_version(self) -> Optional[str]: + return read_text_if_exists(self.repo / "version.nfo") + + def write_root_version(self, version: str) -> None: + target = self.repo / "version.nfo" + target.write_text(f"{version}\n", encoding="utf-8") + + def commit_root_version(self, version: str) -> None: + if self.args.dry_run: + print(f"[DRY-RUN] git add version.nfo && git commit -m 'release: bump root to v{version}'") + return + self.write_root_version(version) + self.git("git", "add", "version.nfo", check=True) + self.git("git", "commit", "-m", f"release: bump root to v{version}", check=True) + self.git("git", "push", self.args.remote, check=True) + + def tag_exists(self, tag: str) -> bool: + result = self.git("git", "rev-parse", "-q", "--verify", f"refs/tags/{tag}", check=False) + return result.returncode == 0 + + def create_tag(self, tag: str, message: str) -> None: + if self.tag_exists(tag): + print(f"[INFO] Tag {tag} już istnieje – pomijam tworzenie.") + return + if self.args.dry_run: + print(f"[DRY-RUN] git tag -a {tag} -m \"{message}\"") + return + self.git("git", "tag", "-a", tag, "-m", message, check=True) + self.git("git", "push", self.args.remote, tag, check=True) + + def ensure_head_tagged(self) -> str: + head_tag = self.get_head_tag() + if head_tag: + return head_tag + + root_version = self.read_root_version() + root_tuple = parse_version(root_version) if root_version else None + + version_tags = self.list_version_tags() + latest_version = version_tags[-1] if version_tags else None + latest_tuple = parse_version(latest_version) if latest_version else None + + if root_version and (root_tuple and (latest_tuple is None or root_tuple > latest_tuple)): + new_version = root_version + else: + base_version = latest_version or root_version or "0.0" + new_version = bump_version(base_version) + if not self.args.dry_run: + print(f"[INFO] Bump root version.nfo -> {new_version}") + self.commit_root_version(new_version) + + tag_message = f"release {new_version}" + self.create_tag(new_version, tag_message) + return new_version + + def gather_directories_for_tag(self, tag: str) -> List[str]: + result = self.git("git", "ls-tree", "-d", "--name-only", tag, check=True) + candidates = [] + for line in result.stdout.splitlines(): + name = line.strip() + if not name: + continue + candidates.append(name) + return candidates + + def version_for_directory(self, tag: str, directory: str) -> str: + show = self.git("git", "show", f"{tag}:{directory}/version.nfo", check=False) + if show.returncode == 0: + version = show.stdout.strip() + if version: + return version + return tag + + def build_assets_for_tag(self, tag: str) -> List[Path]: + assets: List[Path] = [] + directories = self.gather_directories_for_tag(tag) + if not directories: + print(f"[WARN] Tag {tag} nie zawiera katalogów do zzipowania.") + return assets + + tag_output_dir = self.output_dir / sanitize_component(tag) + if not self.args.dry_run: + if tag_output_dir.exists(): + shutil.rmtree(tag_output_dir) + tag_output_dir.mkdir(parents=True, exist_ok=True) + + for directory in directories: + version = self.version_for_directory(tag, directory) + safe_version = sanitize_component(version) + safe_dir = sanitize_component(directory) + zip_name = f"{safe_dir}-v{safe_version}.zip" + zip_path = tag_output_dir / zip_name + + if self.args.dry_run: + print(f"[DRY-RUN] Przygotuj ZIP {zip_path} z taga {tag}:{directory} (pomijając version.nfo)") + assets.append(zip_path) + continue + + # Re-run capturing binary properly. + archive_proc = subprocess.run( + ["git", "archive", "--format=tar", tag, directory], + cwd=str(self.repo), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if archive_proc.returncode != 0: + raise RuntimeError( + f"git archive nie powiódł się dla {tag}:{directory}:\n" + f"{archive_proc.stderr.decode('utf-8', errors='ignore')}" + ) + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + with tarfile.open(fileobj=io.BytesIO(archive_proc.stdout)) as tar: + tar.extractall(tmp_path) + + extracted_root = tmp_path / directory + for extra in extracted_root.rglob("version.nfo"): + if extra.is_file(): + extra.unlink() + + with ZipFile(zip_path, "w", ZIP_DEFLATED) as zipf: + for root, _, files in os.walk(extracted_root): + for filename in files: + file_path = Path(root) / filename + rel_path = file_path.relative_to(tmp_path) + zipf.write(file_path, rel_path.as_posix()) + + assets.append(zip_path) + + return assets + + def release_exists(self, tag: str) -> bool: + result = self.git("gh", "release", "view", tag, check=False) + return result.returncode == 0 + + def create_release(self, tag: str, assets: List[Path]) -> None: + notes = self.args.notes_template.format(tag=tag) + wrapped = "\n".join(textwrap.wrap(notes, width=100)) + + if self.args.dry_run: + print(f"[DRY-RUN] gh release create {tag} {' '.join(str(a) for a in assets)}") + print(f"[DRY-RUN] Notatki:\n{wrapped}") + return + + cmd = ["gh", "release", "create", tag, "--title", tag, "--notes", wrapped] + cmd.extend(str(asset) for asset in assets) + result = self.git(*cmd, check=False) + if result.returncode != 0: + raise RuntimeError( + f"Nie udało się utworzyć release {tag}:\n{result.stdout}{result.stderr}" + ) + + def sync_releases(self) -> None: + tags = self.list_tags() + if not tags: + print("[INFO] Brak tagów do synchronizacji.") + return + + self.output_dir.mkdir(parents=True, exist_ok=True) + + for tag in tags: + if self.release_exists(tag): + print(f"[INFO] Release {tag} już istnieje – pomijam.") + continue + print(f"[INFO] Przygotowuję release dla taga {tag}...") + assets = self.build_assets_for_tag(tag) + self.create_release(tag, assets) + + def run(self) -> None: + self.ensure_repo() + self.ensure_tooling() + self.ensure_clean_state() + self.ensure_head_tagged() + self.sync_releases() + + +def main() -> int: + args = parse_args() + manager = ReleaseManager(args) + try: + manager.run() + except RuntimeError as exc: + print(f"[BŁĄD] {exc}") + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/help_scripts/sync_foundry_module.py b/help_scripts/sync_foundry_module.py index a5a999b..3dbb9cf 100644 --- a/help_scripts/sync_foundry_module.py +++ b/help_scripts/sync_foundry_module.py @@ -58,10 +58,6 @@ ZIP_MODE: str = "ALL" # "ALL" | "MODULE_ONLY" | "OFF" # Katalog wyjściowy na archiwa .zip; jeśli None, użyje SOURCE_BASE_DIR/_zips ZIP_OUTPUT_DIR: Optional[str] = r"C:\Release packs" CHECK_MODE: bool = False # tylko walidacja – brak zmian, wyjście !=0 jeśli są akcje -ENABLE_GH_RELEASE: bool = False # publikowanie release przez gh CLI -RELEASE_TAG_PREFIX: Optional[str] = None # prefiks taga release (np. "module/") -RELEASE_NOTES_TEMPLATE: str = "Automated release for {name} v{version}" -GIT_REMOTE_NAME: str = "origin" # ========================== # KONIEC KONFIGURACJI @@ -128,87 +124,6 @@ def git_changed_top_level_dirs(repo_dir: Path) -> List[str]: return sorted(changed) -def git_current_head(repo_dir: Path) -> str: - rc, out = sh(["git", "rev-parse", "HEAD"], repo_dir) - if rc != 0: - raise RuntimeError(f"Nie mogę ustalić HEAD w {norm(repo_dir)}:\n{out}") - return out.strip() - - -def git_tag_exists(repo_dir: Path, tag: str) -> bool: - rc, _ = sh(["git", "rev-parse", "-q", "--verify", f"refs/tags/{tag}"], repo_dir) - return rc == 0 - - -def create_git_tag(repo_dir: Path, tag: str, message: str, commit: Optional[str]) -> None: - if git_tag_exists(repo_dir, tag): - print(f"[INFO] Tag {tag} już istnieje – pomijam tworzenie.") - return - - cmd = ["git", "tag", "-a", tag] - if commit: - cmd.append(commit) - cmd += ["-m", message] - rc, out = sh(cmd, repo_dir) - if rc != 0: - raise RuntimeError(f"Nie udało się utworzyć taga {tag}:\n{out}") - if out.strip(): - print(out) - - -def push_git_tag(repo_dir: Path, tag: str) -> None: - remote = getattr(ARGS, "git_remote", GIT_REMOTE_NAME) - rc, out = sh(["git", "push", remote, tag], repo_dir) - if rc != 0: - raise RuntimeError(f"Nie udało się wypchnąć taga {tag}:\n{out}") - if out.strip(): - print(out) - - -def ensure_gh_available(repo_dir: Path) -> None: - rc, out = sh(["gh", "--version"], repo_dir) - if rc != 0: - raise RuntimeError("Polecenie 'gh' nie jest dostępne w PATH:\n" + out) - - -def github_release_exists(repo_dir: Path, tag: str) -> bool: - rc, _ = sh(["gh", "release", "view", tag], repo_dir) - return rc == 0 - - -def publish_github_release(repo_dir: Path, tag: str, title: str, notes: str, assets: List[Path]) -> None: - ensure_gh_available(repo_dir) - assets_str = [str(p) for p in assets] - - if github_release_exists(repo_dir, tag): - if not assets_str: - print(f"[INFO] Release {tag} już istnieje – brak nowych assetów do przesłania.") - return - cmd = ["gh", "release", "upload", tag, *assets_str, "--clobber"] - rc, out = sh(cmd, repo_dir) - if rc != 0: - raise RuntimeError(f"Nie udało się zaktualizować release {tag}:\n{out}") - if out.strip(): - print(out) - return - - cmd = ["gh", "release", "create", tag, *assets_str, "--title", title, "--notes", notes] - rc, out = sh(cmd, repo_dir) - if rc != 0: - raise RuntimeError(f"Nie udało się utworzyć release {tag}:\n{out}") - if out.strip(): - print(out) - - -def build_release_tag(name: str, version: str) -> str: - safe_name = name.replace(" ", "-").replace("/", "-") - base = f"{safe_name}-v{version}" - prefix = getattr(ARGS, "release_tag_prefix", RELEASE_TAG_PREFIX) - if prefix: - return f"{prefix}{base}" - return base - - def find_modules_dir_for_user(user: str, relative_pattern: str, appdata_kind: Optional[str]) -> Path: @@ -392,12 +307,12 @@ def write_json_atomic(path: Path, data: dict) -> None: tmp.replace(path) -def run_git_commands(repo_dir: Path, commit_msg: str, dry_run: bool) -> Optional[str]: +def run_git_commands(repo_dir: Path, commit_msg: str, dry_run: bool) -> None: if dry_run: print("[DRY-RUN] git add -A") print(f"[DRY-RUN] git commit -m {commit_msg!r}") print("[DRY-RUN] git push") - return None + return def run(cmd: List[str]) -> None: rc, out = sh(cmd, repo_dir) @@ -413,12 +328,10 @@ def run_git_commands(repo_dir: Path, commit_msg: str, dry_run: bool) -> Optional if out.strip(): print(out) run(["git", "push"]) - head = git_current_head(repo_dir) - return head -def preflight_module(src_dir: Path, dry_run: bool) -> Tuple[str, str, Optional[str]]: +def preflight_module(src_dir: Path, dry_run: bool) -> Tuple[str, str]: """ Moduł: odczyt module.json, bump, zapis (jeśli nie dry_run), commit i push. Zwraca (module_id, new_version, commit_sha lub None przy dry-run). @@ -435,20 +348,18 @@ def preflight_module(src_dir: Path, dry_run: bool) -> Tuple[str, str, Optional[s print(f"[PRE][MODULE] {src_dir.name}: id={module_id}, version={old_version} -> {new_version}") - commit_sha: Optional[str] = None - if dry_run: print("[DRY-RUN] Nie zapisuję module.json i nie wykonuję git.") else: manifest["version"] = new_version write_json_atomic(manifest_path, manifest) commit_msg = f"sync: {module_id} v{new_version}" - commit_sha = run_git_commands(src_dir, commit_msg, dry_run=False) + run_git_commands(src_dir, commit_msg, dry_run=False) - return module_id, new_version, commit_sha + return module_id, new_version -def preflight_non_module(src_dir: Path, dry_run: bool) -> Tuple[str, Optional[str]]: +def preflight_non_module(src_dir: Path, dry_run: bool) -> str: """ Niemoduł: version.nfo w formacie '0.x' (x int). - jeśli brak -> '0.1' @@ -457,7 +368,6 @@ def preflight_non_module(src_dir: Path, dry_run: bool) -> Tuple[str, Optional[st Zwraca (new_version, commit_sha lub None przy dry-run). """ nfo = src_dir / "version.nfo" - commit_sha: Optional[str] = None if not nfo.exists(): new_version = "0.1" print(f"[PRE][FOLDER] {src_dir.name}: version.nfo brak -> {new_version}") @@ -465,8 +375,8 @@ def preflight_non_module(src_dir: Path, dry_run: bool) -> Tuple[str, Optional[st with nfo.open("w", encoding="utf-8") as f: f.write(new_version + "\n") commit_msg = f"sync: {src_dir.name} v{new_version}" - commit_sha = run_git_commands(src_dir, commit_msg, dry_run=False) - return new_version, commit_sha + run_git_commands(src_dir, commit_msg, dry_run=False) + return new_version # istnieje -> wczytaj i bumpnij content = nfo.read_text(encoding="utf-8").strip() @@ -486,15 +396,13 @@ def preflight_non_module(src_dir: Path, dry_run: bool) -> Tuple[str, Optional[st with nfo.open("w", encoding="utf-8") as f: f.write(new_version + "\n") commit_msg = f"sync: {src_dir.name} v{new_version}" - commit_sha = run_git_commands(src_dir, commit_msg, dry_run=False) + run_git_commands(src_dir, commit_msg, dry_run=False) - return new_version, commit_sha + return new_version # ====== ROOT version.nfo (globalna wersja repo) ====== -def maybe_bump_root_version( - repo_dir: Path, changed_any: bool, dry_run: bool -) -> Optional[Tuple[str, Optional[str]]]: +def maybe_bump_root_version(repo_dir: Path, changed_any: bool, dry_run: bool) -> Optional[str]: """ Jeśli: - istnieją zmiany do przetworzenia (changed_any == True) @@ -530,26 +438,11 @@ def maybe_bump_root_version( if dry_run: print("[DRY-RUN][ROOT] Zapis version.nfo i commit/push zostaną pominięte.") - return new_version, None + return new_version nfo.write_text(new_version + "\n", encoding="utf-8") - commit_sha = run_git_commands(repo_dir, f"sync: root v{new_version}", dry_run=False) - return new_version, commit_sha - - -def maybe_publish_root_release(repo_dir: Path, version: str, commit_sha: Optional[str], dry_run: bool) -> None: - if not ARGS.gh_release or dry_run: - return - name = repo_dir.name or "root" - tag = build_release_tag(name, version) - title = f"{name} v{version}" - template = getattr(ARGS, "release_notes_template", RELEASE_NOTES_TEMPLATE) - notes = template.format(name=name, version=version, tag=tag) - if commit_sha is None: - commit_sha = git_current_head(repo_dir) - create_git_tag(repo_dir, tag, title, commit_sha) - push_git_tag(repo_dir, tag) - publish_github_release(repo_dir, tag, title, notes, []) + run_git_commands(repo_dir, f"sync: root v{new_version}", dry_run=False) + return new_version # ====== ZIP utilities ====== @@ -636,22 +529,6 @@ def parse_args() -> argparse.Namespace: help="Tylko sprawdzenie zmian (wymusza dry-run, kod wyjścia 1 przy wymaganych akcjach).") p.set_defaults(check=CHECK_MODE) - # GitHub Release options - release_group = p.add_mutually_exclusive_group() - release_group.add_argument("--gh-release", dest="gh_release", action="store_true", - help="Po zakończeniu commitów utwórz release na GitHubie (wymaga gh CLI).") - release_group.add_argument("--no-gh-release", dest="gh_release", action="store_false", - help="Wyłącz publikowanie release (domyślne).") - p.set_defaults(gh_release=ENABLE_GH_RELEASE) - p.add_argument("--release-tag-prefix", dest="release_tag_prefix", - default=RELEASE_TAG_PREFIX, - help="Opcjonalny prefiks dodawany przed tagiem release (np. 'module/').") - p.add_argument("--release-notes-template", dest="release_notes_template", - default=RELEASE_NOTES_TEMPLATE, - help="Szablon notatek release (format: name, version, tag).") - p.add_argument("--git-remote", dest="git_remote", - default=GIT_REMOTE_NAME, - help="Nazwa zdalnego repozytorium do wypychania tagów (domyślnie 'origin').") return p.parse_args() @@ -667,7 +544,7 @@ def resolve_modules_base(user: str, relative_pattern: str, appdata_kind: Optiona def process_module(src_dir: Path, modules_base: Path, confirm_delete: bool, dry_run: bool) -> None: - module_id, new_ver, commit_sha = preflight_module(src_dir, dry_run=dry_run) + module_id, new_ver = preflight_module(src_dir, dry_run=dry_run) target_dir = modules_base / src_dir.name print(f"[INFO][MODULE] Cel modułu: {norm(target_dir)}") @@ -700,21 +577,8 @@ def process_module(src_dir: Path, modules_base: Path, confirm_delete: bool, dry_ print(f"[DONE][MODULE] {src_dir.name} -> commit 'sync: {module_id} v{new_ver}' wykonany." if not dry_run else f"[DRY-RUN][MODULE] {src_dir.name} -> commit planowany.") - if ARGS.gh_release and not dry_run: - tag = build_release_tag(module_id, new_ver) - title = f"{module_id} v{new_ver}" - template = getattr(ARGS, "release_notes_template", RELEASE_NOTES_TEMPLATE) - notes = template.format(name=module_id, version=new_ver, tag=tag) - assets = [zip_path] if zip_path else [] - if commit_sha is None: - commit_sha = git_current_head(src_dir) - create_git_tag(src_dir, tag, title, commit_sha) - push_git_tag(src_dir, tag) - publish_github_release(src_dir, tag, title, notes, assets) - - def process_non_module(src_dir: Path, dry_run: bool) -> None: - new_ver, commit_sha = preflight_non_module(src_dir, dry_run=dry_run) + new_ver = preflight_non_module(src_dir, dry_run=dry_run) # ZIP po commicie (jeśli ustawienie pozwala) zip_path: Optional[Path] = None if should_zip(is_module=False, zip_mode=ARGS.zip_mode): @@ -726,20 +590,6 @@ def process_non_module(src_dir: Path, dry_run: bool) -> None: print(f"[DONE][FOLDER] {src_dir.name} -> version.nfo = {new_ver}; commit wykonany." if not dry_run else f"[DRY-RUN][FOLDER] {src_dir.name} -> version.nfo będzie {new_ver}; commit planowany.") - if ARGS.gh_release and not dry_run: - name = src_dir.name - tag = build_release_tag(name, new_ver) - title = f"{name} v{new_ver}" - template = getattr(ARGS, "release_notes_template", RELEASE_NOTES_TEMPLATE) - notes = template.format(name=name, version=new_ver, tag=tag) - assets = [zip_path] if zip_path else [] - if commit_sha is None: - commit_sha = git_current_head(src_dir) - create_git_tag(src_dir, tag, title, commit_sha) - push_git_tag(src_dir, tag) - publish_github_release(src_dir, tag, title, notes, assets) - - def main() -> int: global ARGS ARGS = parse_args() @@ -748,10 +598,6 @@ def main() -> int: if check_mode: ARGS.dry_run = True - ARGS.release_tag_prefix = (ARGS.release_tag_prefix or "").strip() or None - ARGS.release_notes_template = ARGS.release_notes_template or RELEASE_NOTES_TEMPLATE - ARGS.git_remote = ARGS.git_remote or GIT_REMOTE_NAME - mode = ARGS.mode user = ARGS.user appdata_kind = ARGS.appdata_kind if ARGS.appdata_kind != "None" else None @@ -777,11 +623,9 @@ def main() -> int: if not src_dir.is_dir(): raise FileNotFoundError(f"[SINGLE] Brak katalogu: {norm(src_dir)}") - root_info = maybe_bump_root_version(source_base, changed_any=True, dry_run=dry_run) - if root_info: + root_bumped = maybe_bump_root_version(source_base, changed_any=True, dry_run=dry_run) + if root_bumped: pending_actions = True - root_version, root_commit = root_info - maybe_publish_root_release(source_base, root_version, root_commit, dry_run) pending_actions = True @@ -802,11 +646,9 @@ def main() -> int: if changed: pending_actions = True - root_info = maybe_bump_root_version(source_base, changed_any=bool(changed), dry_run=dry_run) - if root_info: + root_bumped = maybe_bump_root_version(source_base, changed_any=bool(changed), dry_run=dry_run) + if root_bumped: pending_actions = True - root_version, root_commit = root_info - maybe_publish_root_release(source_base, root_version, root_commit, dry_run) if not changed: print("[INFO] Brak zmian do przetworzenia.") diff --git a/version.nfo b/version.nfo index be58634..bd73f47 100644 --- a/version.nfo +++ b/version.nfo @@ -1 +1 @@ -0.3 +0.4