1
1
name : Require Jump + Anza approval
2
2
3
- # ────── trigger on every meaningful PR event ──────
4
3
on :
5
4
pull_request :
6
- types : [opened, reopened, synchronize, ready_for_review, converted_to_draft]
5
+ types :
6
+ - opened
7
+ - reopened
8
+ - synchronize
9
+ - ready_for_review
10
+ - converted_to_draft
7
11
pull_request_review :
8
12
types : [submitted, dismissed, edited]
9
13
10
- # built-in token is enough (repo-only API)
11
14
permissions :
12
15
contents : read
13
16
pull-requests : read
@@ -20,59 +23,63 @@ jobs:
20
23
uses : actions/github-script@v7
21
24
with :
22
25
script : |
23
- // <-- globals github, context, core are injected by github-script -->
26
+ // globals github, context, core are injected by github-script
24
27
25
- // ──────── 1. MANUAL ROSTERS – edit as needed ────────
28
+ // ──────────── 1. MANUAL ROSTERS ──── ────────
26
29
const jumpApprovers = ['jacobcreech', 'topointon-jump', '0x0ece'];
27
30
const anzaApprovers = ['benhawkins18', 'tigarcia', 't-nelson', 'sakridge'];
28
- // ─────────────────────────────────────────────────────
31
+ // ───────────────────────────────────────────
29
32
30
33
const pr = context.payload.pull_request;
31
- if (!pr) {
32
- core.setFailed('No pull_request context'); return;
33
- }
34
+ if (!pr) { core.setFailed('No pull_request context'); return; }
34
35
35
- // 2. pull every review on this PR
36
+ // 2. fetch every review on this PR
36
37
const { data: reviews } = await github.rest.pulls.listReviews({
37
38
owner: context.repo.owner,
38
39
repo: context.repo.repo,
39
40
pull_number: pr.number,
40
41
per_page: 100
41
42
});
42
43
43
- // ──────── DEBUG BLOCK #1 – raw reviews ────────
44
+ // DEBUG 1: raw events
44
45
core.info('=== Raw review events ===');
45
46
reviews.forEach(r =>
46
47
core.info(`${r.user.login} -> ${r.state} @ ${r.submitted_at}`));
47
- // ───────────────────────────────────────────────
48
48
49
- // 3. collapse to effective state per reviewer
50
- const states = {}; // login → {approved, changesRequested}
49
+ // 3. reduce to effective state per reviewer
50
+ const states = {}; // login → {approved, changesRequested}
51
51
for (const r of reviews) {
52
52
const u = r.user.login;
53
53
states[u] = states[u] || { approved: false, changesRequested: false };
54
- if (r.state === 'APPROVED') states[u].approved = true;
55
- if (r.state === 'REQUEST_CHANGES') states[u].changesRequested = true;
54
+ if (r.state === 'APPROVED') states[u].approved = true;
55
+ if (r.state === 'REQUEST_CHANGES') states[u].changesRequested = true;
56
56
}
57
57
58
- // ──────── DEBUG BLOCK #2 – latest state map ────────
58
+ // DEBUG 2: effective map
59
59
core.info('=== Effective state per reviewer ===');
60
60
Object.entries(states).forEach(([u, s]) =>
61
61
core.info(`${u}: approved=${s.approved}, changesRequested=${s.changesRequested}`));
62
- // ───────────────────────────────────────────────────
63
62
63
+ // 4. build final approved-and-not-blocked set
64
64
const approved = Object.entries(states)
65
65
.filter(([_, s]) => s.approved && !s.changesRequested)
66
66
.map(([u]) => u);
67
67
68
- // ──────── DEBUG BLOCK #3 – final approved list ────────
68
+ // DEBUG 3: final list
69
69
core.info(`Approved reviewers counted: ${approved.join(', ') || 'none'}`);
70
- // ───────────────────────────────────────────────────────
71
70
71
+ // 5. org-level checks
72
72
const hasJump = jumpApprovers.some(u => approved.includes(u));
73
73
const hasAnza = anzaApprovers.some(u => approved.includes(u));
74
74
75
- // 4. nice summary in the PR “Checks” view
75
+ // prepare helpful failure message
76
+ const missing = [];
77
+ if (!hasJump) missing.push(
78
+ `Jump approval missing. Any of: ${jumpApprovers.join(', ')}`);
79
+ if (!hasAnza) missing.push(
80
+ `Anza approval missing. Any of: ${anzaApprovers.join(', ')}`);
81
+
82
+ // PR-check summary
76
83
core.summary
77
84
.addHeading('Jump + Anza approval check')
78
85
.addTable([
81
88
])
82
89
.write();
83
90
84
- if (!hasJump || !hasAnza ) {
85
- core.setFailed('Need at least one Jump and one Anza approval' );
91
+ if (missing.length ) {
92
+ core.setFailed(missing.join(' | ') );
86
93
} else {
87
94
core.notice('All required approvals present; merge allowed.');
88
95
}
0 commit comments