diff --git a/AGENTS.md b/AGENTS.md index b5fee4f..4e8fa1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,6 +160,12 @@ The following rules are enforced for `master`: ### 1. Create Vikunja Task Create a task in Vikunja to get a `DEVX-N` identifier. +**IMPORTANT:** The task title must NOT include the `DEVX-N:` prefix. +The `make create-pr` and `check_auto_merge_ready` commands automatically +prepend `DEVX-N: ` to the Vikunja task title when forming the PR title. +If the Vikunja task title already includes the prefix, the PR title will +have a double prefix and auto-merge validation will fail. + ### 2. Create Branch ```bash git checkout master && git pull diff --git a/src/devx/ci/check_auto_merge_ready.py b/src/devx/ci/check_auto_merge_ready.py index 5c657a8..0838283 100644 --- a/src/devx/ci/check_auto_merge_ready.py +++ b/src/devx/ci/check_auto_merge_ready.py @@ -241,17 +241,33 @@ def cli( else: click.echo("[pre-merge-check] WARNING: VIKUNJA_TOKEN not set — skipping Vikunja title match check.") else: - expected = f"{task_id}: {vikunja_title}" - if pr_title != expected: + # Defensive check: warn if the Vikunja task title already includes + # the task ID prefix. The expected PR title is + # f"{task_id}: {vikunja_title}" — if vikunja_title already starts + # with "{task_id}:", the PR title will have a double prefix. + if vikunja_title.startswith(f"{task_id}:"): errors.append( _( - "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}", - expected=expected, - title=pr_title, + "Vikunja task title '{title}' starts with '{prefix}:'. " + "The task title should NOT include the '{prefix}' prefix — " + "it is automatically added to the PR title. " + "Update the Vikunja task title to remove the prefix.", + title=vikunja_title, + prefix=task_id, ), ) else: - click.echo(f"[pre-merge-check] Vikunja title match OK: {expected}") + expected = f"{task_id}: {vikunja_title}" + if pr_title != expected: + errors.append( + _( + "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}", + expected=expected, + title=pr_title, + ), + ) + else: + click.echo(f"[pre-merge-check] Vikunja title match OK: {expected}") # 6. Branch behind master (skip if --skip-behind-check) if not skip_behind_check: diff --git a/src/devx/translations.json b/src/devx/translations.json index 0ad8d27..99a968c 100644 --- a/src/devx/translations.json +++ b/src/devx/translations.json @@ -3568,35 +3568,43 @@ "zh": "{separator}" }, "Allow empty tag (PR mode where SHA is concrete).": { - "bg": "Allow empty tag (PR mode where SHA is concrete).", - "de": "Allow empty tag (PR mode where SHA is concrete).", + "bg": "Позволи празен таг (PR режим, където SHA е конкретен).", + "de": "Leeren Tag zulassen (PR-Modus, in dem SHA konkret ist).", "en": "Allow empty tag (PR mode where SHA is concrete).", - "pl": "Allow empty tag (PR mode where SHA is concrete).", - "ru": "Allow empty tag (PR mode where SHA is concrete).", - "zh": "Allow empty tag (PR mode where SHA is concrete)." + "pl": "Zezwalaj na pusty tag (tryb PR, w którym SHA jest konkretne).", + "ru": "Разрешить пустой тег (режим PR, где SHA конкретен).", + "zh": "允许空标签(SHA 为具体值的 PR 模式)。" }, "Git tag or ref that was deployed": { - "bg": "Git tag or ref that was deployed", - "de": "Git tag or ref that was deployed", + "bg": "Git таг или референция, която беше разгърната", + "de": "Git-Tag oder Ref, der bereitgestellt wurde", "en": "Git tag or ref that was deployed", - "pl": "Git tag or ref that was deployed", - "ru": "Git tag or ref that was deployed", - "zh": "Git tag or ref that was deployed" + "pl": "Tag Git lub ref, który został wdrożony", + "ru": "Git-тег или ссылка, которые были развёрнуты", + "zh": "已部署的 Git 标签或引用" }, "Git tag to deploy (e.g. v0.28.1).": { - "bg": "Git tag to deploy (e.g. v0.28.1).", - "de": "Git tag to deploy (e.g. v0.28.1).", + "bg": "Git таг за разгръщане (напр. v0.28.1).", + "de": "Git-Tag für Bereitstellung (z.B. v0.28.1).", "en": "Git tag to deploy (e.g. v0.28.1).", - "pl": "Git tag to deploy (e.g. v0.28.1).", - "ru": "Git tag to deploy (e.g. v0.28.1).", - "zh": "Git tag to deploy (e.g. v0.28.1)." + "pl": "Tag Git do wdrożenia (np. v0.28.1).", + "ru": "Git-тег для развёртывания (напр. v0.28.1).", + "zh": "要部署的 Git 标签(例如 v0.28.1)。" }, "Write deploy-ref to $GITHUB_OUTPUT file.": { - "bg": "Write deploy-ref to $GITHUB_OUTPUT file.", - "de": "Write deploy-ref to $GITHUB_OUTPUT file.", + "bg": "Запиши deploy-ref в $GITHUB_OUTPUT файла.", + "de": "Deploy-ref in $GITHUB_OUTPUT-Datei schreiben.", "en": "Write deploy-ref to $GITHUB_OUTPUT file.", - "pl": "Write deploy-ref to $GITHUB_OUTPUT file.", - "ru": "Write deploy-ref to $GITHUB_OUTPUT file.", - "zh": "Write deploy-ref to $GITHUB_OUTPUT file." + "pl": "Zapisz deploy-ref do pliku $GITHUB_OUTPUT.", + "ru": "Записать deploy-ref в файл $GITHUB_OUTPUT.", + "zh": "将 deploy-ref 写入 $GITHUB_OUTPUT 文件。" + }, + "Vikunja task title '{title}' starts with '{prefix}:'. The task title should NOT include the '{prefix}' prefix — it is automatically added to the PR title. Update the Vikunja task title to remove the prefix.": { + "bg": "Заглавието на задачата във Vikunja '{title}' започва с '{prefix}:'. Заглавието на задачата НЕ трябва да съдържа префикса '{prefix}' — той се добавя автоматично към заглавието на PR. Актуализирайте заглавието на задачата във Vikunja, за да премахнете префикса.", + "de": "Der Vikunja-Aufgabentitel '{title}' beginnt mit '{prefix}:'. Der Aufgabentitel darf NICHT den Präfix '{prefix}' enthalten — er wird automatisch zum PR-Titel hinzugefügt. Aktualisieren Sie den Vikunja-Aufgabentitel, um den Präfix zu entfernen.", + "en": "Vikunja task title '{title}' starts with '{prefix}:'. The task title should NOT include the '{prefix}' prefix — it is automatically added to the PR title. Update the Vikunja task title to remove the prefix.", + "pl": "Tytuł zadania Vikunja '{title}' zaczyna się od '{prefix}:'. Tytuł zadania nie powinien zawierać prefiksu '{prefix}' — jest on automatycznie dodawany do tytułu PR. Zaktualizuj tytuł zadania Vikunja, aby usunąć prefiks.", + "ru": "Заголовок задачи Vikunja '{title}' начинается с '{prefix}:'. Заголовок задачи НЕ должен включать префикс '{prefix}' — он автоматически добавляется к заголовку PR. Обновите заголовок задачи Vikunja, чтобы удалить префикс.", + "zh": "Vikunja 任务标题 '{title}' 以 '{prefix}:' 开头。任务标题不应包含 '{prefix}' 前缀 — 它会自动添加到 PR 标题中。请更新 Vikunja 任务标题以删除前缀。" } } diff --git a/tests/unit/test_check_auto_merge_ready.py b/tests/unit/test_check_auto_merge_ready.py index d7307c7..315544a 100644 --- a/tests/unit/test_check_auto_merge_ready.py +++ b/tests/unit/test_check_auto_merge_ready.py @@ -292,3 +292,18 @@ class TestCli: ) assert result.exit_code != 0 assert "does not match Vikunja" in result.output + + def test_fails_with_double_prefix_in_vikunja_title(self) -> None: + """Vikunja title with task ID prefix causes double-prefix in PR title.""" + runner = CliRunner() + with ( + patch.dict("os.environ", {"DEVX_TASK_PREFIX": "DEVX", "VIKUNJA_TOKEN": "tok"}, clear=True), + patch("devx.ci.check_auto_merge_ready.is_branch_behind_master", return_value=False), + patch("devx.ci.check_auto_merge_ready.get_vikunja_title_optional", return_value="DEVX-1: Fix foo"), + ): + result = runner.invoke( + cli, + ["--branch", "DEVX-1-fix-foo", "--pr-title", "DEVX-1: Fix foo"], + ) + assert result.exit_code != 0 + assert "should NOT include" in result.output