[llvm] [Github] Add initial workflow to prune unused user branches (PR #175693)

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 18 12:57:38 PST 2026


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

>From e05438475e1ed95ce063b6e6969354dd77399840 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Tue, 13 Jan 2026 01:40:45 +0000
Subject: [PATCH 1/3] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .github/workflows/prune-branches.yml       | 30 ++++++++
 .github/workflows/prune-unused-branches.py | 89 ++++++++++++++++++++++
 2 files changed, 119 insertions(+)
 create mode 100644 .github/workflows/prune-branches.yml
 create mode 100644 .github/workflows/prune-unused-branches.py

diff --git a/.github/workflows/prune-branches.yml b/.github/workflows/prune-branches.yml
new file mode 100644
index 0000000000000..9a21a9826e486
--- /dev/null
+++ b/.github/workflows/prune-branches.yml
@@ -0,0 +1,30 @@
+name: Prune Branches
+
+permissions:
+  contents: read
+
+on:
+  pull_request:
+    paths:
+     - .github/workflows/prune-branches.yml
+  schedule:
+    - cron: '0 8 * * *'
+
+jobs:
+  prune-branches:
+    name: Prune Branches
+    if: github.repository_owner == 'llvm'
+    runs-on: ubuntu-24.04
+    steps:
+      - name: Fetch LLVM sources
+        uses: actions/checkout at 8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
+        with:
+          fetch-depth: 0
+      - name: Install dependencies
+        run: |
+          pip install --require-hashes -r ./llvm/utils/git/requirements.txt
+      - name: Run Script
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: |
+          python3 .github/workflows/prune-unused-branches.py
diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
new file mode 100644
index 0000000000000..ab09faa63acd2
--- /dev/null
+++ b/.github/workflows/prune-unused-branches.py
@@ -0,0 +1,89 @@
+import subprocess
+import os
+
+import github
+
+
+def get_branches() -> list[str]:
+    git_process = subprocess.run(
+        ["git", "branch", "--all"], stdout=subprocess.PIPE, check=True
+    )
+    branches = [
+        branch.strip() for branch in git_process.stdout.decode("utf-8").split("\n")
+    ]
+
+    def branch_filter(branch_name):
+        return "users/" in branch_name or "revert-" in branch_name
+
+    filtered_branches = list(filter(branch_filter, branches))
+    return [branch.replace("remotes/origin/", "") for branch in filtered_branches]
+
+
+def get_branches_from_open_prs(github_token) -> list[str]:
+    gh = github.Github(auth=github.Auth.Token(github_token))
+    query = """
+  query ($after: String) {
+    search(query: "is:pr repo:llvm/llvm-project is:open head:users/", type: ISSUE, first: 100, after: $after) {
+      nodes {
+        ... on PullRequest {
+          baseRefName
+          headRefName
+          isCrossRepository
+          number
+        }
+      }
+      pageInfo {
+        hasNextPage
+        endCursor
+      }
+    }
+  }"""
+    pr_data = []
+    has_next_page = True
+    variables = {"after": None}
+    while has_next_page:
+        _, res_data = gh.requester.graphql_query(query, variables=variables)
+        import json
+
+        with open("/tmp/test.json", "w") as test_file:
+            json.dump(res_data, test_file)
+        page_info = res_data["data"]["search"]["pageInfo"]
+        has_next_page = page_info["hasNextPage"]
+        if has_next_page:
+            variables["after"] = page_info["endCursor"]
+        prs = res_data["data"]["search"]["nodes"]
+        pr_data.extend(prs)
+        print(f"Processed {len(prs)} PRs")
+
+    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
+
+
+def get_user_branches_to_remove(
+    user_branches: list[str], user_branches_from_prs: list[str]
+) -> list[str]:
+    user_branches_to_remove = set(user_branches)
+    for pr_user_branch in set(user_branches_from_prs):
+        user_branches_to_remove.remove(pr_user_branch)
+    return list(user_branches_to_remove)
+
+
+def main(github_token):
+    user_branches = get_branches()
+    user_branches_from_prs = get_branches_from_open_prs(github_token)
+    print(f"Found {len(user_branches)} user branches in the repository")
+    print(f"Found {len(user_branches_from_prs)} user branches associated with PRs")
+    user_branches_to_remove = get_user_branches_to_remove(
+        user_branches, user_branches_from_prs
+    )
+    print(f"Deleting {len(user_branches_to_remove)} user branches.")
+    print(user_branches_to_remove)
+
+
+if __name__ == "__main__":
+    main(os.environ["GITHUB_TOKEN"])

>From 9642bc5849198ff577457d0d0267fcdb20e57f62 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Tue, 13 Jan 2026 04:34:11 +0000
Subject: [PATCH 2/3] feedback

Created using spr 1.3.7
---
 .github/workflows/prune-unused-branches.py | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/.github/workflows/prune-unused-branches.py b/.github/workflows/prune-unused-branches.py
index ab09faa63acd2..a784cb6db777c 100644
--- a/.github/workflows/prune-unused-branches.py
+++ b/.github/workflows/prune-unused-branches.py
@@ -43,10 +43,6 @@ def get_branches_from_open_prs(github_token) -> list[str]:
     variables = {"after": None}
     while has_next_page:
         _, res_data = gh.requester.graphql_query(query, variables=variables)
-        import json
-
-        with open("/tmp/test.json", "w") as test_file:
-            json.dump(res_data, test_file)
         page_info = res_data["data"]["search"]["pageInfo"]
         has_next_page = page_info["hasNextPage"]
         if has_next_page:

>From 1656a0792a07a882b5d817bdbbdc51bb99b27160 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sun, 18 Jan 2026 20:57:26 +0000
Subject: [PATCH 3/3] fix

Created using spr 1.3.7
---
 .github/workflows/prune-branches.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/prune-branches.yml b/.github/workflows/prune-branches.yml
index 9a21a9826e486..f8dce5e1e54c8 100644
--- a/.github/workflows/prune-branches.yml
+++ b/.github/workflows/prune-branches.yml
@@ -1,4 +1,4 @@
-name: Prune Branches
+name: Prune Unused Branches
 
 permissions:
   contents: read
@@ -8,7 +8,7 @@ on:
     paths:
      - .github/workflows/prune-branches.yml
   schedule:
-    - cron: '0 8 * * *'
+    - cron: '0 8 * * *' # Runs daily at 08:00 UTC.
 
 jobs:
   prune-branches:



More information about the llvm-commits mailing list