Skip to content

Commit 0f2d803

Browse files
authored
Switch to an outside action for pr approval (#4523)
1 parent e473452 commit 0f2d803

File tree

1 file changed

+12
-103
lines changed

1 file changed

+12
-103
lines changed

.github/workflows/pr-approval-check.yml

Lines changed: 12 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,111 +7,20 @@ on:
77
types: [opened, reopened, synchronize]
88

99
jobs:
10-
check-product-eng-approval:
11-
name: Check Product Eng Approval
10+
approval:
1211
runs-on: ubuntu-latest
1312
steps:
14-
- name: Check for Product Engineering approval
15-
uses: actions/github-script@v7
16-
env:
17-
ORG: trufflesecurity
18-
APPROVER_TEAM: product-eng
13+
- name: Mint installation token
14+
id: app-token
15+
uses: actions/create-github-app-token@v2
1916
with:
20-
github-token: ${{ secrets.PR_APPROVAL_CHECK }}
21-
script: |
22-
const { ORG: org, APPROVER_TEAM: team} = process.env
23-
const prettyTeamName = `@${org}/${team}`
17+
app-id: ${{ secrets.PR_APPROVAL_CHECK_APP_ID }}
18+
private-key: ${{ secrets.PR_APPROVAL_CHECK }}
2419

25-
async function status(state, msg) {
26-
await github.rest.repos.createCommitStatus({
27-
owner: context.repo.owner,
28-
repo: context.repo.repo,
29-
sha: context.payload.pull_request.head.sha,
30-
state: state,
31-
context: 'pr-approval-check',
32-
description: msg,
33-
});
34-
}
35-
36-
async function fail(msg) {
37-
core.setOutput(msg);
38-
console.error(msg)
39-
await status('failure', msg)
40-
process.exit(0);
41-
}
42-
43-
async function succeed(msg) {
44-
core.setOutput(msg);
45-
console.info(msg)
46-
await status('success', msg)
47-
process.exit(0);
48-
}
49-
50-
async function fatal(msg) {
51-
core.setFailed(msg);
52-
console.error(msg)
53-
await status('failure', msg)
54-
process.exit(1);
55-
}
56-
57-
58-
await status('pending', `Waiting for approval from ${prettyTeamName} team member`)
59-
60-
// reviews maps reviewer logins to their latest review
61-
let reviews = new Map();
62-
try {
63-
const iter = octokit.paginate.iterator(github.rest.pulls.listReviews, {
64-
owner: context.repo.owner,
65-
repo: context.repo.repo,
66-
pull_number: context.payload.pull_request.number,
67-
});
68-
69-
let pages = [];
70-
for await (const page of iter) {
71-
pages.push(page)
72-
}
73-
74-
const latestReview = (a, b) => new Date(a.submitted_at) > new Date(b.submitted_at) ? a : b;
75-
for await (const page of pages) {
76-
for (const review of page.data) {
77-
const login = review.user.login;
78-
reviews.set(login, reviews.has(login) ? latestReview(reviews.get(login), review) : review);
79-
}
80-
}
81-
} catch (error) {
82-
await fatal(`⚠️ Could not get reviews: ${error.status}`);
83-
}
84-
85-
let approved = false;
86-
let changeRequesters = [];
87-
for (const [login, review] of reviews) {
88-
try {
89-
const membership = await github.rest.teams.getMembershipForUserInOrg({
90-
org: org,
91-
team_slug: team,
92-
username: login,
93-
});
94-
95-
if (membership.data.state === 'active') {
96-
if (review.state === 'APPROVED') {
97-
approved = true;
98-
} else if (review.state === 'CHANGES_REQUESTED') {
99-
changeRequesters.push(login);
100-
}
101-
}
102-
103-
} catch (error) {
104-
if (error.status != 404) {
105-
await fatal(`⚠️ Could not determine membership for ${login} in ${prettyTeamName}: ${error.status}`)
106-
}
107-
}
108-
}
109-
110-
if (changeRequesters.length > 0) {
111-
await fail(`⚠️ Changes requested by: ${changeRequesters.map(login=>`@${login}`).join(", ")} on behalf of ${prettyTeamName}`);
112-
} else if (approved) {
113-
await succeed(`✅ Approved by ${prettyTeamName}`)
114-
} else {
115-
await fail(`⚠️ Requires approval from ${prettyTeamName}`)
116-
}
20+
- name: Require Product Eng approval
21+
uses: trufflesecurity/pr-approval-check@v1
22+
with:
23+
org: trufflesecurity
24+
approver_team: product-eng
25+
github_token: ${{ steps.app-token.outputs.token }}
11726

0 commit comments

Comments
 (0)