Close Stale closing-soon PRs #99
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Close Stale closing-soon PRs | |
| on: | |
| schedule: | |
| - cron: '0 */6 * * *' # every 6 hours | |
| workflow_dispatch: | |
| jobs: | |
| close-stale: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| steps: | |
| - uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const label = 'closing-soon'; | |
| const staleDays = 1; | |
| const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000); | |
| const prs = await github.rest.pulls.list({ | |
| ...context.repo, | |
| state: 'open', | |
| per_page: 100 | |
| }); | |
| for (const pr of prs.data) { | |
| if (!pr.labels.some(l => l.name === label)) continue; | |
| // Find when the label was added | |
| const events = await github.rest.issues.listEvents({ | |
| ...context.repo, | |
| issue_number: pr.number, | |
| per_page: 100 | |
| }); | |
| const labelEvent = events.data | |
| .filter(e => e.event === 'labeled' && e.label?.name === label) | |
| .pop(); | |
| if (!labelEvent) continue; | |
| const labeledAt = new Date(labelEvent.created_at); | |
| if (labeledAt > cutoff) continue; | |
| await github.rest.issues.createComment({ | |
| ...context.repo, | |
| issue_number: pr.number, | |
| body: `🔒 Auto-closing: this PR has had the \`${label}\` label for more than ${staleDays} days without activity from the author.\n\nIf you'd like to continue working on this, please submit a new PR and link to this one if necessary.` | |
| }); | |
| await github.rest.pulls.update({ | |
| ...context.repo, | |
| pull_number: pr.number, | |
| state: 'closed' | |
| }); | |
| console.log(`Closed PR #${pr.number} (labeled ${labeledAt.toISOString()})`); | |
| } |