From e2d499cca69a193bf3a0996426c5b3ccb94b2c97 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Sun, 22 Mar 2026 11:02:34 -0500 Subject: [PATCH] ci: add workflow to auto-close stale PRs (#409) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Adds a daily workflow that auto-closes PRs inactive for 30+ days - Skips PRs authored by jdx or labeled `keep-open` - Includes different close messages depending on CI status (failing vs passing) Ported from jdx/mise. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- > [!NOTE] > **Low Risk** > Low risk: adds a standalone GitHub Actions workflow that only closes eligible open PRs and does not affect application/runtime code. > > **Overview** > Adds a new GitHub Actions workflow (`.github/workflows/pr-closer.yml`) that runs daily (and manually) to close PRs with no activity for 30+ days. > > The job filters out PRs authored by `jdx` or labeled `keep-open`, and posts a different close comment when CI checks are failing vs passing. > > Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 959b5b27b25da4128692186a781052cbe494afc7. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot). --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .github/workflows/pr-closer.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/pr-closer.yml diff --git a/.github/workflows/pr-closer.yml b/.github/workflows/pr-closer.yml new file mode 100644 index 0000000..7c0cc80 --- /dev/null +++ b/.github/workflows/pr-closer.yml @@ -0,0 +1,31 @@ +name: pr-closer + +on: + schedule: + - cron: "0 0 * * *" # daily at midnight + workflow_dispatch: + +jobs: + close-stale-prs: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Close stale PRs + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr list -R "${{ github.repository }}" --state open --json number,author,labels,updatedAt,statusCheckRollup --limit 100 | \ + jq -r '.[] | select( + (.updatedAt | fromdateiso8601) < (now - 30*24*60*60) and + .author.login != "jdx" and + ([.labels[].name] | index("keep-open") | not) + ) | [.number, (if (.statusCheckRollup | length > 0) and (.statusCheckRollup | any(.conclusion == "FAILURE" or .conclusion == "failure")) then "failing" else "passing" end)] | @tsv' | \ + while read -r pr status; do + echo "Closing PR #$pr (checks: $status)" + if [ "$status" = "failing" ]; then + gh pr close "$pr" -R "${{ github.repository }}" -c "This PR has been open for more than 30 days without activity. Note: CI checks were failing, which may be why it wasn't reviewed. Feel free to reopen or create a new PR if you'd like to continue working on this." + else + gh pr close "$pr" -R "${{ github.repository }}" -c "This PR has been open for more than 30 days without activity. Feel free to reopen or create a new PR if you'd like to continue working on this." + fi + done