Harden work-item failure recovery

This commit is contained in:
2026-07-13 13:55:37 +02:00
parent 80447092e9
commit 084a0b5058
3 changed files with 90 additions and 16 deletions

View File

@@ -322,6 +322,13 @@ class Gitea:
except json.JSONDecodeError as error:
raise WorkItemError(f"Could not parse created pull request: {output}") from error
def find_open_pr(self, branch: str) -> dict[str, Any] | None:
pulls = self.api(f"{self.base}/pulls?state=open&limit=50")
for pull in pulls:
if (pull.get("head") or {}).get("ref") == branch:
return pull
return None
def pr(self, number: int) -> dict[str, Any]:
return self.api(f"{self.base}/pulls/{number}")
@@ -399,7 +406,12 @@ class Workflow:
self.git.update_main()
story = self.gitea.next_story()
branch = self.git.create_story_branch(story)
self.gitea.claim(story)
try:
self.gitea.claim(story)
except Exception:
self.git.git("switch", self.config.main_branch)
self.git.git("branch", "-D", branch)
raise
state = {
"issue": story.number,
"story_id": story.story_id,
@@ -421,26 +433,37 @@ class Workflow:
state = self.load_state()
if self.git.current_branch() != state["branch"]:
raise WorkItemError(f"Expected branch {state['branch']}, found {self.git.current_branch()}")
commands = tuple(dict.fromkeys((*self.config.required_tests, *tests)))
if not commands:
raise WorkItemError("At least one automated test command is required")
self.git.assert_safe_changes()
for command in commands:
self.runner.run_shell(command, cwd=self.root)
paths = self.git.assert_safe_changes()
if not confirmed:
summary = self.git.git("diff", "--stat")
raise WorkItemError(
"Review the changes and rerun with --yes to commit:\n"
f"{summary}\nFiles: {', '.join(path.as_posix() for path in paths)}"
)
story = Story(
number=int(state["issue"]), story_id=state["story_id"], title=state["title"],
epic=int(state["story_id"][2:4]), sequence=int(state["story_id"][5:7]),
labels=frozenset(), assignees=(), raw={},
)
commit = self.git.stage_commit_push(story, state["branch"])
pr = self.gitea.create_pr(story, state["branch"], commands, commit)
if state.get("status") == "pushed":
commands = tuple(state["tests"])
commit = state["commit"]
elif state.get("status") == "in-progress":
commands = tuple(dict.fromkeys((*self.config.required_tests, *tests)))
if not commands:
raise WorkItemError("At least one automated test command is required")
self.git.assert_safe_changes()
for command in commands:
self.runner.run_shell(command, cwd=self.root)
paths = self.git.assert_safe_changes()
if not confirmed:
summary = self.git.git("diff", "--stat")
raise WorkItemError(
"Review the changes and rerun with --yes to commit:\n"
f"{summary}\nFiles: {', '.join(path.as_posix() for path in paths)}"
)
commit = self.git.stage_commit_push(story, state["branch"])
state.update({"status": "pushed", "commit": commit, "tests": list(commands)})
self.save_state(state)
else:
raise WorkItemError(f"Story cannot be submitted from status {state.get('status')!r}")
pr = self.gitea.find_open_pr(state["branch"])
if pr is None:
pr = self.gitea.create_pr(story, state["branch"], commands, commit)
pr_number = int(pr.get("index") or pr.get("number"))
state.update({"status": "review", "pr": pr_number, "commit": commit, "tests": list(commands)})
self.save_state(state)