diff --git a/.github/workflows/aur.yml b/.github/workflows/aur.yml index 832282b..f411ef2 100644 --- a/.github/workflows/aur.yml +++ b/.github/workflows/aur.yml @@ -1,9 +1,11 @@ name: Publish AUR on: - push: - branches: - - main + workflow_run: + workflows: + - Sync Version + types: + - completed workflow_dispatch: concurrency: @@ -12,6 +14,7 @@ concurrency: jobs: aur: + if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-latest env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" @@ -20,29 +23,14 @@ jobs: - name: Checkout uses: actions/checkout@v5 with: + ref: ${{ github.event_name == 'workflow_dispatch' && github.ref || github.event.workflow_run.head_branch }} fetch-depth: 0 - name: Determine version from app config id: version run: | - # Usando Python para extrair a versão de forma robusta - PKGVER=$(python3 -c " - import re - import os - - target = 'src/zashterminal/settings/config.py' - if not os.path.exists(target): - import sys; sys.exit(f'Erro: Arquivo {target} nao encontrado na raiz') - - with open(target, 'r', encoding='utf-8') as f: - content = f.read() - # Regex simplificada que aceita aspas simples ou duplas - match = re.search(r'APP_VERSION\\s*=\\s*[\\\"\\']([^\\\"\\']+)[\\\"\\']', content) - if match: - print(match.group(1)) - else: - import sys; sys.exit('Erro: Variavel APP_VERSION nao encontrada dentro do arquivo') - ") + python3 scripts/sync_version.py --check + PKGVER=$(python3 scripts/sync_version.py --print-current) echo "pkgver=$PKGVER" >> $GITHUB_OUTPUT - name: Update PKGBUILD pkgver diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml new file mode 100644 index 0000000..2714123 --- /dev/null +++ b/.github/workflows/version-bump.yml @@ -0,0 +1,64 @@ +name: Sync Version + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + bump: + description: "Semantic bump type" + required: false + default: "patch" + type: choice + options: + - patch + - minor + - major + version: + description: "Explicit version override (optional, e.g. 0.8.2)" + required: false + type: string + +permissions: + contents: write + +jobs: + sync-version: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.x" + + - name: Bump and sync version files + id: sync + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then + OUTPUT=$(python3 scripts/sync_version.py --set "${{ github.event.inputs.version }}") + elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + OUTPUT=$(python3 scripts/sync_version.py --bump "${{ github.event.inputs.bump || 'patch' }}") + else + OUTPUT=$(python3 scripts/sync_version.py --bump patch) + fi + printf '%s\n' "$OUTPUT" + NEW_VERSION=$(printf '%s\n' "$OUTPUT" | head -n 1) + echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT" + + - name: Commit changes + run: | + if git diff --quiet; then + echo "No version changes to commit." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add src/zashterminal/settings/config.py locale/src/zashterminal/settings/config.py pyproject.toml locale/pyproject.toml default.nix locale/default.nix PKGBUILD scripts/sync_version.py + git commit -m "Bump version to ${{ steps.sync.outputs.version }}" + git push diff --git a/.github/workflows/version-consistency.yml b/.github/workflows/version-consistency.yml new file mode 100644 index 0000000..fa6c528 --- /dev/null +++ b/.github/workflows/version-consistency.yml @@ -0,0 +1,25 @@ +name: Version Consistency + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +jobs: + check-version: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.x" + + - name: Verify version alignment + run: | + python3 scripts/sync_version.py --check diff --git a/PKGBUILD b/PKGBUILD index 90bdb2e..f118dad 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -3,7 +3,7 @@ pkgname=zashterminal # NOTE: CI updates this value automatically based on # locale/src/zashterminal/settings/config.py (APP_VERSION). -pkgver=0.0.0 +pkgver=0.8.1 pkgrel=1 pkgdesc="A modern GTK4/Adwaita terminal emulator with advanced session management, SSH integration, and security features." arch=('any') diff --git a/default.nix b/default.nix index 20f41a0..0bdf219 100644 --- a/default.nix +++ b/default.nix @@ -13,7 +13,7 @@ python3Packages.buildPythonApplication { pname = "zashterminal"; - version = "0.1.0"; + version = "0.8.1"; src = ./.; diff --git a/locale/default.nix b/locale/default.nix index d61d2ad..a14ab94 100644 --- a/locale/default.nix +++ b/locale/default.nix @@ -13,7 +13,7 @@ python3Packages.buildPythonApplication { pname = "zashterminal"; - version = "0.1.0"; + version = "0.8.1"; src = ./.; diff --git a/locale/pyproject.toml b/locale/pyproject.toml index aa54ed4..7a613c5 100644 --- a/locale/pyproject.toml +++ b/locale/pyproject.toml @@ -6,7 +6,7 @@ classifiers = [ "Programming Language :: Python :: 3", "Topic :: Terminals :: Terminal Emulators/X Terminals", ] -version = "0.1.0" +version = "0.8.1" authors = [ { name = "Leonardo Berbert", email = "leo4berbert@gmail.com" }, ] diff --git a/locale/src/zashterminal/settings/config.py b/locale/src/zashterminal/settings/config.py index 930dcde..ad5dcd7 100644 --- a/locale/src/zashterminal/settings/config.py +++ b/locale/src/zashterminal/settings/config.py @@ -32,7 +32,7 @@ class AppConstants: APP_ID = "org.leoberbert.zashterminal" APP_TITLE = "Zashterminal" - APP_VERSION = "0.8.0" + APP_VERSION = "0.8.1" DEVELOPER_NAME = "Leonardo Berbert" DEVELOPER_TEAM = ["Leonardo Berbert"] COPYRIGHT = "© 2025 Leonardo Berbert" diff --git a/pyproject.toml b/pyproject.toml index 0057402..a6b7e51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ classifiers = [ "Programming Language :: Python :: 3", "Topic :: Terminals :: Terminal Emulators/X Terminals", ] -version = "0.1.0" +version = "0.8.1" authors = [ { name = "Leonardo Berbert", email = "leo4berbert@gmail.com" }, ] diff --git a/scripts/sync_version.py b/scripts/sync_version.py new file mode 100644 index 0000000..e38b386 --- /dev/null +++ b/scripts/sync_version.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + +TARGETS = ( + ( + "src/zashterminal/settings/config.py", + r'(APP_VERSION\s*=\s*")([^"]+)(")', + "group3", + ), + ( + "locale/src/zashterminal/settings/config.py", + r'(APP_VERSION\s*=\s*")([^"]+)(")', + "group3", + ), + ("pyproject.toml", r'^(version\s*=\s*")([^"]+)(")\s*$', "group3"), + ("locale/pyproject.toml", r'^(version\s*=\s*")([^"]+)(")\s*$', "group3"), + ("default.nix", r'^( version\s*=\s*")([^"]+)(";\s*)$', "group3"), + ("locale/default.nix", r'^( version\s*=\s*")([^"]+)(";\s*)$', "group3"), + ("PKGBUILD", r"^(pkgver=)([^\n]+)$", "group2"), +) + + +def read_current_version() -> str: + config_path = ROOT / "src/zashterminal/settings/config.py" + content = config_path.read_text(encoding="utf-8") + match = re.search(r'APP_VERSION\s*=\s*"([^"]+)"', content) + if not match: + raise SystemExit(f"Unable to find APP_VERSION in {config_path}") + return match.group(1) + + +def bump_version(version: str, part: str) -> str: + match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)", version.strip()) + if not match: + raise SystemExit( + f"Current version '{version}' is not semver-like (expected X.Y.Z)" + ) + + major, minor, patch = (int(piece) for piece in match.groups()) + if part == "major": + return f"{major + 1}.0.0" + if part == "minor": + return f"{major}.{minor + 1}.0" + if part == "patch": + return f"{major}.{minor}.{patch + 1}" + raise SystemExit(f"Unsupported bump type: {part}") + + +def _replace_match(match: re.Match[str], new_version: str, mode: str) -> str: + if mode == "group2": + return f"{match.group(1)}{new_version}" + return f"{match.group(1)}{new_version}{match.group(3)}" + + +def replace_once(path: Path, pattern: str, new_version: str, mode: str) -> bool: + text = path.read_text(encoding="utf-8") + compiled = re.compile(pattern, re.MULTILINE) + updated, count = compiled.subn( + lambda match: _replace_match(match, new_version, mode), text, count=1 + ) + if count != 1: + raise SystemExit(f"Unable to update version in {path}") + + if updated != text: + path.write_text(updated, encoding="utf-8") + return True + return False + + +def sync_all(new_version: str) -> list[str]: + changed: list[str] = [] + for rel_path, pattern, mode in TARGETS: + path = ROOT / rel_path + if not path.exists(): + continue + if replace_once(path, pattern, new_version, mode): + changed.append(rel_path) + return changed + + +def collect_mismatches(expected_version: str) -> list[str]: + mismatches: list[str] = [] + for rel_path, pattern, _mode in TARGETS: + path = ROOT / rel_path + if not path.exists(): + continue + + text = path.read_text(encoding="utf-8") + match = re.search(pattern, text, re.MULTILINE) + if not match: + mismatches.append(f"{rel_path}: version marker not found") + continue + + current_value = match.group(2) + if current_value != expected_version: + mismatches.append(f"{rel_path}: {current_value} != {expected_version}") + + return mismatches + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Synchronize Zashterminal version across project files." + ) + group = parser.add_mutually_exclusive_group() + group.add_argument("--set", dest="set_version", help="Set an explicit version.") + group.add_argument( + "--bump", + choices=("major", "minor", "patch"), + help="Increment the current semantic version.", + ) + parser.add_argument( + "--print-current", + action="store_true", + help="Print the current APP_VERSION from config.py.", + ) + parser.add_argument( + "--check", + action="store_true", + help="Fail if any tracked file is not aligned with APP_VERSION.", + ) + return parser + + +def main() -> int: + parser = build_parser() + args = parser.parse_args() + + current_version = read_current_version() + + if args.check and not args.set_version and not args.bump: + mismatches = collect_mismatches(current_version) + if mismatches: + print(f"Version mismatch detected against APP_VERSION={current_version}:") + for item in mismatches: + print(item) + return 1 + print(f"All tracked files are aligned with APP_VERSION={current_version}") + return 0 + + if args.print_current and not args.set_version and not args.bump: + print(current_version) + return 0 + + if args.set_version: + new_version = args.set_version.strip() + elif args.bump: + new_version = bump_version(current_version, args.bump) + else: + parser.error("Provide --print-current, --check, --set, or --bump.") + + changed = sync_all(new_version) + print(new_version) + if changed: + print("Updated files:") + for rel_path in changed: + print(rel_path) + else: + print("No files changed.") + return 0 + + +if __name__ == "__main__": + sys.exit(main())