From 45647c15d307cb5920b7999cdcba8b1306a925ba Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Wed, 25 Mar 2026 10:25:56 -0600 Subject: [PATCH] Added github actions to close stale issues automatically. Hopefully it doesnt break things --- .github/workflows/stale-issues.yml | 100 +++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 .github/workflows/stale-issues.yml diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml new file mode 100644 index 0000000..2072345 --- /dev/null +++ b/.github/workflows/stale-issues.yml @@ -0,0 +1,100 @@ +name: Close Stale Issues and PRs + +on: + schedule: + - cron: '0 0 * * *' # Runs daily at midnight UTC + workflow_dispatch: # Allow manual triggering + +jobs: + close-stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - name: Close stale issues + uses: actions/github-script@v7 + with: + script: | + const sixMonthsAgo = new Date(); + sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6); + + let closedIssues = 0; + let closedPRs = 0; + + // --- Close stale issues --- + const issueIterator = github.paginate.iterator( + github.rest.issues.listForRepo, + { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100, + } + ); + + for await (const { data: items } of issueIterator) { + for (const issue of items) { + // Skip pull requests (issues API returns both) + if (issue.pull_request) continue; + + if (new Date(issue.updated_at) < sixMonthsAgo) { + console.log(`Closing issue #${issue.number}: "${issue.title}" (last activity: ${issue.updated_at})`); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: `This issue has been automatically closed due to inactivity. It has had no activity for 6 months.\n\nIf this issue is still relevant, please feel free to reopen it with updated information or context. We apologize for any inconvenience.`, + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'not_planned', + }); + + closedIssues++; + } + } + } + + // --- Close stale pull requests --- + const prIterator = github.paginate.iterator( + github.rest.pulls.list, + { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + per_page: 100, + } + ); + + for await (const { data: prs } of prIterator) { + for (const pr of prs) { + if (new Date(pr.updated_at) < sixMonthsAgo) { + console.log(`Closing PR #${pr.number}: "${pr.title}" (last activity: ${pr.updated_at})`); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body: `This pull request has been automatically closed due to inactivity. It has had no activity for 6 months.\n\nIf this PR is still relevant, please feel free to reopen it with updated information or context. We apologize for any inconvenience.`, + }); + + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + state: 'closed', + }); + + closedPRs++; + } + } + } + + console.log(`Closed ${closedIssues} stale issue(s) and ${closedPRs} stale PR(s).`);