[llvm] [Github] Account for cross-repo PRs in prune-unused-branches (PR #181232)

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 13 12:00:11 PST 2026


https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/181232

>From 43405b90c7d0124a2eaab78e7df5fc6d227c1a0f Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Thu, 12 Feb 2026 20:31:23 +0000
Subject: [PATCH 1/4] [Github] Account for cross-repo PRs in
 prune-unused-branches

Some users (as reported in the discourse thread) use user branches
purely as a diff base for cross repo pull requests. This patch makes it
so that we do not delete branches that are used in this way.
---
 .github/workflows/prune-unused-branches.py | 23 ++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
index ac8d87f4241e0..bd4ae90f7382d 100644
--- a/.github/workflows/prune-unused-branches.py
+++ b/.github/workflows/prune-unused-branches.py
@@ -22,11 +22,11 @@ def branch_filter(branch_name):
     return [branch.replace("remotes/origin/", "") for branch in filtered_branches]
 
 
-def get_branches_from_open_prs(github_token) -> list[str]:
+def query_prs(github_token, extra_query_criteria):
     gh = github.Github(auth=github.Auth.Token(github_token))
-    query = """
+    query_template = """
   query ($after: String) {
-    search(query: "is:pr repo:llvm/llvm-project is:open head:users/", type: ISSUE, first: 100, after: $after) {
+    search(query: "is:pr repo:llvm/llvm-project is:open {extra_query_criteria}", type: ISSUE, first: 100, after: $after) {
       nodes {
         ... on PullRequest {
           baseRefName
@@ -41,6 +41,7 @@ def get_branches_from_open_prs(github_token) -> list[str]:
       }
     }
   }"""
+    query = query_template.format(extra_query_criteria=extra_query_criteria)
     pr_data = []
     has_next_page = True
     variables = {"after": None}
@@ -54,13 +55,27 @@ def get_branches_from_open_prs(github_token) -> list[str]:
         pr_data.extend(prs)
         print(f"Processed {len(prs)} PRs")
 
+    return pr_data
+
+
+def get_branches_from_open_prs(github_token) -> list[str]:
+    pr_data = []
+    pr_data.extend(query_prs(github_token, "head:users/"))
+    # We need to explicitly check cases where the base is a user branch to
+    # ensure we capture branches that are used as a diff base for cross-repo
+    # PRs.
+    pr_data.extend(query_prs(github_token, "base:users/"))
+
     user_branches = []
     for pr in pr_data:
         if not pr["isCrossRepository"]:
             if pr["baseRefName"] != "main":
                 user_branches.append(pr["baseRefName"])
             user_branches.append(pr["headRefName"])
-    return user_branches
+        else:
+            assert pr["baseRefName"].startswith("users/")
+            user_branches.append(pr["baseRefName"])
+    return list(set(user_branches))
 
 
 def get_user_branches_to_remove(

>From 7ba412c98dded869367a1b6d23c6000b92951afc Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Thu, 12 Feb 2026 20:57:19 +0000
Subject: [PATCH 2/4] add comment

---
 .github/workflows/prune-unused-branches.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
index bd4ae90f7382d..60198b6512225 100644
--- a/.github/workflows/prune-unused-branches.py
+++ b/.github/workflows/prune-unused-branches.py
@@ -75,6 +75,7 @@ def get_branches_from_open_prs(github_token) -> list[str]:
         else:
             assert pr["baseRefName"].startswith("users/")
             user_branches.append(pr["baseRefName"])
+    # Convert to a set to ensure we have no duplicates.
     return list(set(user_branches))
 
 

>From af2ce97a12f5ae0e37edd0781e4ca9114554e93d Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Fri, 13 Feb 2026 19:01:24 +0000
Subject: [PATCH 3/4] feedback

---
 .github/workflows/prune-unused-branches.py | 36 +++++++++++-----------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
index 60198b6512225..79b4b11ebff4b 100644
--- a/.github/workflows/prune-unused-branches.py
+++ b/.github/workflows/prune-unused-branches.py
@@ -22,26 +22,26 @@ def branch_filter(branch_name):
     return [branch.replace("remotes/origin/", "") for branch in filtered_branches]
 
 
-def query_prs(github_token, extra_query_criteria):
+def query_prs(github_token, extra_query_criteria) -> list[str]:
     gh = github.Github(auth=github.Auth.Token(github_token))
     query_template = """
-  query ($after: String) {
-    search(query: "is:pr repo:llvm/llvm-project is:open {extra_query_criteria}", type: ISSUE, first: 100, after: $after) {
-      nodes {
-        ... on PullRequest {
-          baseRefName
-          headRefName
-          isCrossRepository
-          number
-        }
-      }
-      pageInfo {
-        hasNextPage
-        endCursor
-      }
-    }
-  }"""
-    query = query_template.format(extra_query_criteria=extra_query_criteria)
+    query ($after: String) {{
+        search(query: "is:pr repo:llvm/llvm-project is:open {query_param}", type: ISSUE, first: 100, after: $after) {{
+        nodes {{
+            ... on PullRequest {{
+            baseRefName
+            headRefName
+            isCrossRepository
+            number
+            }}
+        }}
+        pageInfo {{
+            hasNextPage
+            endCursor
+        }}
+        }}
+    }}"""
+    query = query_template.format(query_param=extra_query_criteria)
     pr_data = []
     has_next_page = True
     variables = {"after": None}

>From fe29738039c067c0104bec03cb2769253ca8b385 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Fri, 13 Feb 2026 19:59:55 +0000
Subject: [PATCH 4/4] fix

---
 .github/workflows/prune-unused-branches.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
index 79b4b11ebff4b..2e5d04ccdb256 100644
--- a/.github/workflows/prune-unused-branches.py
+++ b/.github/workflows/prune-unused-branches.py
@@ -73,7 +73,10 @@ def get_branches_from_open_prs(github_token) -> list[str]:
                 user_branches.append(pr["baseRefName"])
             user_branches.append(pr["headRefName"])
         else:
-            assert pr["baseRefName"].startswith("users/")
+            # We want to skip cross-repo PRs where someone has simply used a
+            # users/ branch naming scheme for a branch in their fork.
+            if pr["baseRefName"] == "main":
+                continue
             user_branches.append(pr["baseRefName"])
     # Convert to a set to ensure we have no duplicates.
     return list(set(user_branches))



More information about the llvm-commits mailing list