Skip to content

pr-approval-check: refactor, fix pagination, fix approval logic #21

pr-approval-check: refactor, fix pagination, fix approval logic

pr-approval-check: refactor, fix pagination, fix approval logic #21

name: PR Approval Check
on:
pull_request_review:
types: [submitted, dismissed]
pull_request:
types: [opened, reopened, synchronize]
jobs:
check-product-eng-approval:
name: Check Product Eng Approval
runs-on: ubuntu-latest
permissions:
statuses: write
pull-requests: write
steps:
- name: Check for Product Engineering approval
uses: actions/github-script@v7
env:
ORG: trufflesecurity
APPROVER_TEAM: product-eng
with:
# github-token: ${{ secrets.GH_REVIEW_TOKEN }}
script: |
const { ORG: org, APPROVER_TEAM: team} = process.env
const prettyTeamName = `@${org}/${team}`
const children = await github.rest.teams.listChildInOrg({
org: org,
team_slug: team,
});
async function status(state, msg) {
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state: state,
context: `product-eng-approval-${team}`,
description: msg,
});
}
async function fail(msg) {
core.setFailed(msg);
console.error(msg)
await status('failure', msg)
process.exit(1);
}
async function succeed(msg) {
core.setOutput(msg);
console.info(msg)
await status('success', msg)
process.exit(0);
}
await status('pending', `Waiting for approval from ${prettyTeamName} team member`)
let latestReviews = {};
try {
const iter = octokit.paginate.iterator(github.rest.pulls.listReviews, {
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
let pages = [];
for await (const p of iter) {
pages.push(p)
}
const laterThan = (a, b) => new Date(a.submitted_at) > new Date(b.submitted_at) ? a : b;
latestReviews = pages.reduce((acc, page) => page.data.reduce((a, r) => ((!(r.user.login in a) || laterThan(r, a[r.user.login]) ? { ...a, [r.user.login]: r } : a)), acc) , {})
} catch (error) {
await fail(`⚠️ Could not get reviews: ${error.status}`);
}
for (const reviewer in latestReviews) {
if (latestReviews[reviewer].state !== 'APPROVED') {
continue
}
try {
const membership = await github.rest.teams.getMembershipForUserInOrg({
org: org,
team_slug: team,
username: reviewer,
});
if (membership.data.state == 'active') {
await succeed(`✅ Approved by ${reviewer} on behalf of ${prettyTeamName}`)
}
} catch (error) {
if (error.status != 404) {
await fail(`⚠️ Could not determine membership for ${reviewer} in ${prettyTeamName}: ${error.status}`)
}
}
}
await fail(`⚠️ No approvers found from ${prettyTeamName}`)