From 361b9a1ed8b9da4c508d4291db2902e9c8cb9261 Mon Sep 17 00:00:00 2001 From: Elliott de Launay Date: Mon, 15 Jun 2026 13:32:04 +0000 Subject: [PATCH] fix(gha): updating stale workflow logic --- .github/workflows/label-pr-review-state.yml | 105 +++++++++++--------- .github/workflows/stale.yml | 4 +- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/.github/workflows/label-pr-review-state.yml b/.github/workflows/label-pr-review-state.yml index 2c83ecc6a..57ea7015d 100644 --- a/.github/workflows/label-pr-review-state.yml +++ b/.github/workflows/label-pr-review-state.yml @@ -6,76 +6,89 @@ on: workflow_dispatch: permissions: - pull-requests: read - issues: write + pull-requests: write + +concurrency: + group: label-pr-review-state + cancel-in-progress: false jobs: reconcile: runs-on: ubuntu-latest steps: - name: Reconcile PR review state labels - uses: actions/github-script@v7 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const { owner, repo } = context.repo; const stateLabels = ['awaiting-author', 'awaiting-review']; + const failures = []; const prs = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', per_page: 100, }); for (const pr of prs) { - const reviews = await github.paginate(github.rest.pulls.listReviews, { - owner, repo, pull_number: pr.number, per_page: 100, - }); + try { + const reviews = await github.paginate(github.rest.pulls.listReviews, { + owner, repo, pull_number: pr.number, per_page: 100, + }); - // Reviews are returned chronologically, so later entries replace - // each reviewer's earlier decision. - const latest = new Map(); - for (const r of reviews) { - if (r.state !== 'COMMENTED') { - latest.set(r.user.login, r); + // Reviews are returned chronologically, so later entries replace + // each reviewer's earlier decision. + const latest = new Map(); + for (const r of reviews) { + if (r.state !== 'COMMENTED') { + latest.set(r.user.login, r); + } } - } - const changeRequestReviewers = [...latest.entries()] - .filter(([, review]) => review.state === 'CHANGES_REQUESTED') - .map(([login]) => login); - const requestedReviewers = new Set( - pr.requested_reviewers.map(reviewer => reviewer.login), - ); + const changeRequestReviewers = [...latest.entries()] + .filter(([, review]) => review.state === 'CHANGES_REQUESTED') + .map(([login]) => login); + const requestedReviewers = new Set( + pr.requested_reviewers.map(reviewer => reviewer.login), + ); - let desiredLabel = null; - if (changeRequestReviewers.length > 0) { - desiredLabel = changeRequestReviewers.every( - reviewer => requestedReviewers.has(reviewer), - ) - ? 'awaiting-review' - : 'awaiting-author'; - } + let desiredLabel = null; + if (changeRequestReviewers.length > 0) { + desiredLabel = changeRequestReviewers.every( + reviewer => requestedReviewers.has(reviewer), + ) + ? 'awaiting-review' + : 'awaiting-author'; + } - const currentLabels = new Set(pr.labels.map(label => label.name)); - for (const label of stateLabels) { - if (label !== desiredLabel && currentLabels.has(label)) { - await github.rest.issues.removeLabel({ - owner, repo, issue_number: pr.number, name: label, + const currentLabels = new Set(pr.labels.map(label => label.name)); + for (const label of stateLabels) { + if (label !== desiredLabel && currentLabels.has(label)) { + await github.rest.issues.removeLabel({ + owner, repo, issue_number: pr.number, name: label, + }); + } + } + + if (desiredLabel && !currentLabels.has(desiredLabel)) { + await github.rest.issues.addLabels({ + owner, repo, issue_number: pr.number, labels: [desiredLabel], }); } - } - if (desiredLabel && !currentLabels.has(desiredLabel)) { - await github.rest.issues.addLabels({ - owner, repo, issue_number: pr.number, labels: [desiredLabel], - }); + if ( + desiredLabel !== 'awaiting-author' && + currentLabels.has('stale-awaiting-author') + ) { + await github.rest.issues.removeLabel({ + owner, repo, issue_number: pr.number, + name: 'stale-awaiting-author', + }); + } + } catch (error) { + failures.push(`#${pr.number}: ${error.message}`); + core.error(`Failed to reconcile PR #${pr.number}: ${error.message}`); } + } - if ( - desiredLabel !== 'awaiting-author' && - currentLabels.has('stale-awaiting-author') - ) { - await github.rest.issues.removeLabel({ - owner, repo, issue_number: pr.number, - name: 'stale-awaiting-author', - }); - } + if (failures.length > 0) { + core.setFailed(`Failed to reconcile ${failures.length} PR(s): ${failures.join('; ')}`); } diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3e51b4485..4843e0613 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -14,7 +14,7 @@ jobs: name: 60-day inactivity runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} @@ -38,7 +38,7 @@ jobs: name: 14-day author inactivity after requested changes runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }}