Skip to content

Commit 11f88af

Browse files
authored
ci: Bind Codex approval to review request
1 parent 157f682 commit 11f88af

1 file changed

Lines changed: 48 additions & 6 deletions

File tree

‎.github/workflows/codex-review-gate.yml‎

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,28 @@ jobs:
252252
return match ? asDate(match[1]) : null;
253253
}
254254
255+
function requestCommentIdForRun(run) {
256+
const summary = String(run.output?.summary || '');
257+
const match = summary.match(/^Request comment: (\d+)$/m);
258+
return match ? Number(match[1]) : null;
259+
}
260+
261+
function requestBoundApprovalForRun(run) {
262+
const summary = String(run.output?.summary || '');
263+
return (
264+
run.output?.title === 'Codex review required after base update' ||
265+
/^Approval mode: request-reaction$/m.test(summary)
266+
);
267+
}
268+
255269
async function inspectCodexOutcome(
256270
pull,
257271
run,
258272
quotaFloor,
259-
allowTerminal,
273+
allowApproval,
260274
terminalFloor,
275+
requestCommentId,
276+
requestBoundApproval,
261277
) {
262278
const startedAt = asDate(run.started_at || run.created_at) || now;
263279
const resultFloor =
@@ -269,7 +285,7 @@ jobs:
269285
? quotaFloor
270286
: resultFloor;
271287
272-
const [reviews, reviewComments, issueComments] =
288+
const [reviews, reviewComments, issueComments, requestReactions] =
273289
await Promise.all([
274290
github.paginate(github.rest.pulls.listReviews, {
275291
owner,
@@ -289,6 +305,14 @@ jobs:
289305
issue_number: pull.number,
290306
per_page: 100,
291307
}),
308+
requestCommentId
309+
? github.paginate(github.rest.reactions.listForIssueComment, {
310+
owner,
311+
repo,
312+
comment_id: requestCommentId,
313+
per_page: 100,
314+
})
315+
: Promise.resolve([]),
292316
]);
293317
294318
const commentsByReview = new Map();
@@ -303,7 +327,6 @@ jobs:
303327
304328
const terminal = [];
305329
for (const review of reviews) {
306-
if (!allowTerminal) continue;
307330
if (!isCodex(review.user?.login)) continue;
308331
if (review.commit_id !== pull.head.sha) continue;
309332
const submittedAt = asDate(review.submitted_at);
@@ -329,7 +352,7 @@ jobs:
329352
}
330353
331354
for (const comment of issueComments) {
332-
if (!allowTerminal) continue;
355+
if (!allowApproval || requestBoundApproval) continue;
333356
if (!isCodex(comment.user?.login)) continue;
334357
const body = String(comment.body || '');
335358
if (!body.startsWith("Codex Review: Didn't find any major issues.")) {
@@ -378,6 +401,16 @@ jobs:
378401
terminal.push({ at: createdAt, kind: 'approve', findingCount: 0 });
379402
}
380403
404+
if (allowApproval && requestBoundApproval && requestCommentId) {
405+
for (const reaction of requestReactions) {
406+
if (!isCodex(reaction.user?.login)) continue;
407+
if (reaction.content !== '+1') continue;
408+
const createdAt = asDate(reaction.created_at);
409+
if (!createdAt || createdAt < resultFloor) continue;
410+
terminal.push({ at: createdAt, kind: 'approve', findingCount: 0 });
411+
}
412+
}
413+
381414
terminal.sort((a, b) => {
382415
if (a.kind !== b.kind) return a.kind === 'findings' ? -1 : 1;
383416
return b.at - a.at;
@@ -438,13 +471,17 @@ jobs:
438471
const requestFloor = requestedAtForRun(run);
439472
const requiresFreshRequest =
440473
run.output?.title === 'Codex review required after base update';
474+
const requestCommentId = requestCommentIdForRun(run);
475+
const requestBoundApproval = requestBoundApprovalForRun(run);
441476
442477
const outcome = await inspectCodexOutcome(
443478
pull,
444479
run,
445480
availableSince,
446481
!requiresFreshRequest || Boolean(requestFloor),
447482
requestFloor,
483+
requestCommentId,
484+
requestBoundApproval,
448485
);
449486
if (outcome.terminal) {
450487
if (completedSuccess && outcome.terminal.kind !== 'findings') {
@@ -486,7 +523,10 @@ jobs:
486523
repo,
487524
pull_number: event.pr,
488525
});
489-
if (current.data.head.sha !== event.head_sha) {
526+
if (
527+
current.data.head.sha !== event.head_sha ||
528+
current.data.base.sha !== event.base_sha
529+
) {
490530
await github.rest.checks.update({
491531
owner,
492532
repo,
@@ -496,7 +536,7 @@ jobs:
496536
completed_at: now.toISOString(),
497537
output: {
498538
title: 'Codex review superseded',
499-
summary: 'The pull request changed while its Codex result was being reconciled.',
539+
summary: 'The pull request head or base changed while its Codex result was being reconciled.',
500540
},
501541
});
502542
continue;
@@ -662,7 +702,9 @@ jobs:
662702
title: 'Codex review requested',
663703
summary: [
664704
`Requested at: ${now.toISOString()}`,
705+
`Request comment: ${Number(comment.data.id)}`,
665706
`Base commit: ${candidate.base_sha}`,
707+
'Approval mode: request-reaction',
666708
'Requested managed Codex review and waiting for its result.',
667709
].join('\n'),
668710
},

0 commit comments

Comments
 (0)