This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new bf3400aa1e4 Resolve UNKNOWN mergeable status in auto-triage via REST
API (#63317)
bf3400aa1e4 is described below
commit bf3400aa1e461affc89c035b2ca7cb9e232a4a28
Author: Jarek Potiuk <[email protected]>
AuthorDate: Wed Mar 11 09:49:10 2026 +0100
Resolve UNKNOWN mergeable status in auto-triage via REST API (#63317)
GitHub's GraphQL API computes mergeability lazily and often returns
UNKNOWN. Add a phase that queries the REST API (which triggers the
computation) for PRs with unknown status, with one retry after a
short delay for cases where GitHub hasn't finished computing yet.
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../src/airflow_breeze/commands/pr_commands.py | 82 ++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/dev/breeze/src/airflow_breeze/commands/pr_commands.py
b/dev/breeze/src/airflow_breeze/commands/pr_commands.py
index d7b6cf84b9a..d1dcee5c863 100644
--- a/dev/breeze/src/airflow_breeze/commands/pr_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/pr_commands.py
@@ -1174,6 +1174,71 @@ def _display_workflow_approval_panel(pr: PRData,
author_profile: dict | None, pe
console.print(Panel(info_text, title="Workflow Approval Needed",
border_style="bright_cyan"))
+def _resolve_unknown_mergeable(token: str, github_repository: str, prs:
list[PRData]) -> int:
+ """Resolve UNKNOWN mergeable status for PRs via REST API.
+
+ GitHub's GraphQL API computes mergeability lazily and often returns
UNKNOWN.
+ The REST API triggers computation and returns the result. Sometimes the
first
+ call still returns null, so we retry once after a short delay.
+
+ Returns the number of PRs whose status was resolved.
+ """
+ import time
+
+ import requests
+
+ unknown_prs = [pr for pr in prs if pr.mergeable == "UNKNOWN"]
+ if not unknown_prs:
+ return 0
+
+ resolved = 0
+ still_unknown: list[PRData] = []
+
+ for pr in unknown_prs:
+ url =
f"https://api.github.com/repos/{github_repository}/pulls/{pr.number}"
+ response = requests.get(
+ url,
+ headers={"Authorization": f"Bearer {token}", "Accept":
"application/vnd.github.v3+json"},
+ timeout=30,
+ )
+ if response.status_code == 200:
+ data = response.json()
+ mergeable = data.get("mergeable")
+ if mergeable is True:
+ pr.mergeable = "MERGEABLE"
+ resolved += 1
+ elif mergeable is False:
+ pr.mergeable = "CONFLICTING"
+ resolved += 1
+ else:
+ # null means GitHub hasn't computed it yet — retry later
+ still_unknown.append(pr)
+ else:
+ still_unknown.append(pr)
+
+ if still_unknown:
+ # Give GitHub a moment to compute mergeability, then retry
+ time.sleep(2)
+ for pr in still_unknown:
+ url =
f"https://api.github.com/repos/{github_repository}/pulls/{pr.number}"
+ response = requests.get(
+ url,
+ headers={"Authorization": f"Bearer {token}", "Accept":
"application/vnd.github.v3+json"},
+ timeout=30,
+ )
+ if response.status_code == 200:
+ data = response.json()
+ mergeable = data.get("mergeable")
+ if mergeable is True:
+ pr.mergeable = "MERGEABLE"
+ resolved += 1
+ elif mergeable is False:
+ pr.mergeable = "CONFLICTING"
+ resolved += 1
+
+ return resolved
+
+
def _fetch_pr_diff(token: str, github_repository: str, pr_number: int) -> str
| None:
"""Fetch the diff for a PR via GitHub REST API. Returns the diff text or
None on failure."""
import requests
@@ -1644,6 +1709,23 @@ def auto_triage(
)
pr.failed_checks = _fetch_failed_checks(token,
github_repository, pr.head_sha)
+ # Phase 2b2: Resolve UNKNOWN mergeable status via REST API
+ unknown_count = sum(1 for pr in candidate_prs if pr.mergeable == "UNKNOWN")
+ if unknown_count:
+ get_console().print(
+ f"[info]Resolving merge conflict status for {unknown_count} "
+ f"{'PRs' if unknown_count != 1 else 'PR'} with unknown
status...[/]"
+ )
+ resolved = _resolve_unknown_mergeable(token, github_repository,
candidate_prs)
+ remaining = unknown_count - resolved
+ if remaining:
+ get_console().print(
+ f" [dim]{resolved} resolved, {remaining} still unknown "
+ f"(GitHub hasn't computed mergeability yet).[/]"
+ )
+ else:
+ get_console().print(f" [dim]All {resolved} resolved.[/]")
+
# Phase 2c: Fetch unresolved review comment counts for candidate PRs
if candidate_prs and run_ci:
get_console().print(