-
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 all 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,9 @@ 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; pr_url?: string }, | ||
| ); | ||
| case 'compound': | ||
| return checkCompound(config as GateConfig & { all: GateConfig[] }); | ||
| case 'human_approval': | ||
|
|
@@ -260,23 +262,52 @@ async function checkGhReview(config: { repo: string; pr: number | string }): Pro | |
| } | ||
| } | ||
|
|
||
| async function checkCentaurReview(config: { pr_url: 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 } }; | ||
| async function checkCentaurReview(config: { | ||
| repo?: string; | ||
| pr?: number | string; | ||
| pr_url?: string; | ||
| }): Promise<GateResult> { | ||
| // Support both repo+pr and legacy pr_url gate config formats | ||
| let repo = config.repo; | ||
| let pr = config.pr; | ||
| if (!repo && !pr && config.pr_url) { | ||
| const match = config.pr_url.match(/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)/); | ||
| if (match) { | ||
| repo = match[1]; | ||
| pr = match[2]; | ||
| } | ||
| if (data.status === 'changes_requested') { | ||
| return { resolved: true, status: 'fail', artifacts: { review: data.review } }; | ||
| } | ||
| if (!repo || !pr) return { resolved: false, status: 'fail' }; | ||
|
|
||
| try { | ||
| const { stdout } = await execFileAsync('gh', [ | ||
| 'api', | ||
| `repos/${repo}/issues/${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() || stdout.trim() === 'null') return { resolved: false, status: 'fail' }; | ||
|
|
||
| const comment = JSON.parse(stdout) as { body: string; created_at: string }; | ||
| if (!comment) return { resolved: false, status: 'fail' }; | ||
| const body = comment.body; | ||
|
|
||
| // Check severity first β a review with findings takes precedence even if "LGTM" appears | ||
| // Regexes match Centaur's summary format: "Found **N** issue(s) (X critical, Y warning)" | ||
| 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' }; | ||
|
|
||
| // LGTM or info/style only β 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]