From 9c51c8b62c3562f50c4cb2f2a7de74bcd974f09b Mon Sep 17 00:00:00 2001 From: emil Date: Fri, 19 Jun 2026 21:46:45 +0000 Subject: [PATCH] GRM-25: feat: auto-delete branch after merge in configure_repo script --- Makefile | 15 +-------------- scripts/configure_repo.py | 6 ++++++ scripts/setup.sh | 22 ++++++++++++++++++++++ src/gitea_runner_manager/api_clients.py | 7 +++++++ src/gitea_runner_manager/config.py | 4 ++++ src/gitea_runner_manager/i18n.py | 14 ++++++++++++++ tests/unit/test_api_clients.py | 14 ++++++++++++++ tests/unit/test_configure_repo.py | 5 ++++- 8 files changed, 72 insertions(+), 15 deletions(-) create mode 100755 scripts/setup.sh diff --git a/Makefile b/Makefile index b03d561..5160f23 100644 --- a/Makefile +++ b/Makefile @@ -8,20 +8,7 @@ CHECKMAKE := $(shell command -v checkmake 2>/dev/null || echo $(HOME)/go/bin/che all: setup setup: $(VENV)/bin/activate .env activate-scripts checkmake - $(BIN)/pip install -e ".[dev]" - $(BIN)/ansible-galaxy collection install -r ansible/requirements.yml - $(BIN)/pre-commit install - $(BIN)/pre-commit install --hook-type commit-msg - $(BIN)/pre-commit install --hook-type pre-push - @echo "" - @echo "Setup complete." - @echo "Activate the virtual environment with one of:" - @echo " source .venv/bin/activate (generic)" - @echo " source activate.sh (bash)" - @echo " source activate.fish (fish)" - @echo " source activate.zsh (zsh)" - @-$(BIN)/grm --version - @-$(BIN)/pre-commit --version + @bash scripts/setup.sh "$(BIN)" .env: @if [ ! -f .env ]; then \ diff --git a/scripts/configure_repo.py b/scripts/configure_repo.py index 18c64d8..81742a2 100644 --- a/scripts/configure_repo.py +++ b/scripts/configure_repo.py @@ -19,6 +19,7 @@ from gitea_runner_manager.config import ( LABEL_CONFIG, REPO_NAME, REPO_OWNER, + REPO_SETTINGS_CONFIG, ) from gitea_runner_manager.exceptions import APIError from gitea_runner_manager.i18n import _ @@ -78,6 +79,11 @@ def main() -> None: else: click.echo(_(" Label '{label}' created.", label=label_name)) + click.echo("") + click.echo(_("Configuring repository settings...")) + client.update_repo_settings(cast(dict[str, object], REPO_SETTINGS_CONFIG)) + click.echo(_(" - Auto-delete branch after merge: yes")) + click.echo("") click.echo(_("Repository configuration complete.")) except APIError as e: diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..16f39e5 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -e + +BIN="${1:-.venv/bin}" + +"$BIN/pip" install -e ".[dev]" +"$BIN/ansible-galaxy" collection install -r ansible/requirements.yml +"$BIN/pre-commit" install +"$BIN/pre-commit" install --hook-type commit-msg +"$BIN/pre-commit" install --hook-type pre-push + +echo "" +echo "Setup complete." +echo "Activate the virtual environment with one of:" +echo " source .venv/bin/activate (generic)" +echo " source activate.sh (bash)" +echo " source activate.fish (fish)" +echo " source activate.zsh (zsh)" + +# Verification +"$BIN/grm" --version 2>/dev/null || true +"$BIN/pre-commit" --version 2>/dev/null || true diff --git a/src/gitea_runner_manager/api_clients.py b/src/gitea_runner_manager/api_clients.py index 864fbc6..8497eae 100644 --- a/src/gitea_runner_manager/api_clients.py +++ b/src/gitea_runner_manager/api_clients.py @@ -53,6 +53,13 @@ class GiteaClient: raise APIError(status, message) from e return response + # -- repo settings -- + + def update_repo_settings(self, settings: dict[str, Any]) -> dict[str, Any]: + """Update repository settings (e.g. auto-delete branch after merge).""" + r = self._request("PATCH", "", json=settings) + return r.json() + # -- branch protection -- def list_branch_protections(self) -> list[dict[str, Any]]: diff --git a/src/gitea_runner_manager/config.py b/src/gitea_runner_manager/config.py index cbc7c8b..a1fb2fb 100644 --- a/src/gitea_runner_manager/config.py +++ b/src/gitea_runner_manager/config.py @@ -37,3 +37,7 @@ LABEL_CONFIG: dict[str, object] = { "color": "2ecc71", "description": "Auto-merge PR when all CI checks pass", } + +REPO_SETTINGS_CONFIG: dict[str, object] = { + "default_delete_branch_after_merge": True, +} diff --git a/src/gitea_runner_manager/i18n.py b/src/gitea_runner_manager/i18n.py index ad8c9ae..301e3b5 100644 --- a/src/gitea_runner_manager/i18n.py +++ b/src/gitea_runner_manager/i18n.py @@ -586,6 +586,20 @@ TRANSLATIONS: dict[str, dict[str, str]] = { "ru": "Конфигурация репозитория завершена.", "zh": "仓库配置完成。", }, + "Configuring repository settings...": { + "en": "Configuring repository settings...", + "bg": "Конфигуриране на настройките на хранилището...", + "de": "Repository-Einstellungen konfigurieren...", + "ru": "Настройка параметров репозитория...", + "zh": "正在配置仓库设置...", + }, + " - Auto-delete branch after merge: yes": { + "en": " - Auto-delete branch after merge: yes", + "bg": " - Автоматично изтриване на клон след сливане: да", + "de": " - Branch nach Merge automatisch löschen: ja", + "ru": " - Автоудаление ветки после слияния: да", + "zh": " - 合并后自动删除分支: 是", + }, "HTTP {status} Forbidden — your token lacks admin rights.\nMake sure the token belongs to a repo owner or organisation admin.\nAlternatively, configure branch protection manually in Settings → Branches.": { # noqa: E501 "en": "HTTP {status} Forbidden — your token lacks admin rights.\nMake sure the token belongs to a repo owner or organisation admin.\nAlternatively, configure branch protection manually in Settings → Branches.", # noqa: E501 "bg": "HTTP {status} Забранено — вашият токен няма администраторски права.\nУверете се, че токенът принадлежи на собственик на хранилище или администратор на организация.\nАлтернативно, конфигурирайте защитата на клона ръчно в Настройки → Клонове.", # noqa: E501 diff --git a/tests/unit/test_api_clients.py b/tests/unit/test_api_clients.py index 655200d..85af19a 100644 --- a/tests/unit/test_api_clients.py +++ b/tests/unit/test_api_clients.py @@ -189,6 +189,20 @@ class TestGiteaClient: json={"Do": "squash", "MergeTitleField": "fix: bug"}, ) + def test_update_repo_settings(self) -> None: + client = GiteaClient("https://git.example.com", "tok", "owner", "repo") + client._session.request = MagicMock(return_value=_mock_response({"default_delete_branch_after_merge": True})) + + settings = {"default_delete_branch_after_merge": True} + result = client.update_repo_settings(settings) + assert result["default_delete_branch_after_merge"] is True + client._session.request.assert_called_once_with( + "PATCH", + "https://git.example.com/repos/owner/repo", + timeout=DEFAULT_TIMEOUT, + json=settings, + ) + def test_create_release(self) -> None: client = GiteaClient("https://git.example.com", "tok", "owner", "repo") client._session.request = MagicMock(return_value=_mock_response({"id": 1})) diff --git a/tests/unit/test_configure_repo.py b/tests/unit/test_configure_repo.py index cac495e..69f2125 100644 --- a/tests/unit/test_configure_repo.py +++ b/tests/unit/test_configure_repo.py @@ -6,7 +6,7 @@ from unittest.mock import MagicMock, patch import click import pytest -from gitea_runner_manager.config import BRANCH_PROTECTION_CONFIG +from gitea_runner_manager.config import BRANCH_PROTECTION_CONFIG, REPO_SETTINGS_CONFIG from gitea_runner_manager.exceptions import APIError from scripts.configure_repo import ( _handle_http_error, @@ -53,6 +53,7 @@ class TestMain: mock_client.ensure_branch_protection.assert_called_once_with("master", BRANCH_PROTECTION_CONFIG) mock_client.ensure_label.assert_called_once() + mock_client.update_repo_settings.assert_called_once_with(REPO_SETTINGS_CONFIG) def test_main_label_already_exists(self) -> None: with patch.dict("os.environ", {"REPO_TOKEN": "tok"}, clear=True): @@ -65,6 +66,7 @@ class TestMain: mock_client.ensure_branch_protection.assert_called_once_with("master", BRANCH_PROTECTION_CONFIG) mock_client.ensure_label.assert_called_once() + mock_client.update_repo_settings.assert_called_once_with(REPO_SETTINGS_CONFIG) def test_main_api_error(self) -> None: with patch.dict("os.environ", {"REPO_TOKEN": "tok"}, clear=True): @@ -94,3 +96,4 @@ def test_main_module_block() -> None: namespace["GiteaClient"] = mock_client_cls namespace["main"]() mock_client.ensure_branch_protection.assert_called_once_with("master", BRANCH_PROTECTION_CONFIG) + mock_client.update_repo_settings.assert_called_once_with(REPO_SETTINGS_CONFIG)