Check CI status, analyze test failures, auto-fix obvious issues or discuss with user
Analyze CI failures for PR $ARGUMENTS (or the current branch's PR if no argument given).
# If $ARGUMENTS is a number or URL, use it directly.
# Otherwise detect from current branch:
gh pr view --json number,title,headRefName --jq '{number, title, headRefName}'
Parse the buildId from any check URL first (see Step 1c), then hit the test summary endpoint:
curl -s "https://dev.azure.com/{org}/{project_guid}/_apis/test/resultsummarybybuild?buildId={buildId}&api-version=7.0-preview"
No auth needed. Returns aggregate counts instantly (~1KB):
{
"aggregatedResultsAnalysis": {
"totalTests": 279518,
"resultsByOutcome": {
"Passed": {"count": 276837},
"Failed": {"count": 24},
"NotExecuted": {"count": 2657}
},
"runSummaryByOutcome": {
"Failed": {"runsCount": 14},
"Passed": {"runsCount": 23}
}
}
}
If Failed.count == 0 and all checks passed — report success, stop.
Use gh pr checks text format (tab-separated) — it reliably includes Azure URLs unlike the JSON statusCheckRollup where detailsUrl can be null.
gh pr checks $PR 2>&1
Output format (tab-separated):
CheckName\tstatus\tduration\tURL
Parse and classify each check:
pass — succeededfail — failedpending — still runningGroup checks by source:
dev.azure.com. Extract buildId from first Azure URL. These are the test jobs.github.com/actions. These include build (compilation), gitleaks (secret scanning), Danger (PR linting). Failed GitHub Actions checks are relevant — report them.CodeRabbit (no URL or review-only) — skip.Extract buildId from the first Azure URL (all checks in one pipeline run share the same buildId).
For each failed GitHub Actions check, fetch its details:
# Extract run_id and job_id from URL: https://github.com/{owner}/{repo}/actions/runs/{run_id}/job/{job_id}
gh run view {run_id} --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {name, conclusion}'
Report these as Category E (non-test failures) in the final output. Common cases:
gh pr view $PR --comments --jq '.comments[-1].body'/loop 2m /fix-ci $PR to monitor."Use the Azure Test Results microservice at vstmr.dev.azure.com. This is a different hostname from the build APIs and serves test result data publicly for public projects.
curl -s "https://vstmr.dev.azure.com/questdb/questdb/_apis/testresults/resultsbybuild?buildId={buildId}&publishContext=CI&outcomes=Failed&\$top=200&api-version=5.2-preview.1"
No authentication or special headers needed. Returns all failed test results (~1-5KB):
[
{
"automatedTestName": "test[/sql/sample_by_fill.test]",
"automatedTestStorage": "io.questdb.test.sqllogictest.SqlTest",
"outcome": "Failed",
"runId": 795795,
"durationInMs": 1067.0,
"id": 100001,
"testCaseTitle": "test[/sql/sample_by_fill.test]"
}
]
Key fields:
automatedTestName / testCaseTitle — the test nameautomatedTestStorage — the test class (e.g., io.questdb.test.sqllogictest.SqlTest)runId — which CI job run this failure came fromoutcome — always "Failed" given the filterDeduplicate by test name — the same test fails across multiple platforms (mac, windows, linux). Group by automatedTestName, collect runIds to know which platforms failed.
If this returns 0 results but Step 1b showed failures, fall back to Step 2b (log tail parsing). This can happen if the pipeline doesn't publish JUnit test results.
The vstmr endpoint returns test names but NOT errorMessage, stackTrace, or computerName. If AZURE_DEVOPS_PAT is set, enrich each failed test with full details.
Step 2 gives us runId per failed test. Use the authenticated test/runs/{runId}/results endpoint to get error details:
# For each unique runId from Step 2:
curl -s -u ":$AZURE_DEVOPS_PAT" \
-H "X-TFS-FedAuthRedirect: Suppress" \
"https://dev.azure.com/questdb/questdb/_apis/test/runs/{runId}/results?outcomes=Failed&api-version=7.0"
This returns full details per failed test:
errorMessage — the assertion failure or exception messagestackTrace — full Java stack traceautomatedTestName, automatedTestStorage — test identityfailingSince — when this test started failingfailureType — type of failureWith this data, skip directly to Step 4 (classification).
Note: test/runs?buildId=... (listing runs by build) requires Build: Read scope and returns 403 with Test Management: Read alone. But test/runs/{runId}/results works with just Test Management: Read — and we already have runIds from the unauthenticated Step 2.
If no PAT is set, suggest the user create one for richer failure data:
To get error messages and stack traces without downloading logs, set
AZURE_DEVOPS_PAT:
- Go to https://dev.azure.com/questdb/_usersSettings/tokens
- Click "New Token"
- Set scope: Test Management → Read (the only scope needed)
- Add to
~/.zshenv:export AZURE_DEVOPS_PAT=<token>Without it, I can still see which tests failed but need to download log tails for error details.
Only suggest this once per session, and only if log tail parsing is actually needed (i.e., the test names alone aren't enough for classification).
Use this when Step 2 returns 0 results or when error messages are needed and no PAT is available.
Extract org, project GUID, buildId, jobId from each failed check's URL: