Promote "status:"-label to "ready to merge" if soaked for long enough #2481
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: Promote "status:"-label to "ready to merge" if soaked for long enough | |
| on: | |
| schedule: | |
| - cron: '0 * * * *' # every hour, on the hour | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| promote_ready_to_merge: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Promote approved PRs to "ready to merge" | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const owner = context.repo.owner | |
| const repo = context.repo.repo | |
| const now = new Date() | |
| // 1. Search for open PRs with "status:approved" | |
| const searchQuery = `repo:${owner}/${repo} is:pr is:open label:"status:approved"` | |
| const { data: searchResults } = await github.rest.search.issuesAndPullRequests({ q: searchQuery }) | |
| for (const pr of searchResults.items) { | |
| const prNumber = pr.number | |
| // Get full PR info (for timestamps) | |
| const { data: prData } = await github.rest.pulls.get({ | |
| owner, | |
| repo, | |
| pull_number: prNumber | |
| }) | |
| const createdAt = new Date(prData.created_at) | |
| const hoursSinceCreation = (now - createdAt) / (1000 * 60 * 60) | |
| if (hoursSinceCreation < 24) { | |
| core.info(`Skipping #${prNumber} (created ${hoursSinceCreation.toFixed(1)}h ago)`) | |
| continue | |
| } | |
| // Find the last "status:" label change (via timeline events) | |
| const { data: events } = await github.rest.issues.listEvents({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| per_page: 100 | |
| }) | |
| const lastStatusChange = events | |
| .filter(e => e.event === 'labeled' || e.event === 'unlabeled') | |
| .filter(e => e.label && e.label.name.startsWith('status:')) | |
| .sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0] | |
| if (lastStatusChange) { | |
| const hoursSinceStatusChange = (now - new Date(lastStatusChange.created_at)) / (1000 * 60 * 60) | |
| if (hoursSinceStatusChange < 12) { | |
| core.info(`Skipping #${prNumber} (status changed ${hoursSinceStatusChange.toFixed(1)}h ago)`) | |
| continue | |
| } | |
| } | |
| // 2. Conditions met → remove "status:approved", add "status:ready to merge" | |
| try { | |
| await github.rest.issues.removeLabel({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| name: 'status:approved' | |
| }).catch(() => {}) | |
| await github.rest.issues.addLabels({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| labels: ['status:ready to merge'] | |
| }) | |
| core.info(`Promoted #${prNumber} to status:ready to merge`) | |
| } catch (err) { | |
| core.warning(`Failed to update #${prNumber}: ${err.message}`) | |
| } | |
| } |