Harden work-item failure recovery
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user