This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push:
new 3117af05f ci: Fix PR maintenance for pull requests without workflows
3117af05f is described below
commit 3117af05f24bc4bd68a4ff9f4bfff20352350e22
Author: Szymon Janc <[email protected]>
AuthorDate: Mon Oct 19 18:01:33 2026 +0200
ci: Fix PR maintenance for pull requests without workflows
GraphQL Commit.file() returns an error if path doesn't exist in commit.
Old pull requests with head commit from before .github/workflows was
added made whole query fail, and gh stops pagination on errors.
Query workflows trees separately using Repository.object() which
returns null for non-existing path instead.
Assisted-by: Claude:claude-opus-5-5
---
.github/scripts/pr_maintenance.py | 59 +++++++++++++++++++++++++++++++--------
1 file changed, 47 insertions(+), 12 deletions(-)
diff --git a/.github/scripts/pr_maintenance.py
b/.github/scripts/pr_maintenance.py
index 11b5b18ad..20f0b4dfd 100644
--- a/.github/scripts/pr_maintenance.py
+++ b/.github/scripts/pr_maintenance.py
@@ -57,6 +57,10 @@ CI_RUNS_MAX_AGE_DAYS = 30
# Limit API usage, remaining pull requests are handled by next runs
MAX_PULLS_PER_RUN = 20
+# Workflows trees are queried with object() which returns null if path
+# doesn't exist, Commit.file() fails whole query (and gh pagination) instead
+TREES_PER_QUERY = 100
+
REPO = os.environ.get("GITHUB_REPOSITORY", "")
PULLS_QUERY = """
@@ -88,20 +92,13 @@ query (
}
baseRef {
target {
- ... on Commit {
- file(path: ".github/workflows") {
- oid
- }
- }
+ oid
}
}
commits(last: 1) {
nodes {
commit {
oid
- file(path: ".github/workflows") {
- oid
- }
status {
context(name: $context) {
state
@@ -117,6 +114,16 @@ query (
}
"""
+TREES_QUERY = """
+query ($owner: String!, $repo: String!) {
+ repository(owner: $owner, name: $repo) {
+%s
+ }
+}
+"""
+
+TREE_FIELD = 'c%d: object(expression: "%s:.github/workflows") { oid }'
+
def gh(*args):
"""Runs gh command, returns its output"""
@@ -128,6 +135,25 @@ def error(message):
print(f"::error::{message}")
+def workflows_trees(commits):
+ """Returns dict of commit to its .github/workflows tree (or None)"""
+ owner, repo = REPO.split("/")
+ commits = sorted(set(commits))
+ trees = {}
+
+ for i in range(0, len(commits), TREES_PER_QUERY):
+ chunk = commits[i:i + TREES_PER_QUERY]
+ fields = "\n".join(TREE_FIELD % (n, c) for n, c in enumerate(chunk))
+ data = json.loads(gh("api", "graphql",
+ "-f", f"query={TREES_QUERY % fields}",
+ "-f", f"owner={owner}", "-f", f"repo={repo}"))
+ result = data["data"]["repository"]
+ for n, c in enumerate(chunk):
+ trees[c] = (result[f"c{n}"] or {}).get("oid")
+
+ return trees
+
+
def list_pulls():
owner, repo = REPO.split("/")
pages = json.loads(gh("api", "graphql", "--paginate", "--slurp",
@@ -145,17 +171,26 @@ def list_pulls():
continue
base = (node["baseRef"] or {}).get("target") or {}
- base_tree = (base.get("file") or {}).get("oid")
pulls.append({
"number": node["number"],
"head": commit["oid"],
"labels": [l["name"] for l in node["labels"]["nodes"]],
"status": (commit["status"] or {}).get("context"),
- "tree": (commit["file"] or {}).get("oid"),
- "base_tree": base_tree,
- "base": f"{node['baseRefName']}@{(base_tree or 'none')[:12]}",
+ "base_name": node["baseRefName"],
+ "base_head": base.get("oid"),
})
+ trees = workflows_trees([p["head"] for p in pulls] +
+ [p["base_head"] for p in pulls if p["base_head"]])
+
+ for pull in pulls:
+ base_head = pull.pop("base_head")
+ base_name = pull.pop("base_name")
+ base_tree = trees.get(base_head)
+ pull["tree"] = trees[pull["head"]]
+ pull["base_tree"] = base_tree
+ pull["base"] = f"{base_name}@{(base_tree or 'none')[:12]}"
+
return pulls