PR inactivity reminders #18
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: PR inactivity reminders | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 2 * * *" # Daily (UTC) – works only in upstream repo | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| manage-prs: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Send inactivity reminders | |
| uses: actions/github-script@v7 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| console.log("===== PR INACTIVITY REMINDER CHECK START ====="); | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const prs = await github.paginate( | |
| github.rest.pulls.list, | |
| { | |
| owner, | |
| repo, | |
| state: "open", | |
| per_page: 100 | |
| } | |
| ); | |
| console.log(`Total open PRs: ${prs.length}`); | |
| const now = new Date(); | |
| let reminder1Count = 0; | |
| let reminder2Count = 0; | |
| for (const pr of prs) { | |
| if (pr.draft) continue; | |
| const comments = await github.paginate( | |
| github.rest.issues.listComments, | |
| { | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| per_page: 100 | |
| } | |
| ); | |
| const lastActivityDate = | |
| comments.length > 0 | |
| ? new Date(comments[comments.length - 1].created_at) | |
| : new Date(pr.created_at); | |
| const inactivityDays = Math.floor( | |
| (now - lastActivityDate) / (1000 * 60 * 60 * 24) | |
| ); | |
| const reminder1Exists = comments.some(c => | |
| c.body.includes("Reminder 1") | |
| ); | |
| const reminder2Exists = comments.some(c => | |
| c.body.includes("Reminder 2") | |
| ); | |
| const mentions = [ | |
| `@${pr.user.login}`, | |
| ...pr.assignees.map(a => `@${a.login}`) | |
| ].join(" "); | |
| if (inactivityDays === 20 && !reminder1Exists) { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| body: `${mentions} | |
| **Reminder 1** | |
| This PR has had **no activity for 20 days**. | |
| Please respond to keep it active.` | |
| }); | |
| console.log(`Reminder 1 sent to PR #${pr.number}`); | |
| reminder1Count++; | |
| } | |
| else if (inactivityDays === 40 && !reminder2Exists) { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| body: `${mentions} | |
| **Reminder 2** | |
| This PR has had **no activity for 40 days**. | |
| Please update or respond to avoid future action.` | |
| }); | |
| console.log(`Reminder 2 sent to PR #${pr.number}`); | |
| reminder2Count++; | |
| } | |
| } | |
| console.log("===== SUMMARY ====="); | |
| console.log(`Reminder 1 sent: ${reminder1Count}`); | |
| console.log(`Reminder 2 sent: ${reminder2Count}`); | |
| console.log("===== PR INACTIVITY REMINDER CHECK END ====="); |