feat: catch up Renovate PRs with passing CI in agent loop (#289) (#293)

This commit was merged in pull request #293.
This commit is contained in:
Bot of Thomas Güttler
2026-05-27 20:09:13 +02:00
parent f42522e6d0
commit 5ddfe68467
+52
View File
@@ -251,6 +251,24 @@ def _open_issue_prs() -> list[dict]:
return issue_prs return issue_prs
def _open_renovate_prs() -> list[dict]:
"""Return all open PRs from Renovate (renovate/* branches), oldest-first."""
result = subprocess.run(
["fgj", "--hostname", "codeberg.org", "pr", "list",
"--repo", REPO, "--state", "open", "--json"],
capture_output=True, text=True,
)
if result.returncode != 0 or not result.stdout.strip():
return []
prs = json.loads(result.stdout)
renovate_prs = [
pr for pr in prs
if (pr.get("head", {}).get("ref") or "").startswith("renovate/")
]
renovate_prs.sort(key=lambda p: p["number"])
return renovate_prs
def _latest_ci_run_for_pr(pr_number: int) -> dict | None: def _latest_ci_run_for_pr(pr_number: int) -> dict | None:
"""Return the latest CI run triggered by a pull_request event for the given PR number.""" """Return the latest CI run triggered by a pull_request event for the given PR number."""
pr_ref = f"#{pr_number}" pr_ref = f"#{pr_number}"
@@ -828,6 +846,40 @@ def _run_loop() -> int:
print(f"Merged PR #{pr_number}.") print(f"Merged PR #{pr_number}.")
return 0 return 0
# ── 2c. Catch-up: merge Renovate PRs with passing CI ─────────────────────
# The merge-renovate CI job only fires on pull_request events. If a Renovate
# PR had CI run before that job was added (or the automerge label was absent),
# it stays open forever. Detect and merge those here.
for pr in _open_renovate_prs():
pr_number = pr["number"]
pr_url = f"{REPO_URL}/pulls/{pr_number}"
pr_run = _latest_ci_run_for_pr(pr_number)
if pr_run and pr_run.get("status") == "running":
print(f"Catch-up (Renovate): CI {_ci_run_url(pr_run['id'])} on PR #{pr_number} still running. Waiting.")
return 0
if pr_run and pr_run.get("status") in ("failure", "error"):
print(f"Catch-up (Renovate): CI {_ci_run_url(pr_run['id'])} on PR #{pr_number} failed — skipping.")
continue
if pr_run and pr_run.get("status") == "success":
print(f"Catch-up (Renovate): CI passed on PR #{pr_number} ({pr_url}) — merging.")
try:
_merge_pr(pr_number)
except RuntimeError as e:
print(f"Catch-up (Renovate): merge of PR #{pr_number} failed: {e} — skipping.")
continue
branch = pr.get("head", {}).get("ref", "")
if _find_pr_for_branch(branch):
print(f"Catch-up (Renovate): PR #{pr_number} still open after merge — skipping.")
continue
print(f"Catch-up (Renovate): merged PR #{pr_number}.")
return 0
if pr_run is None:
print(f"Catch-up (Renovate): no CI run for PR #{pr_number} ({pr_url}) — skipping (needs manual review).")
# ── 3. Global CI check (main branch only) ──────────────────────────────── # ── 3. Global CI check (main branch only) ────────────────────────────────
run = _latest_main_ci_run() run = _latest_main_ci_run()