Skip to content

ci(gpu): gate GPU tests in-workflow so the required check always reports - #321

Merged
vivekkhandelwal1 merged 2 commits into
mainfrom
fix/gpu-tests-required-check-gate
Aug 4, 2026
Merged

ci(gpu): gate GPU tests in-workflow so the required check always reports#321
vivekkhandelwal1 merged 2 commits into
mainfrom
fix/gpu-tests-required-check-gate

Conversation

@vivekkhandelwal1

Copy link
Copy Markdown
Collaborator

The problem

pytest (GPU, MI350) is a required status check in the active main protection ruleset (strict_required_status_checks_policy: true). But gpu-tests.yml filtered its pull_request trigger with a paths: list.

Per GitHub's docs on required status checks, those two settings are incompatible:

Cause Result
A workflow is skipped by path filtering Associated checks stay Pending and block merging
A job is skipped by a conditional The job reports Success

So a PR touching none of the filtered paths never produces a pytest (GPU, MI350) result at all, and the merge gate waits forever on a check that will never arrive. This is not theoretical — five of the seven currently open PRs are blocked by it:

PR Files GPU checks
#307 docs/** none
#313 .github/workflows/{lock-requirements,refresh-baselines}.yml none
#314 .github/workflows/* (setup-python bump) none
#315 nightly-eval.yml, pages.yml, docs/ none
#317 src/aorta/cli/**, src/aorta/tools/**, pyproject.toml none
#318 tests/instrumentation/test_environment.py 2
#320 scripts/ci/gen_dashboard.py 2

Note the workflow's own header comment anticipated making this check required, but marking it so didn't account for the paths filter.

The fix

Move the path decision from the trigger into the workflow:

  • pull_request: no longer carries paths:, so the workflow always starts and always reports.
  • A new changes job on ubuntu-latest lists the PR's files via gh api .../pulls/N/files and sets a gpu output. Non-PR events (schedule, workflow_dispatch) always return true.
  • gpu-tests gains needs: changes and gates on needs.changes.outputs.gpu == 'true', keeping its existing fork-PR guard. gpu-regression skips along with it, since a dependency that did not succeed skips the dependent job.

A skipped job reports Success, so docs-only PRs satisfy the required check in seconds without ever touching the MI350 runner. permissions: gains pull-requests: read for the file listing.

Job names are unchanged, so the ruleset needs no edit.

Behaviour is preserved

The pattern list is one-to-one with the paths: filter it replaces. I replayed the gate logic against the actual file lists of all seven open PRs and it reproduces the old decisions exactly — gpu=true for #318 and #320, gpu=false for the other five.

Edge cases also checked: a brand-new file under scripts/ci/, a deep subtree under src/aorta/workloads/, gpu-tests.yml itself, an unrelated workflow, docs-only, and near-miss lookalikes (scripts/other/x.py, docker.md, src/aorta/racecar/x.py) all classify correctly.

One implementation note worth flagging for review: the patterns are single-quoted in a bash array and iterated as "${patterns[@]}". An earlier draft used an unquoted string list, which the shell filename-expanded against the working directory — that silently turned scripts/ci/* into whatever happened to exist locally and would have missed newly added files. The array form keeps them literal so they reach case as patterns.

Verification

This PR touches .github/workflows/gpu-tests.yml, which is in the pattern list, so GPU jobs should run here and prove the positive path still works. The skip path is proven by updating #315 with main afterwards and confirming pytest (GPU, MI350) reports as skipped/Success.

Made with Cursor

`pytest (GPU, MI350)` is a required status check in the `main protection`
ruleset, but gpu-tests.yml filtered its `pull_request` trigger by path.
A workflow skipped by path filtering never reports -- its checks stay
Pending -- so any PR touching none of those paths could never satisfy the
requirement and was permanently unmergeable. Five of the seven currently
open PRs are blocked this way (#307, #313, #314, #315, #317).

Drop the trigger-level `paths:` filter and decide inside the workflow
instead: a new `changes` job on ubuntu-latest lists the PR's files and
sets an output, and the GPU jobs gate on it. A job skipped by a
conditional reports Success, so non-GPU PRs now pass the required check
without ever occupying the single MI350 runner.

The pattern list is one-to-one with the `paths:` filter it replaces, so
which PRs run GPU work is unchanged; verified against all seven open PRs.
Job names are unchanged, so the ruleset needs no edit.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI lite review requested due to automatic review settings August 4, 2026 08:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the GPU CI workflow so the required pytest (GPU, MI350) check always produces a conclusion on PRs by moving path-based gating from the workflow trigger into an in-workflow “changes” gate job.

Changes:

  • Removes pull_request.paths filtering so the workflow always runs and reports checks.
  • Adds a changes job that lists PR files via gh api and outputs whether GPU-relevant paths changed.
  • Gates pytest (GPU, MI350) (and thus its dependent regression job) on the changes output while preserving the fork-PR safety guard.

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

Comment thread .github/workflows/gpu-tests.yml
The gate fetched the file list through process substitution, which
discards the command's exit status -- `set -euo pipefail` never saw a
failed `gh api`. A transient outage, rate limit or token-scope problem
therefore produced an empty list and a confident `gpu=false`, skipping
the GPU jobs and handing a GPU-touching PR a green required check
without ever testing it.

Capture the listing explicitly and default to `gpu=true` when it cannot
be retrieved or comes back empty, so an indeterminate gate errs towards
running the suite instead of silently waving a PR through.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings August 4, 2026 09:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@vivekkhandelwal1
vivekkhandelwal1 merged commit 6edd07c into main Aug 4, 2026
8 checks passed
@vivekkhandelwal1
vivekkhandelwal1 deleted the fix/gpu-tests-required-check-gate branch August 4, 2026 09:14
qianghan-amd added a commit that referenced this pull request Aug 4, 2026
Conflict in .github/workflows/gpu-tests.yml, resolved in favour of main's
design. `pytest (GPU, MI350)` is a required status check, and main's #321
removed the `paths:` filter from the `pull_request` trigger because a workflow
skipped by path filtering leaves its checks Pending forever instead of
reporting, making any PR outside those paths permanently unmergeable. The filter
now lives in the `changes` job as a bash `case` pattern array.

This branch had added four entries to the `paths:` list that main deleted, so
keeping either side alone would have lost something: main's side drops the env
probe from GPU-relevant paths, and this branch's side reinstates the trigger
filter that made the required check unmergeable. The four entries moved into the
`patterns` array instead -- env_knobs.py, environment.py, audit_env_knobs.py and
test_env_knob_audit.py -- so the probe still triggers the GPU suite under main's
gate. The audit step merged cleanly and is unchanged.

Verified rather than assumed: the array is bash, not YAML, so the explanatory
comment sits inside `patterns=(...)`; expanding the real array shows 17 elements
with no comment leaking in as one. Running main's own `case` loop against the
merged patterns matches on each of the four files individually and still reports
false for a docs-only change, so the gate neither lost coverage nor became
unconditionally true.

Full tests/ -n 16 in the ROCm 7.0.2 image, same command and hardware:
merged 21 failed / 2911 passed / 93 skipped against origin/main's
21 failed / 2791 passed / 93 skipped, failure lists identical, so 0 new failures
and +120 passing. Shared-file ruff findings are an exact multiset match with
origin/main; all four workflows parse and the generated knob table still matches
the registry.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

2 participants