diff --git a/.github/workflows/review-claims.yml b/.github/workflows/review-claims.yml index 7385fbb083..c6e495d92e 100644 --- a/.github/workflows/review-claims.yml +++ b/.github/workflows/review-claims.yml @@ -12,7 +12,7 @@ on: pull_request_review: types: [submitted] schedule: - - cron: "23 */6 * * *" + - cron: "23 * * * *" workflow_dispatch: permissions: @@ -138,8 +138,16 @@ jobs: } for (const name of present) { if (latestLabeler[name] === reviewer) { - await github.rest.issues.removeLabel({ owner, repo, issue_number: pr.number, name }); - core.info(`Removed ${name}: claimer ${reviewer} submitted their review.`); + try { + await github.rest.issues.removeLabel({ owner, repo, issue_number: pr.number, name }); + core.info(`Removed ${name}: claimer ${reviewer} submitted their review.`); + } catch (e) { + if (e.status === 403) { + core.warning(`Token is read-only in this PR context; the hourly sweep will release ${name} instead.`); + } else { + throw e; + } + } } else { core.info(`Kept ${name}: claimed by ${latestLabeler[name] ?? 'unknown'}, review came from ${reviewer}.`); } @@ -192,12 +200,18 @@ jobs: let removedAny = false; for (const name of present) { const info = latest[name]; - if (!info || now - info.at < MAX_AGE_MS) continue; + if (!info) continue; const reviewedSince = reviews.some((r) => r.user && r.user.login === info.actor && Date.parse(r.submitted_at) > info.at && (r.state === 'APPROVED' || r.state === 'CHANGES_REQUESTED')); - if (reviewedSince) continue; + if (reviewedSince) { + await github.rest.issues.removeLabel({ owner, repo, issue_number: pr.number, name }) + .catch((e) => core.info(`PR #${pr.number}: ${name} release skipped: ${e.message}`)); + core.info(`PR #${pr.number}: released ${name} — claimer ${info.actor} already reviewed (backstop for restricted-token contexts).`); + continue; + } + if (now - info.at < MAX_AGE_MS) continue; await github.rest.issues.removeLabel({ owner, repo, issue_number: pr.number, name }) .catch((e) => core.info(`PR #${pr.number}: ${name} removal skipped: ${e.message}`)); removedAny = true;