Process stale issues and PRs #383
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: 'Process stale issues and PRs' | |
| on: | |
| schedule: | |
| - cron: '21 0 * * *' | |
| workflow_dispatch: | |
| pull_request: | |
| types: [converted_to_draft] | |
| permissions: {} | |
| jobs: | |
| stale: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| steps: | |
| - name: Process stale issues and PRs | |
| uses: actions/stale@v9.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| stale-issue-message: "As a part of this repository's maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 7 days with no activity this issue will be automatically closed." | |
| close-issue-message: 'This issue was closed because it has been 14 days with no activity.' | |
| operations-per-run: 140 | |
| days-before-stale: -1 | |
| days-before-close: -1 | |
| days-before-issue-stale: 7 | |
| days-before-issue-close: 7 | |
| stale-issue-label: 'status: stale' | |
| exempt-issue-labels: 'type: enhancement' | |
| only-issue-labels: 'needs: author feedback' | |
| close-issue-label: "status: can't reproduce" | |
| days-before-pr-stale: 30 | |
| days-before-pr-close: 14 | |
| stale-pr-label: 'status: stale' | |
| only-pr-labels: 'needs: author feedback' | |
| stale-pr-message: "As a part of this repository's maintenance, this PR is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 14 days with no activity this PR will be automatically closed." | |
| close-pr-message: 'This PR was closed because it has been 1.5 months with no activity.' | |
| delete-branch: true | |
| ascending: true | |
| - name: Process stale flaky tests issues | |
| uses: actions/stale@v9.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| only-issue-labels: 'metric: flaky e2e test' | |
| exempt-issue-labels: 'type: skipped test' | |
| days-before-stale: -1 | |
| days-before-close: -1 | |
| days-before-issue-stale: 5 | |
| days-before-issue-close: 2 | |
| stale-issue-label: 'status: stale' | |
| stale-issue-message: 'This issue is being marked as stale due to inactivity. It will be auto-closed if no further activity occurs within the next 2 days.' | |
| close-issue-message: 'Auto-closed due to inactivity. Please re-open if you believe this issue is still valid.' | |
| close-issue-reason: 'not_planned' | |
| remove-stale-when-updated: true | |
| exempt-all-assignees: false | |
| enable-statistics: true | |
| ascending: true | |
| operations-per-run: 120 | |
| - name: Remove stale PR approvals (over 30 days old) | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 | |
| with: | |
| script: | | |
| const thirtyDaysAgo = new Date(); | |
| thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); | |
| console.log(`Checking for approvals before: ${thirtyDaysAgo.toISOString()}`); | |
| const prs = await github.paginate(github.rest.pulls.list, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| per_page: 100 | |
| }); | |
| for (const pr of prs) { | |
| const reviews = await github.paginate(github.rest.pulls.listReviews, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number | |
| }); | |
| // Find the latest approval date for this PR | |
| let latestApproval = null; | |
| const approvalReviews = []; | |
| for (const review of reviews) { | |
| if (review.state === 'APPROVED') { | |
| const reviewDate = new Date(review.submitted_at); | |
| approvalReviews.push(review); | |
| if (!latestApproval || reviewDate > latestApproval) { | |
| latestApproval = reviewDate; | |
| } | |
| } | |
| } | |
| // Process only if we found any approvals | |
| if (latestApproval) { | |
| console.log(`PR #${pr.number} latest approval on ${latestApproval.toISOString()}`); | |
| if (latestApproval < thirtyDaysAgo) { | |
| console.log(`Found ${approvalReviews.length} approvals to dismiss on PR #${pr.number} (latest approval was on ${latestApproval.toISOString()})`); | |
| // Dismiss all approvals | |
| for (const review of approvalReviews) { | |
| console.log(`Dismissing approval from ${review.user.login}`); | |
| await github.rest.pulls.dismissReview({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number, | |
| review_id: review.id, | |
| message: 'This approval has been dismissed due to being stale (latest PR approval was 30+ days old). Please request a new review.' | |
| }); | |
| } | |
| } else { | |
| console.log(`Keeping approvals on PR #${pr.number} (latest approval on ${latestApproval.toISOString()})`); | |
| } | |
| } | |
| } | |
| remove-draft-approvals: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| pull-requests: write | |
| if: github.event_name == 'pull_request' && github.event.action == 'converted_to_draft' | |
| steps: | |
| - name: Remove approvals from draft PR | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 | |
| with: | |
| script: | | |
| const pr = context.payload.pull_request; | |
| const reviews = await github.paginate(github.rest.pulls.listReviews, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number | |
| }); | |
| for (const review of reviews) { | |
| if (review.state === 'APPROVED') { | |
| console.log(`Dismissing approval on draft PR #${pr.number} from ${review.user.login}`); | |
| await github.rest.pulls.dismissReview({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr.number, | |
| review_id: review.id, | |
| message: 'This approval has been dismissed due to the PR being moved to draft status. Please request a new review when ready.' | |
| }); | |
| } | |
| } |