Public Access
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a17982f2cf | ||
|
|
cf85964877 | ||
|
|
fbb1fc3134 | ||
|
|
a8f86aca68 | ||
|
|
13bed1d99c |
@@ -35,3 +35,6 @@ Thumbs.db
|
||||
|
||||
# Badges
|
||||
.badges/
|
||||
|
||||
# Deprecated CI task tracking (branch name is the sole source of truth)
|
||||
.taskid
|
||||
|
||||
@@ -287,15 +287,10 @@ setuptools via `dynamic = ["version"]` in `pyproject.toml`.
|
||||
|
||||
### Task ID Resolution
|
||||
|
||||
`auto_merge` resolves the task ID from the branch name first (e.g.
|
||||
`DEVX-12-fix-foo` → `DEVX-12`), falling back to the `.taskid` file
|
||||
for branches without a task ID prefix. If both exist and disagree,
|
||||
a warning is printed and the branch task ID is preferred.
|
||||
|
||||
**When creating a new branch from an existing branch**, the `.taskid`
|
||||
file may be stale (it contains the old branch's task ID). Either:
|
||||
1. Update `.taskid` to match the new branch's task ID, or
|
||||
2. Delete `.taskid` — the branch name is the primary source of truth
|
||||
`auto_merge` resolves the task ID solely from the branch name (e.g.
|
||||
`DEVX-12-fix-foo` → `DEVX-12`). Branch names must include the task ID
|
||||
prefix — there is no `.taskid` file fallback. If a stale `.taskid` file
|
||||
exists in the repo, a deprecation warning is printed advising its removal.
|
||||
|
||||
### Workflow `auto-merge` Job and `always()`
|
||||
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.10.0] - 2026-06-24
|
||||
|
||||
### Features
|
||||
|
||||
- Remove .taskid file fallback, use branch name only
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use raw/branch/badges/ URLs for badges in README and docs
|
||||
|
||||
## [0.9.12] - 2026-06-24
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -16,12 +16,12 @@ quality badges.
|
||||
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
## Why devx?
|
||||
|
||||
|
||||
+6
-6
@@ -12,12 +12,12 @@ project to be reusable across all oblachno-oss repositories.
|
||||
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/src/branch/master/LICENSE)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/wiki)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/actions)
|
||||
[](https://git.oblachno.oblachno.fyi/oblachno-oss/devx/releases)
|
||||
[](https://www.python.org/downloads/)
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""devx — reusable development and CI/CD tools for oblachno-oss projects."""
|
||||
|
||||
__version__ = "0.9.12"
|
||||
__version__ = "0.10.0"
|
||||
|
||||
+15
-27
@@ -2,9 +2,9 @@
|
||||
"""Auto-merge PR when all CI checks pass.
|
||||
|
||||
Runs as the final job in ci.yml. Reads the task ID from the branch name
|
||||
(falling back to ``.taskid`` file for branches without a task ID prefix),
|
||||
validates the PR title, and squash-merges with a conventional commit
|
||||
message prefixed by the task ID.
|
||||
(e.g., ``DEVX-31-fix-foo`` → ``DEVX-31``), validates the PR title against
|
||||
the Vikunja task, and squash-merges with a conventional commit message
|
||||
prefixed by the task ID.
|
||||
|
||||
PR title format: ``{PREFIX}-N: <vikunja task title>``
|
||||
Merge commit format: ``{PREFIX}-N <conventional commit message>``
|
||||
@@ -42,7 +42,7 @@ from devx.config import (
|
||||
from devx.exceptions import APIError
|
||||
from devx.i18n import _
|
||||
|
||||
TASKID_FILE = ".taskid"
|
||||
TASKID_FILE = ".taskid" # Deprecated, kept for backward-compat warnings
|
||||
PR_TITLE_RE = re.compile(rf"^{TASK_PREFIX}-\d+:\s+.+")
|
||||
|
||||
load_dotenv()
|
||||
@@ -63,44 +63,31 @@ def run_cmd(args: list[str], check: bool = True) -> subprocess.CompletedProcess[
|
||||
|
||||
|
||||
def read_taskid(branch: str) -> str:
|
||||
"""Read task ID from branch name, falling back to .taskid file.
|
||||
"""Read task ID from branch name.
|
||||
|
||||
The branch name is the primary source of truth for the task ID
|
||||
(e.g., ``DEVX-31-fix-foo`` → ``DEVX-31``). The ``.taskid`` file
|
||||
is a legacy fallback for branches without a task ID prefix.
|
||||
The branch name is the sole source of truth for the task ID
|
||||
(e.g., ``DEVX-31-fix-foo`` → ``DEVX-31``). Branches must include
|
||||
the task ID prefix — there is no ``.taskid`` file fallback.
|
||||
|
||||
If both sources exist and disagree, a warning is printed and the
|
||||
branch task ID is preferred (it is the current source of truth).
|
||||
If a stale ``.taskid`` file exists and disagrees with the branch
|
||||
name, a deprecation warning is printed advising its removal.
|
||||
"""
|
||||
branch_task_id = extract_task_id(branch)
|
||||
if branch_task_id:
|
||||
# Check for stale .taskid file that disagrees with branch name
|
||||
# Warn about stale .taskid file if it exists and disagrees
|
||||
path = Path(TASKID_FILE)
|
||||
if path.exists():
|
||||
file_task_id = path.read_text(encoding="utf-8").strip()
|
||||
if file_task_id and file_task_id != branch_task_id:
|
||||
click.echo(
|
||||
_(
|
||||
"WARNING: .taskid file ({file_id}) disagrees with branch name ({branch_id}). "
|
||||
"Using branch task ID. Update or delete .taskid to silence this warning.",
|
||||
"WARNING: .taskid file ({file_id}) is deprecated and disagrees with branch name ({branch_id}). "
|
||||
"Delete .taskid from the repo — branch name is the sole source of truth.",
|
||||
file_id=file_task_id,
|
||||
branch_id=branch_task_id,
|
||||
)
|
||||
)
|
||||
return branch_task_id
|
||||
# Fallback: read from .taskid file
|
||||
path = Path(TASKID_FILE)
|
||||
if path.exists():
|
||||
task_id = path.read_text(encoding="utf-8").strip()
|
||||
if task_id:
|
||||
click.echo(
|
||||
_(
|
||||
"Task ID from .taskid file: {task_id} (not found in branch name '{branch}')",
|
||||
task_id=task_id,
|
||||
branch=branch,
|
||||
)
|
||||
)
|
||||
return task_id
|
||||
return ""
|
||||
|
||||
|
||||
@@ -229,7 +216,8 @@ def main(branch: str, pr_title: str, repo: str, pr_number: str) -> None:
|
||||
if not task_id:
|
||||
raise click.ClickException(
|
||||
_(
|
||||
"Oops! No task ID found in .taskid file or branch name '{branch}'.",
|
||||
"Oops! No task ID found in branch name '{branch}'. "
|
||||
"Branch names must include the task ID prefix (e.g., DEVX-31-fix-bug).",
|
||||
branch=branch,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -298,8 +298,6 @@ DEFAULT_INFRASTRUCTURE: list[str] = [
|
||||
"activate.sh",
|
||||
"activate.fish",
|
||||
"activate.zsh",
|
||||
# CI task tracking file (written by CI, not by developers)
|
||||
".taskid",
|
||||
]
|
||||
|
||||
|
||||
|
||||
+14
-21
@@ -776,13 +776,6 @@
|
||||
"ru": "Oops! Master branch commits must start with a task ID.\n Expected: {prefix}-N: <conventional commit message>\n Got: {subject}",
|
||||
"zh": "Oops! Master branch commits must start with a task ID.\n Expected: {prefix}-N: <conventional commit message>\n Got: {subject}"
|
||||
},
|
||||
"Oops! No task ID found in .taskid file or branch name '{branch}'.": {
|
||||
"bg": "Oops! No task ID found in .taskid file or branch name '{branch}'.",
|
||||
"de": "Oops! No task ID found in .taskid file or branch name '{branch}'.",
|
||||
"en": "Oops! No task ID found in .taskid file or branch name '{branch}'.",
|
||||
"ru": "Oops! No task ID found in .taskid file or branch name '{branch}'.",
|
||||
"zh": "Oops! No task ID found in .taskid file or branch name '{branch}'."
|
||||
},
|
||||
"Oops! PR title must follow format '{prefix}-N: <task title>'.\n Expected: {task_id}: <task title>\n Got: {pr_title}": {
|
||||
"bg": "Oops! PR title must follow format '{prefix}-N: <task title>'.\n Expected: {task_id}: <task title>\n Got: {pr_title}",
|
||||
"de": "Oops! PR title must follow format '{prefix}-N: <task title>'.\n Expected: {task_id}: <task title>\n Got: {pr_title}",
|
||||
@@ -993,13 +986,6 @@
|
||||
"ru": "Task ID: {task_id}",
|
||||
"zh": "Task ID: {task_id}"
|
||||
},
|
||||
"Task ID from .taskid file: {task_id} (not found in branch name '{branch}')": {
|
||||
"bg": "Task ID от .taskid файл: {task_id} (не е намерен в името на клона '{branch}')",
|
||||
"de": "Task ID aus .taskid-Datei: {task_id} (nicht im Branch-Namen '{branch}' gefunden)",
|
||||
"en": "Task ID from .taskid file: {task_id} (not found in branch name '{branch}')",
|
||||
"ru": "Task ID из файла .taskid: {task_id} (не найден в имени ветки '{branch}')",
|
||||
"zh": "来自 .taskid 文件的 Task ID: {task_id}(在分支名 '{branch}' 中未找到)"
|
||||
},
|
||||
"Test '{name}' took {elapsed:.2f}s (limit: {limit}s). Optimise: use lighter fixtures, reduce I/O, or mock external calls.": {
|
||||
"bg": "Test '{name}' took {elapsed:.2f}s (limit: {limit}s). Optimise: use lighter fixtures, reduce I/O, or mock external calls.",
|
||||
"de": "Test '{name}' took {elapsed:.2f}s (limit: {limit}s). Optimise: use lighter fixtures, reduce I/O, or mock external calls.",
|
||||
@@ -1084,13 +1070,6 @@
|
||||
"ru": "WARNING: --skip-tests passed — skipping test verification.",
|
||||
"zh": "WARNING: --skip-tests passed — skipping test verification."
|
||||
},
|
||||
"WARNING: .taskid file ({file_id}) disagrees with branch name ({branch_id}). Using branch task ID. Update or delete .taskid to silence this warning.": {
|
||||
"bg": "ВНИМАНИЕ: .taskid файл ({file_id}) не съвпада с името на клона ({branch_id}). Използва се task ID от клона. Актуализирайте или изтрийте .taskid за да премахнете това предупреждение.",
|
||||
"de": "WARNUNG: .taskid-Datei ({file_id}) stimmt nicht mit Branch-Namen ({branch_id}) überein. Branch-Task-ID wird verwendet. Aktualisieren oder löschen Sie .taskid, um diese Warnung zu unterdrücken.",
|
||||
"en": "WARNING: .taskid file ({file_id}) disagrees with branch name ({branch_id}). Using branch task ID. Update or delete .taskid to silence this warning.",
|
||||
"ru": "ВНИМАНИЕ: файл .taskid ({file_id}) не совпадает с именем ветки ({branch_id}). Используется Task ID из ветки. Обновите или удалите .taskid, чтобы скрыть это предупреждение.",
|
||||
"zh": "警告:.taskid 文件 ({file_id}) 与分支名 ({branch_id}) 不一致。使用分支 Task ID。更新或删除 .taskid 以消除此警告。"
|
||||
},
|
||||
"Warning: could not fetch tags from origin.": {
|
||||
"bg": "Warning: could not fetch tags from origin.",
|
||||
"de": "Warning: could not fetch tags from origin.",
|
||||
@@ -1258,5 +1237,19 @@
|
||||
"en": "{file} already exists. Use --force to overwrite.",
|
||||
"ru": "{file} already exists. Use --force to overwrite.",
|
||||
"zh": "{file} already exists. Use --force to overwrite."
|
||||
},
|
||||
"Oops! No task ID found in branch name '{branch}'. Branch names must include the task ID prefix (e.g., DEVX-31-fix-bug).": {
|
||||
"en": "Oops! No task ID found in branch name '{branch}'. Branch names must include the task ID prefix (e.g., DEVX-31-fix-bug).",
|
||||
"bg": "Ой! Не е намерен ID на задача в името на клона '{branch}'. Имената на клонове трябва да включват префикса за ID на задача (напр. DEVX-31-fix-bug).",
|
||||
"de": "Hoppla! Keine Task-ID im Branch-Namen '{branch}' gefunden. Branch-Namen müssen das Task-ID-Präfix enthalten (z.B. DEVX-31-fix-bug).",
|
||||
"ru": "Ой! ID задачи не найден в имени ветки '{branch}'. Имена веток должны включать префикс ID задачи (например, DEVX-31-fix-bug).",
|
||||
"zh": "哎呀!在分支名称 '{branch}' 中未找到任务 ID。分支名称必须包含任务 ID 前缀(例如 DEVX-31-fix-bug)。"
|
||||
},
|
||||
"WARNING: .taskid file ({file_id}) is deprecated and disagrees with branch name ({branch_id}). Delete .taskid from the repo — branch name is the sole source of truth.": {
|
||||
"en": "WARNING: .taskid file ({file_id}) is deprecated and disagrees with branch name ({branch_id}). Delete .taskid from the repo — branch name is the sole source of truth.",
|
||||
"bg": "ВНИМАНИЕ: Файлът .taskid ({file_id}) е остарял и не съвпада с името на клона ({branch_id}). Изтрийте .taskid от хранилището — името на клона е единственият източник на истината.",
|
||||
"de": "WARNUNG: Die Datei .taskid ({file_id}) ist veraltet und stimmt nicht mit dem Branch-Namen ({branch_id}) überein. Löschen Sie .taskid aus dem Repo — der Branch-Name ist die einzige Wahrheitsquelle.",
|
||||
"ru": "ВНИМАНИЕ: Файл .taskid ({file_id}) устарел и не совпадает с именем ветки ({branch_id}). Удалите .taskid из репозитория — имя ветки — единственный источник истины.",
|
||||
"zh": "警告:.taskid 文件 ({file_id}) 已弃用,与分支名称 ({branch_id}) 不一致。请从仓库中删除 .taskid — 分支名称是唯一的真实来源。"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,40 +21,31 @@ from devx.exceptions import APIError
|
||||
|
||||
|
||||
class TestReadTaskid:
|
||||
def test_prefers_branch_name_over_file(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-60\n")
|
||||
# Branch name takes priority over .taskid file
|
||||
assert read_taskid("DEVX-19-fix-bug") == "DEVX-19"
|
||||
|
||||
def test_falls_back_to_file_when_no_branch_match(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-60\n")
|
||||
# No task ID in branch name → fall back to .taskid
|
||||
assert read_taskid("some-branch") == "DEVX-60"
|
||||
|
||||
def test_falls_back_to_branch_name(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
def test_extracts_from_branch_name(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
assert read_taskid("DEVX-19-fix-bug") == "DEVX-19"
|
||||
|
||||
def test_returns_empty_when_no_file_no_match(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
def test_returns_empty_when_no_match(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
assert read_taskid("feature-branch") == ""
|
||||
|
||||
def test_empty_file_falls_back_to_branch(self, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("\n")
|
||||
assert read_taskid("DEVX-42-test") == "DEVX-42"
|
||||
|
||||
def test_warns_on_stale_taskid_file(self, tmp_path, monkeypatch, capsys) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-60\n")
|
||||
# Branch name takes priority, but stale .taskid should produce a warning
|
||||
# Branch name takes priority, stale .taskid should produce deprecation warning
|
||||
assert read_taskid("DEVX-19-fix-bug") == "DEVX-19"
|
||||
captured = capsys.readouterr()
|
||||
assert "WARNING" in captured.out
|
||||
assert "DEVX-60" in captured.out
|
||||
assert "DEVX-19" in captured.out
|
||||
combined = captured.out + captured.err
|
||||
assert "WARNING" in combined
|
||||
assert "deprecated" in combined
|
||||
assert "DEVX-60" in combined
|
||||
assert "DEVX-19" in combined
|
||||
|
||||
def test_no_warning_when_taskid_file_absent(self, tmp_path, monkeypatch, capsys) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
assert read_taskid("DEVX-42-test") == "DEVX-42"
|
||||
captured = capsys.readouterr()
|
||||
assert "WARNING" not in captured.out
|
||||
|
||||
|
||||
# -- extract_task_id (legacy fallback) --
|
||||
@@ -217,7 +208,6 @@ class TestMain:
|
||||
self, mock_client_cls: MagicMock, _mock_validate: MagicMock, tmp_path, monkeypatch
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.get_pr_commits.return_value = [
|
||||
@@ -244,7 +234,7 @@ class TestMain:
|
||||
@patch("devx.ci.auto_merge.GiteaClient")
|
||||
def test_no_task_id_raises(self, mock_client_cls: MagicMock, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
# No .taskid file, no DEVX-N in branch name
|
||||
# No DEVX-N in branch name
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["feature-branch", "DEVX-19: test", "owner/repo", "7"])
|
||||
assert result.exit_code != 0
|
||||
@@ -254,7 +244,6 @@ class TestMain:
|
||||
@patch("devx.ci.auto_merge.GiteaClient")
|
||||
def test_invalid_pr_title_raises(self, mock_client_cls: MagicMock, tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["DEVX-19-fix", "Bad title", "owner/repo", "7"])
|
||||
@@ -268,7 +257,6 @@ class TestMain:
|
||||
self, mock_client_cls: MagicMock, _mock_validate: MagicMock, tmp_path, monkeypatch
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.get_pr_commits.return_value = [
|
||||
@@ -298,7 +286,6 @@ class TestMain:
|
||||
self, mock_client_cls: MagicMock, _mock_validate: MagicMock, tmp_path, monkeypatch
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.get_pr_commits.return_value = [
|
||||
@@ -323,7 +310,6 @@ class TestMain:
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
"""When no conventional commit message is found in PR commits, raises."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.get_pr_commits.return_value = []
|
||||
@@ -341,7 +327,6 @@ class TestMain:
|
||||
def test_invalid_pr_number_raises(self, tmp_path, monkeypatch) -> None:
|
||||
"""Non-integer PR number should raise."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["DEVX-19-fix", "DEVX-19: Test", "owner/repo", "not-a-number"])
|
||||
assert result.exit_code != 0
|
||||
@@ -351,7 +336,6 @@ class TestMain:
|
||||
def test_invalid_repo_format_raises(self, tmp_path, monkeypatch) -> None:
|
||||
"""Repo without owner/name should raise."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["DEVX-19-fix", "DEVX-19: Test", "invalidrepo", "7"])
|
||||
assert result.exit_code != 0
|
||||
@@ -365,7 +349,6 @@ class TestMain:
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
"""When rebase retry also fails, raises with helpful message."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / ".taskid").write_text("DEVX-19\n")
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.get_pr_commits.return_value = [
|
||||
|
||||
Reference in New Issue
Block a user