Skip to content

Comments

Add gh aw checks command for deterministic PR CI state classification#18164

Merged
pelikhan merged 3 commits intomainfrom
copilot/add-ci-state-classification-command
Feb 24, 2026
Merged

Add gh aw checks command for deterministic PR CI state classification#18164
pelikhan merged 3 commits intomainfrom
copilot/add-ci-state-classification-command

Conversation

Copy link
Contributor

Copilot AI commented Feb 24, 2026

Cross-repo automation was blocked on inconsistent gh pr checks output—human-oriented text that causes false-green triage when "no checks" is silently treated as success.

New command: gh aw checks <pr-number>

Queries the GitHub Checks API for a PR's head SHA, then emits a single normalized state:

State Meaning
success All checks passed
failed ≥1 check failed / errored / timed out
pending Checks queued or in-progress
no_checks No check runs registered at all
policy_blocked Only policy/branch-protection gates blocking (not product failures)
# Machine-readable: normalized state to stdout, human message to stderr
gh aw checks 42

# Full signal dump for tooling
gh aw checks 42 --repo owner/repo --json

JSON output shape (--json):

{
  "state": "failed",
  "pr_number": "42",
  "head_sha": "abc123",
  "check_runs": [{ "name": "test", "status": "completed", "conclusion": "failure", "html_url": "..." }],
  "total_count": 1
}

Changes

  • pkg/cli/checks_command.go — Command implementation: resolves PR head SHA, fetches check runs from the GitHub Checks API, classifies state via classifyCheckState(), routes normalized state to stdout and formatted message to stderr. policy_blocked is detected via name-pattern matching against known GitHub branch-protection check names. Includes classifyGHAPIError() for user-friendly 404 (PR not found) and 403/401 (authentication) error messages using console.FormatErrorWithSuggestions.
  • pkg/cli/checks_command_test.go — 25 fixture-based unit tests covering all five states, policy pattern matching, command argument arity, and API error classification.
  • cmd/gh-aw/main.go — Registers checks in the analysis command group alongside logs, audit, and health.
Original prompt

This section details on the original issue you should resolve

<issue_title>Add explicit CI state classification command for gh-aw PR triage</issue_title>
<issue_description>Problem
Operators currently infer check states from heterogeneous GitHub outputs, which leads to false-green triage when no checks is interpreted as success.

Why now
Cross-repo automation is now blocked on a deterministic check-state contract (failed, pending, no checks, policy-blocked).

Current behavior is insufficient
gh pr checks output is human-oriented and inconsistent across repos/workflow setups, so downstream tooling has to guess state.

Expected behavior
Provide a machine-readable classifier command in gh-aw that maps PR check rollups to normalized states.

Acceptance criteria

  • Command accepts repo + PR input and emits JSON.
  • JSON contains one normalized state plus supporting raw signals.
  • no checks reported is explicitly classified as no checks configured/not triggered.
  • Policy/account gates are classified separately from product failures.

Validation

  • Add fixture-based tests for failed, pending, no checks, and policy-blocked.
  • Verify deterministic output shape in CI.

Codepaths

  • cmd/gh-aw
  • internal/github
  • scripts
    </issue_description>

Comments on the Issue (you are @copilot in this section)

@pelikhan Could you explain more? @pelikhan Is this a new command to gh aw? @pelikhan @github/next-copilot-reviewers
  • implement as a new command "checks" in .go
  • provide text based and json content using --json
  • use helper to add arguments
  • add integration test in ci.yml

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add explicit CI state classification command for PR triage Add gh aw checks command for deterministic PR CI state classification Feb 24, 2026
@pelikhan pelikhan marked this pull request as ready for review February 24, 2026 15:02
Copilot AI review requested due to automatic review settings February 24, 2026 15:02
@pelikhan
Copy link
Contributor

@copilot handle the case where the pr does not exist or invalid token (403)

