-
Notifications
You must be signed in to change notification settings - Fork 0
fix(signals): rewrite centaur_review gate to check GitHub comments #444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -186,7 +186,7 @@ export async function checkGate(config: GateConfig): Promise<GateResult> { | |
| case 'gh_review': | ||
| return checkGhReview(config as GateConfig & { repo: string; pr: number | string }); | ||
| case 'centaur_review': | ||
| return checkCentaurReview(config as GateConfig & { pr_url: string }); | ||
| return checkCentaurReview(config as GateConfig & { repo: string; pr: number | string }); | ||
| case 'compound': | ||
| return checkCompound(config as GateConfig & { all: GateConfig[] }); | ||
| case 'human_approval': | ||
|
|
@@ -260,23 +260,42 @@ async function checkGhReview(config: { repo: string; pr: number | string }): Pro | |
| } | ||
| } | ||
|
|
||
| async function checkCentaurReview(config: { pr_url: string }): Promise<GateResult> { | ||
| async function checkCentaurReview(config: { | ||
| repo: string; | ||
| pr: number | string; | ||
| }): Promise<GateResult> { | ||
| try { | ||
| const res = await fetch( | ||
| `http://localhost:8642/api/reviews?pr=${encodeURIComponent(config.pr_url)}`, | ||
| ); | ||
| if (!res.ok) return { resolved: false, status: 'fail' }; | ||
| const data = (await res.json()) as { status?: string; review?: unknown }; | ||
|
|
||
| if (data.status === 'approved') { | ||
| return { resolved: true, status: 'pass', artifacts: { review: data.review } }; | ||
| const { stdout } = await execFileAsync('gh', [ | ||
| 'api', | ||
| `repos/${config.repo}/issues/${config.pr}/comments`, | ||
| '--jq', | ||
| '[.[] | select(.body | startswith("## Centaur Review")) | {body: .body, created_at: .created_at}] | last', | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ bugs: When no comments match the |
||
| ]); | ||
| if (!stdout.trim()) return { resolved: false, status: 'fail' }; | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π‘ bugs: When no Centaur Review comment exists on the PR, the jq filter |
||
|
|
||
| const comment = JSON.parse(stdout) as { body: string; created_at: string }; | ||
| const body = comment.body; | ||
|
|
||
| // LGTM with no issues = pass | ||
| if (body.includes('LGTM')) { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π΅ unsafe_assumptions:
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π΅ unsafe_assumptions: |
||
| return { resolved: true, status: 'pass', artifacts: { review: body } }; | ||
| } | ||
| if (data.status === 'changes_requested') { | ||
| return { resolved: true, status: 'fail', artifacts: { review: data.review } }; | ||
|
|
||
| // Has findings β resolved (review exists) but status depends on severity | ||
| const hasCritical = /\d+\s+critical/.test(body); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π΅ style: The regexes |
||
| const hasWarning = /\d+\s+warning/.test(body); | ||
|
|
||
| if (hasCritical || hasWarning) { | ||
| return { | ||
| resolved: true, | ||
| status: 'fail', | ||
| artifacts: { review: body, hasCritical, hasWarning }, | ||
| }; | ||
| } | ||
| return { resolved: false, status: 'fail' }; | ||
|
|
||
| // Review exists but only info/style β pass | ||
| return { resolved: true, status: 'pass', artifacts: { review: body } }; | ||
| } catch { | ||
| // Centaur might not be running β that's fine, just not resolved | ||
| return { resolved: false, status: 'fail' }; | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ regressions: The function signature changed from
{ pr_url: string }to{ repo: string; pr: number | string }, but the signal resolve endpoint inapp.ts:1048still supports matchingcentaur_reviewtasks bypr_url, and the test atsignal-processor.test.ts:251creates gate configs with onlypr_url. If any existing tasks were created withpr_url-only configs, polling viacheckGatewill cast them to{ repo, pr }(bothundefined), causinggh api repos/undefined/issues/undefined/commentsto fail silently every poll cycle. Either migrate the resolve endpoint and tests to droppr_urlsupport, or handle both config shapes incheckCentaurReview.[fixable]