-
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 1 commit
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,41 @@ 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: Existing gate configs using the
pr_urlformat (e.g.{ type: 'centaur_review', pr_url: 'https://...' }) will fail during polling βconfig.repoandconfig.prwill beundefined, producing a badgh apipath. The REST resolve endpoint inapp.ts:1048and the test at signal-processor.test.ts:251 still supportpr_urlmatching, creating an inconsistency. Either migrate the resolve endpoint and tests away frompr_url, or handle both formats incheckCentaurReview.[fixable]