Ensure proper use of console helpers.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new gh aw checks command to provide deterministic PR CI state classification, addressing false-green triage issues caused by inconsistent gh pr checks output.

Changes:

  • Introduces a new checks command that queries GitHub's Checks API and legacy Status API to return one of five normalized states: success, failed, pending, no_checks, or policy_blocked
  • Supports both machine-readable JSON output and human-readable text output with the normalized state written to stdout
  • Includes comprehensive unit tests covering all state classifications, API interactions, and policy pattern matching

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
pkg/cli/checks_command.go Implements the checks command with GitHub API integration, state classification logic, and output formatting
pkg/cli/checks_command_test.go Provides 23 unit tests covering all five check states, policy detection patterns, and command structure validation
cmd/gh-aw/main.go Registers the checks command in the analysis command group

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


func TestClassifyCheckState_NoChecks(t *testing.T) {
state := classifyCheckState([]PRCheckRun{}, []PRCommitStatus{})
assert.Equal(t, CheckStateNoChecks, state, "empty check runs and statuses should yield no_checks")
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected spelling of 'yield' context: changed 'should yield no_checks' to 'should return no_checks' for consistency with error message conventions.

Suggested change
assert.Equal(t, CheckStateNoChecks, state, "empty check runs and statuses should yield no_checks")
assert.Equal(t, CheckStateNoChecks, state, "empty check runs and statuses should return no_checks")

Copilot uses AI. Check for mistakes.

for _, cr := range checkRuns {
switch cr.Status {
case "queued", "in_progress", "waiting", "requested", "pending":
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The status value 'waiting' is not documented in GitHub's Check Runs API. The valid status values are 'queued', 'in_progress', and 'completed'. Consider verifying if 'waiting' and 'requested' are valid status values or if they should be removed.

Suggested change
case "queued", "in_progress", "waiting", "requested", "pending":
case "queued", "in_progress":

Copilot uses AI. Check for mistakes.
hasPending = true
case "completed":
switch cr.Conclusion {
case "failure", "timed_out", "startup_failure":
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conclusion value 'startup_failure' is not a standard GitHub Check Run conclusion. Valid conclusions include 'success', 'failure', 'neutral', 'cancelled', 'skipped', 'timed_out', 'action_required', 'stale'. Consider verifying this value or documenting its source.

Suggested change
case "failure", "timed_out", "startup_failure":
case "failure", "timed_out":

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Contributor

@copilot avoid legacy APIs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 24, 2026

@copilot handle the case where the pr does not exist or invalid token (403)

Ensure proper use of console helpers.

Done in 3c80679.

Added classifyGHAPIError() which inspects the gh api exit stderr and maps:

  • 404 / "not found" → actionable error: "PR #N not found in <repo>" with suggestions to verify the PR number and use --repo
  • 403 / 401 / "bad credentials" → actionable error: "GitHub API authentication failed" with suggestions to run gh auth login and check token scopes
  • Generic → falls back to the raw exit-code message

All three fetch functions (fetchPRHeadSHA, fetchCheckRuns, fetchCommitStatuses) now go through this helper. RunChecks no longer double-prints by calling FormatErrorMessage before returning; errors are pre-formatted via FormatErrorWithSuggestions so main.go recognises them as already-formatted and re-uses them verbatim.

@pelikhan pelikhan merged commit b046c6b into main Feb 24, 2026
78 checks passed
@pelikhan pelikhan deleted the copilot/add-ci-state-classification-command branch February 24, 2026 15:20
Copy link
Contributor Author

Copilot AI commented Feb 24, 2026

@copilot avoid legacy APIs

Done in 8d3edf3. Removed the legacy commit statuses API entirely — PRCommitStatus, commitStatusAPIResponse, fetchCommitStatuses, and the Statuses field from ChecksResult are all gone. classifyCheckState now operates only on []PRCheckRun from the Checks API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add explicit CI state classification command for gh-aw PR triage

2 participants