From eff736cc0fd935c13cd9a239b570fa81f987b790 Mon Sep 17 00:00:00 2001 From: Liangsheng Yin Date: Fri, 15 May 2026 02:18:28 -0700 Subject: [PATCH] Deprecate /rerun-stage; scrub CUDA target_stage infra (#25322) --- .github/workflows/_pr-awareness-comment.yml | 1 - .github/workflows/_pr-test-check-changes.yml | 179 +------------ .../workflows/_pr-test-sgl-kernel-build.yml | 5 +- .github/workflows/_pr-test-stage.yml | 20 +- .github/workflows/pr-test-extra.yml | 31 +-- .github/workflows/pr-test-jit-kernel.yml | 28 +- .github/workflows/pr-test-multimodal-gen.yml | 78 ++---- .github/workflows/pr-test-sgl-kernel.yml | 10 +- .github/workflows/pr-test.yml | 97 +------ scripts/ci/utils/slash_command_handler.py | 250 ++---------------- 10 files changed, 95 insertions(+), 604 deletions(-) diff --git a/.github/workflows/_pr-awareness-comment.yml b/.github/workflows/_pr-awareness-comment.yml index 65f7d00ea..a0a4d817c 100644 --- a/.github/workflows/_pr-awareness-comment.yml +++ b/.github/workflows/_pr-awareness-comment.yml @@ -92,7 +92,6 @@ jobs: const newBlock = [ outerStart, - '---', '### CI Awareness', '', `Latest PR Test: ${ptStart}${newPrTest}${ptEnd}`, diff --git a/.github/workflows/_pr-test-check-changes.yml b/.github/workflows/_pr-test-check-changes.yml index 26d63807b..61cccb599 100644 --- a/.github/workflows/_pr-test-check-changes.yml +++ b/.github/workflows/_pr-test-check-changes.yml @@ -3,18 +3,9 @@ name: Check Changes on: workflow_call: inputs: - pr_head_sha: - type: string - default: '' git_ref: type: string default: '' - target_stage: - type: string - default: '' - include_wheel_build: - type: boolean - default: false run_all_tests: type: boolean default: false @@ -30,8 +21,6 @@ on: value: ${{ jobs.run.outputs.main_package }} sgl_kernel: value: ${{ jobs.run.outputs.sgl_kernel }} - sgl_kernel_raw: - value: ${{ jobs.run.outputs.sgl_kernel_raw }} jit_kernel: value: ${{ jobs.run.outputs.jit_kernel }} multimodal_gen: @@ -52,20 +41,10 @@ jobs: name: check-changes runs-on: ubuntu-latest outputs: - # Use API-based detection for target_stage mode (filter-api), otherwise use dorny/paths-filter (filter) - main_package: ${{ steps.filter-api.outputs.main_package || steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} - # sgl_kernel is forced to false when target_stage is set AND include_wheel_build is NOT set, - # since sgl-kernel-build-wheels normally skips in target_stage mode. When include_wheel_build - # is true, keep the real value so the wheel build runs and the target stage downloads its - # artifact (used by /rerun-stage on PRs that modify sgl-kernel/). - # This prevents CUSTOM_BUILD_SGL_KERNEL=true when the wheel artifacts aren't available. - # Note: If PR has kernel changes AND target_stage is set AND include_wheel_build is NOT set, - # the validate-target-stage step will fail. - sgl_kernel: ${{ (!inputs.target_stage || inputs.include_wheel_build) && (steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel) }} - # Raw sgl_kernel value before target_stage override (used for validation) - sgl_kernel_raw: ${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel }} - jit_kernel: ${{ steps.filter-api.outputs.jit_kernel || steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} - multimodal_gen: ${{ steps.filter-api.outputs.multimodal_gen || steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} + main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} + sgl_kernel: ${{ steps.filter.outputs.sgl_kernel }} + jit_kernel: ${{ steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} + multimodal_gen: ${{ steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} partitions: ${{ steps.partitions.outputs.partitions }} partition_model_sha: ${{ steps.partition-model-sha.outputs.sha }} b200_runner: ${{ steps.set-runner.outputs.b200_runner }} @@ -75,7 +54,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-maintenance @@ -95,9 +74,7 @@ jobs: - name: Detect file changes id: filter uses: dorny/paths-filter@v3 - # Only use paths-filter for pull_request events (where it works correctly) - # For workflow_dispatch with target_stage, we use GitHub API in the next step - if: steps.run-mode.outputs.run_all_tests != 'true' && !inputs.target_stage + if: steps.run-mode.outputs.run_all_tests != 'true' with: filters: | main_package: @@ -128,93 +105,13 @@ jobs: # see API-side detector below for rationale. - "sgl-kernel/**/!(*.md|THIRDPARTYNOTICES.txt|LICENSE)" - # For /rerun-stage (workflow_dispatch with target_stage), dorny/paths-filter doesn't work - # correctly because it falls back to "last commit" detection which breaks for merge commits. - # Instead, we use the GitHub API to compare the PR commit against main. - - name: Detect file changes via API (for target_stage) - id: filter-api - if: inputs.target_stage && inputs.pr_head_sha - env: - GH_TOKEN: ${{ github.token }} - run: | - echo "Detecting file changes via GitHub API for target_stage mode..." - echo "PR head SHA: ${{ inputs.pr_head_sha }}" - - # Get the list of changed files by comparing PR commit against main - # This correctly handles merge commits by looking at the actual PR diff - CHANGED_FILES=$(gh api "repos/${{ github.repository }}/compare/main...${{ inputs.pr_head_sha }}" \ - --jq '[.files[].filename] | .[]' 2>/dev/null || echo "") - - if [ -z "$CHANGED_FILES" ]; then - echo "Warning: Could not fetch changed files from API, assuming no changes" - echo "sgl_kernel=false" >> $GITHUB_OUTPUT - echo "main_package=false" >> $GITHUB_OUTPUT - echo "jit_kernel=false" >> $GITHUB_OUTPUT - echo "multimodal_gen=false" >> $GITHUB_OUTPUT - exit 0 - fi - - echo "Changed files:" - echo "$CHANGED_FILES" | head -20 - echo "..." - - # Check for sgl-kernel changes - # Note: edits to .github/workflows/pr-test-sgl-kernel.yml are intentionally - # NOT considered sgl-kernel changes. That filter line used to be included - # so workflow refactors got retested, but in practice it only catches the - # workflow's *consumers* (test job definitions), not the wheel build steps - # themselves — and gating sgl_kernel=true on it forces a 20-30 min wheel - # rebuild + the stage-a-test-1-gpu-small gate for pure CI-yaml edits that - # can't actually affect kernel behavior. PRs that touch wheel-build logic - # in scripts/ci/cuda/ or sgl-kernel/ still trigger correctly. - if echo "$CHANGED_FILES" | grep -qE "^sgl-kernel/"; then - echo "sgl_kernel=true" >> $GITHUB_OUTPUT - echo "Detected sgl-kernel changes" - else - echo "sgl_kernel=false" >> $GITHUB_OUTPUT - fi - - # Check for main_package changes (excluding multimodal_gen, jit_kernel/diffusion, jit_kernel/tests/diffusion, jit_kernel/benchmark/diffusion, cli) - # Note: Need to filter out multimodal_gen and diffusion-related paths before checking, not pipe grep -q output - MAIN_PKG_FILES=$(echo "$CHANGED_FILES" | grep -E "^(python/sglang/|python/pyproject\.toml|scripts/ci/cuda/|scripts/ci/utils/|test/|\.github/workflows/pr-test\.yml|\.github/workflows/pr-gate\.yml|\.github/actions/)" | grep -v -E "^(python/sglang/multimodal_gen/|python/sglang/jit_kernel/diffusion/|python/sglang/jit_kernel/tests/diffusion/|python/sglang/jit_kernel/benchmark/diffusion/|python/sglang/cli/)" || true) - if [ -n "$MAIN_PKG_FILES" ]; then - echo "main_package=true" >> $GITHUB_OUTPUT - echo "Detected main_package changes" - else - echo "main_package=false" >> $GITHUB_OUTPUT - fi - - # Check for jit_kernel changes - if echo "$CHANGED_FILES" | grep -qE "^(python/sglang/jit_kernel/|python/pyproject\.toml|\.github/workflows/pr-test\.yml|\.github/workflows/pr-test-jit-kernel\.yml)"; then - echo "jit_kernel=true" >> $GITHUB_OUTPUT - echo "Detected jit_kernel changes" - else - echo "jit_kernel=false" >> $GITHUB_OUTPUT - fi - - # Check for multimodal_gen changes, including diffusion-specific jit_kernel coverage - if echo "$CHANGED_FILES" | grep -qE "^(python/sglang/multimodal_gen/|python/sglang/cli/|python/sglang/jit_kernel/diffusion/|python/sglang/jit_kernel/tests/diffusion/|python/sglang/jit_kernel/benchmark/diffusion/|python/pyproject\.toml|\.github/workflows/pr-test\.yml|\.github/workflows/pr-test-multimodal-gen\.yml)"; then - echo "multimodal_gen=true" >> $GITHUB_OUTPUT - echo "Detected multimodal_gen changes" - else - echo "multimodal_gen=false" >> $GITHUB_OUTPUT - fi - - name: Determine full-parallel mode id: parallel-mode - env: - GH_TOKEN: ${{ github.token }} run: | # `full=true` lifts the matrix-fanout throttle so each suite's - # max_parallel = size. Conditions (matching the prior set-parallel - # step exactly): + # max_parallel = size. Conditions: # 1. Scheduled cron run. # 2. pull_request event with the `high priority` label. - # 3. workflow_dispatch with target_stage set (i.e. /rerun-stage) - # whose underlying PR carries `high priority`. The labels - # aren't on the dispatch payload, so look them up via API: - # try SHA -> /pulls (works for fork PRs), fall back to - # branch name -> gh pr list (works for non-fork PRs). FULL=false if [[ "${{ github.event_name }}" == "schedule" ]]; then FULL=true @@ -222,22 +119,6 @@ jobs: elif [[ "${{ github.event_name }}" == "pull_request" && "${{ contains(github.event.pull_request.labels.*.name, 'high priority') }}" == "true" ]]; then FULL=true echo "high priority PR -> full parallelism" - elif [[ -n "${{ inputs.target_stage }}" ]]; then - LABELS="" - PR_HEAD_SHA="${{ inputs.pr_head_sha }}" - if [[ -n "$PR_HEAD_SHA" ]]; then - LABELS=$(gh api "repos/${{ github.repository }}/commits/${PR_HEAD_SHA}/pulls" \ - --jq '.[0].labels[].name' 2>/dev/null || true) - fi - if [[ -z "$LABELS" ]]; then - LABELS=$(gh pr list --head "${{ github.ref_name }}" --repo "${{ github.repository }}" \ - --json labels --jq '.[0].labels[].name' 2>/dev/null || true) - fi - echo "PR labels (via API): ${LABELS:-"(none)"}" - if echo "$LABELS" | grep -Fxq "high priority"; then - FULL=true - echo "high priority PR (via API) -> full parallelism" - fi fi echo "full=$FULL" >> "$GITHUB_OUTPUT" @@ -285,12 +166,9 @@ jobs: - name: Set B200 runner tag id: set-runner run: | - # Use kernel-build runner only when sgl_kernel changes are detected AND we're not in target_stage mode - # (target_stage skips wheel builds, so we can't use custom kernels) - # Use API-based detection (filter-api) for target_stage mode, otherwise use dorny/paths-filter (filter) - sgl_kernel="${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel }}" - target_stage="${{ inputs.target_stage }}" - if [[ "$sgl_kernel" == "true" && -z "$target_stage" ]]; then + # Use kernel-build runner only when sgl_kernel changes are detected. + sgl_kernel="${{ steps.filter.outputs.sgl_kernel }}" + if [[ "$sgl_kernel" == "true" ]]; then echo "b200_runner=4-gpu-b200-kernel" >> $GITHUB_OUTPUT else echo "b200_runner=4-gpu-b200" >> $GITHUB_OUTPUT @@ -313,32 +191,6 @@ jobs: echo "Filtered run, continue-on-error disabled" fi - - name: Validate target_stage with kernel changes - # Fail only when PR has sgl-kernel changes AND the caller didn't opt into include_wheel_build. - # include_wheel_build=true means sgl-kernel-build-wheels will run alongside the target stage - # (see the sgl_kernel output and sgl-kernel-build-wheels if-conditions above/below), so it's - # safe to proceed. - if: inputs.target_stage && !inputs.include_wheel_build && (steps.filter-api.outputs.sgl_kernel == 'true' || steps.filter.outputs.sgl_kernel == 'true') - run: | - echo "::error::Cannot use /rerun-stage when PR has sgl-kernel changes without include_wheel_build." - echo "::error::The sgl-kernel-build-wheels job is skipped in target_stage mode by default, but this PR modifies sgl-kernel/ files." - echo "::error::The slash-command handler should have set include_wheel_build=true automatically; falling back to /tag-and-rerun-ci." - echo "" - echo "ERROR: Cannot use /rerun-stage when PR has sgl-kernel changes without include_wheel_build." - echo "" - echo "This PR modifies files in sgl-kernel/, which requires building custom kernel wheels." - echo "Running the target stage without rebuilding the kernel would use the wrong (PyPI)" - echo "version of sgl-kernel instead of your changes." - echo "" - echo "The /rerun-stage handler sets include_wheel_build=true automatically when it detects" - echo "sgl-kernel/ changes on the PR. If you see this error, the handler may be outdated." - echo "" - echo "Alternatives:" - echo " /tag-and-rerun-ci - Re-run the full workflow including kernel builds" - echo " /rerun-ci - Re-run the full workflow" - echo "" - exit 1 - - name: Show filter results in summary (table) run: | { @@ -346,13 +198,10 @@ jobs: echo "" echo "| Component | Changed |" echo "|-------------------|---------|" - echo "| main_package | ${{ steps.filter-api.outputs.main_package || steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} |" - echo "| sgl_kernel (raw) | ${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel }} |" - echo "| sgl_kernel (used) | ${{ (!inputs.target_stage || inputs.include_wheel_build) && (steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel) }} |" - echo "| jit_kernel | ${{ steps.filter-api.outputs.jit_kernel || steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} |" - echo "| multimodal_gen | ${{ steps.filter-api.outputs.multimodal_gen || steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} |" - echo "| target_stage | ${{ inputs.target_stage || '(none)' }} |" - echo "| detection_method | ${{ inputs.target_stage && 'GitHub API' || 'dorny/paths-filter' }} |" + echo "| main_package | ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} |" + echo "| sgl_kernel | ${{ steps.filter.outputs.sgl_kernel }} |" + echo "| jit_kernel | ${{ steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} |" + echo "| multimodal_gen | ${{ steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} |" echo "| b200_runner | ${{ steps.set-runner.outputs.b200_runner }} |" echo "| enable_retry | ${{ steps.set-retry.outputs.enable_retry }} |" echo "| continue_on_error | ${{ steps.set-continue-on-error.outputs.continue_on_error }} |" diff --git a/.github/workflows/_pr-test-sgl-kernel-build.yml b/.github/workflows/_pr-test-sgl-kernel-build.yml index 903c6e8a0..e7b57d7ed 100644 --- a/.github/workflows/_pr-test-sgl-kernel-build.yml +++ b/.github/workflows/_pr-test-sgl-kernel-build.yml @@ -21,9 +21,6 @@ on: description: "Suffix appended to the upload-artifact name. '' for x86, '-aarch64' for arm." type: string default: '' - pr_head_sha: - type: string - default: '' git_ref: type: string default: '' @@ -69,7 +66,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: "recursive" - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-maintenance diff --git a/.github/workflows/_pr-test-stage.yml b/.github/workflows/_pr-test-stage.yml index 94cdcfe16..2c6e24829 100644 --- a/.github/workflows/_pr-test-stage.yml +++ b/.github/workflows/_pr-test-stage.yml @@ -11,7 +11,7 @@ on: workflow_call: inputs: self_name: - description: 'Caller job key; used for partitions[suite] lookup and target_stage gating.' + description: 'Caller job key; used for partitions[suite] lookup.' type: string required: true runner_config: @@ -27,7 +27,7 @@ on: type: string required: true caller_inputs: - description: 'toJson(inputs) from pr-test.yml. Read via fromJson(...).target_stage / pr_head_sha / git_ref / skip_stage_health_check / test_parallel_dispatch.' + description: 'toJson(inputs) from pr-test.yml. Read via fromJson(...).git_ref / skip_stage_health_check / test_parallel_dispatch.' type: string required: true partitions: @@ -74,19 +74,11 @@ env: jobs: run: name: ${{ inputs.self_name }} (${{ matrix.partition }}) - # target_stage takes precedence; otherwise default per-commit gating - # runs on schedule / parallel-dispatch / non-failed PR with main_package - # or sgl_kernel changes. + # Runs on schedule / parallel-dispatch / non-failed PR with main_package or sgl_kernel changes. if: | always() && - ( - (fromJson(inputs.caller_inputs).target_stage == inputs.self_name) || - ( - !fromJson(inputs.caller_inputs).target_stage && - ((github.event_name == 'schedule' || fromJson(inputs.caller_inputs).test_parallel_dispatch == true) || (!failure() && !cancelled())) && - (fromJson(inputs.check_changes).main_package == 'true' || fromJson(inputs.check_changes).sgl_kernel == 'true') - ) - ) + ((github.event_name == 'schedule' || fromJson(inputs.caller_inputs).test_parallel_dispatch == true) || (!failure() && !cancelled())) && + (fromJson(inputs.check_changes).main_package == 'true' || fromJson(inputs.check_changes).sgl_kernel == 'true') runs-on: ${{ inputs.runs_on }} timeout-minutes: 240 env: @@ -100,7 +92,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ fromJson(inputs.caller_inputs).pr_head_sha || fromJson(inputs.caller_inputs).git_ref || github.sha }} + ref: ${{ fromJson(inputs.caller_inputs).git_ref || github.sha }} - name: Resolve runner_config id: rc diff --git a/.github/workflows/pr-test-extra.yml b/.github/workflows/pr-test-extra.yml index 626b49711..cc7041cf7 100644 --- a/.github/workflows/pr-test-extra.yml +++ b/.github/workflows/pr-test-extra.yml @@ -9,33 +9,16 @@ name: PR Test Extra # Stages: extra-a (1-/2-gpu) and extra-b (4-/8-gpu) caller stubs reuse # `_pr-test-stage.yml` and `_pr-test-check-changes.yml` from pr-test.yml. -run-name: ${{ inputs.target_stage && (inputs.pr_head_sha && format('[{0}] {1}', inputs.target_stage, inputs.pr_head_sha) || format('[{0}]', inputs.target_stage)) || '' }} - on: pull_request: branches: [main] workflow_dispatch: inputs: - target_stage: - description: "Specific stage to run (optional, for quick testing)" - required: false - type: string - default: "" force_continue_on_error: description: "Force continue-on-error (test scheduled CI behavior)" required: false type: boolean default: false - pr_head_sha: - description: "PR head SHA to checkout (for /rerun-stage on fork PRs)" - required: false - type: string - default: "" - include_wheel_build: - description: "When set with target_stage, also run sgl-kernel-build-wheels so the target stage uses the freshly-built kernel (for /rerun-stage on PRs that modify sgl-kernel/)" - required: false - type: boolean - default: false test_parallel_dispatch: description: "Test parallel dispatch behavior (simulates scheduled run)" required: false @@ -60,7 +43,7 @@ on: default: false concurrency: - group: pr-test-extra-${{ github.event_name }}-${{ github.head_ref || github.ref_name || 'default' }}-${{ inputs.pr_head_sha || 'current' }}-${{ inputs.target_stage || inputs.git_ref || 'all' }} + group: pr-test-extra-${{ github.event_name }}-${{ github.head_ref || github.ref_name || 'default' }}-${{ inputs.git_ref || 'all' }} cancel-in-progress: ${{ github.event_name != 'workflow_call' }} env: @@ -76,7 +59,7 @@ permissions: actions: write contents: read issues: read - pull-requests: read + pull-requests: write jobs: # =============================================== check changes ==================================================== @@ -96,10 +79,7 @@ jobs: ) uses: ./.github/workflows/_pr-test-check-changes.yml with: - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} - target_stage: ${{ inputs.target_stage || '' }} - include_wheel_build: ${{ inputs.include_wheel_build == true }} run_all_tests: ${{ inputs.run_all_tests == true }} force_continue_on_error: ${{ inputs.force_continue_on_error == true }} pr_test_yml: '.github/workflows/pr-test-extra.yml' @@ -111,8 +91,6 @@ jobs: call-pr-awareness: needs: check-changes if: always() && github.event_name == 'pull_request' - permissions: - pull-requests: write uses: ./.github/workflows/_pr-awareness-comment.yml with: workflow_kind: pr-test-extra @@ -122,15 +100,12 @@ jobs: sgl-kernel-build-wheels: needs: check-changes if: | - always() && needs.check-changes.result == 'success' && - needs.check-changes.outputs.sgl_kernel == 'true' && - (!inputs.target_stage || inputs.include_wheel_build) + needs.check-changes.outputs.sgl_kernel == 'true' uses: ./.github/workflows/_pr-test-sgl-kernel-build.yml with: runs_on: x64-kernel-build-node job_display_name: Build Wheel - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true }} secrets: inherit diff --git a/.github/workflows/pr-test-jit-kernel.yml b/.github/workflows/pr-test-jit-kernel.yml index 83a4ca0ea..74c0b90e4 100644 --- a/.github/workflows/pr-test-jit-kernel.yml +++ b/.github/workflows/pr-test-jit-kernel.yml @@ -12,18 +12,10 @@ on: b200_runner: required: true type: string - pr_head_sha: - required: false - type: string - default: '' git_ref: required: false type: string default: '' - target_stage: - required: false - type: string - default: '' test_parallel_dispatch: required: false type: string @@ -46,14 +38,13 @@ jobs: jit-kernel-unit-test: if: | github.event_name != 'schedule' && - inputs.test_parallel_dispatch != 'true' && - !inputs.target_stage + inputs.test_parallel_dispatch != 'true' runs-on: 1-gpu-h100 timeout-minutes: 240 steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -87,14 +78,13 @@ jobs: jit-kernel-multigpu-unit-test: if: | github.event_name != 'schedule' && - inputs.test_parallel_dispatch != 'true' && - !inputs.target_stage + inputs.test_parallel_dispatch != 'true' runs-on: 8-gpu-h200 timeout-minutes: 240 steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-maintenance @@ -126,14 +116,13 @@ jobs: jit-kernel-benchmark-test: if: | github.event_name != 'schedule' && - inputs.test_parallel_dispatch != 'true' && - !inputs.target_stage + inputs.test_parallel_dispatch != 'true' runs-on: 1-gpu-h100 timeout-minutes: 240 steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -167,14 +156,13 @@ jobs: jit-kernel-b200-test: if: | github.event_name != 'schedule' && - inputs.test_parallel_dispatch != 'true' && - !inputs.target_stage + inputs.test_parallel_dispatch != 'true' runs-on: ${{ inputs.b200_runner }} timeout-minutes: 240 steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health diff --git a/.github/workflows/pr-test-multimodal-gen.yml b/.github/workflows/pr-test-multimodal-gen.yml index 0a94eb985..18cf49387 100644 --- a/.github/workflows/pr-test-multimodal-gen.yml +++ b/.github/workflows/pr-test-multimodal-gen.yml @@ -16,18 +16,10 @@ on: required: false type: string default: 'false' - pr_head_sha: - required: false - type: string - default: '' git_ref: required: false type: string default: '' - target_stage: - required: false - type: string - default: '' test_parallel_dispatch: required: false type: string @@ -51,13 +43,7 @@ env: jobs: compute-diffusion-partitions: - if: | - (inputs.target_stage == 'multimodal-gen-test-1-gpu') || - (inputs.target_stage == 'multimodal-gen-test-2-gpu') || - ( - !inputs.target_stage && - inputs.multimodal_gen == 'true' - ) + if: inputs.multimodal_gen == 'true' runs-on: ubuntu-latest outputs: matrix-1gpu: ${{ steps.compute.outputs.matrix-1gpu }} @@ -70,7 +56,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - name: Set up Python uses: actions/setup-python@v5 @@ -88,14 +74,8 @@ jobs: always() && needs.compute-diffusion-partitions.result == 'success' && needs.compute-diffusion-partitions.outputs.matrix-1gpu != '{"include":[]}' && - ( - (inputs.target_stage == 'multimodal-gen-test-1-gpu') || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && - inputs.multimodal_gen == 'true' - ) - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && + inputs.multimodal_gen == 'true' runs-on: 1-gpu-h100 timeout-minutes: 240 strategy: @@ -105,7 +85,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -167,14 +147,8 @@ jobs: always() && needs.compute-diffusion-partitions.result == 'success' && needs.compute-diffusion-partitions.outputs.matrix-2gpu != '{"include":[]}' && - ( - (inputs.target_stage == 'multimodal-gen-test-2-gpu') || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && - inputs.multimodal_gen == 'true' - ) - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && + inputs.multimodal_gen == 'true' runs-on: 2-gpu-h100 timeout-minutes: 240 strategy: @@ -184,7 +158,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -243,23 +217,15 @@ jobs: multimodal-gen-component-accuracy: if: | - ( - inputs.target_stage == 'multimodal-gen-component-accuracy' || - inputs.target_stage == 'multimodal-gen-component-accuracy-1-gpu' || - inputs.target_stage == 'multimodal-gen-component-accuracy-2-gpu' - ) || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && - inputs.multimodal_gen == 'true' - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && + inputs.multimodal_gen == 'true' runs-on: 2-gpu-h100 timeout-minutes: 240 steps: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -296,19 +262,15 @@ jobs: multimodal-gen-test-1-b200: if: | - (inputs.target_stage == 'multimodal-gen-test-1-b200') || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && - inputs.multimodal_gen == 'true' - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && + inputs.multimodal_gen == 'true' runs-on: ${{ inputs.b200_runner }} timeout-minutes: 240 steps: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -352,19 +314,15 @@ jobs: multimodal-gen-unit-test: if: | - (inputs.target_stage == 'multimodal-gen-unit-test') || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && - inputs.multimodal_gen == 'true' - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) && + inputs.multimodal_gen == 'true' runs-on: 1-gpu-h100 timeout-minutes: 120 steps: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -405,7 +363,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - name: Set up Python uses: actions/setup-python@v5 diff --git a/.github/workflows/pr-test-sgl-kernel.yml b/.github/workflows/pr-test-sgl-kernel.yml index 2a49d2a3c..54cfd3736 100644 --- a/.github/workflows/pr-test-sgl-kernel.yml +++ b/.github/workflows/pr-test-sgl-kernel.yml @@ -9,10 +9,6 @@ on: b200_runner: required: true type: string - pr_head_sha: - required: false - type: string - default: '' git_ref: required: false type: string @@ -37,7 +33,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -72,7 +68,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -119,7 +115,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 7353f0218..dbd41d4ef 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -1,7 +1,4 @@ name: PR Test -# Dynamic run-name for /rerun-stage commands to enable URL lookup -# Format: "[stage-name] sha" for fork PRs, "[stage-name]" for non-fork, default for normal runs -run-name: ${{ inputs.target_stage && (inputs.pr_head_sha && format('[{0}] {1}', inputs.target_stage, inputs.pr_head_sha) || format('[{0}]', inputs.target_stage)) || '' }} on: schedule: @@ -10,26 +7,11 @@ on: branches: [main] workflow_dispatch: inputs: - target_stage: - description: "Specific stage to run (optional, for quick testing)" - required: false - type: string - default: "" force_continue_on_error: description: "Force continue-on-error (test scheduled CI behavior)" required: false type: boolean default: false - pr_head_sha: - description: "PR head SHA to checkout (for /rerun-stage on fork PRs)" - required: false - type: string - default: "" - include_wheel_build: - description: "When set with target_stage, also run sgl-kernel-build-wheels so the target stage uses the freshly-built kernel (for /rerun-stage on PRs that modify sgl-kernel/)" - required: false - type: boolean - default: false test_parallel_dispatch: description: "Test parallel dispatch behavior (simulates scheduled run)" required: false @@ -59,13 +41,11 @@ on: default: false concurrency: - # Concurrency group structure: pr-test-{event}-{branch}-{pr_sha}-{stage} + # Concurrency group structure: pr-test-{event}-{branch}-{git_ref} # - event_name prevents scheduled runs from colliding with fork PRs whose branch is named 'main' # (without it, both resolve the branch segment to 'main' and block each other) # - github.head_ref (pull_request) or github.ref_name (workflow_dispatch) normalizes to branch name - # - pr_head_sha isolates /rerun-stage from main branch runs - # - target_stage allows parallel stage dispatches to run independently - group: pr-test-${{ github.event_name }}-${{ github.head_ref || github.ref_name || 'default' }}-${{ inputs.pr_head_sha || 'current' }}-${{ inputs.target_stage || inputs.git_ref || 'all' }} + group: pr-test-${{ github.event_name }}-${{ github.head_ref || github.ref_name || 'default' }}-${{ inputs.git_ref || 'all' }} cancel-in-progress: ${{ github.event_name != 'workflow_call' }} env: @@ -83,17 +63,14 @@ permissions: actions: write contents: read issues: read - pull-requests: read + pull-requests: write jobs: # =============================================== check changes ==================================================== check-changes: uses: ./.github/workflows/_pr-test-check-changes.yml with: - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} - target_stage: ${{ inputs.target_stage || '' }} - include_wheel_build: ${{ inputs.include_wheel_build == true }} run_all_tests: ${{ inputs.run_all_tests == true }} force_continue_on_error: ${{ inputs.force_continue_on_error == true }} secrets: inherit @@ -103,8 +80,6 @@ jobs: call-pr-awareness: needs: check-changes if: always() && github.event_name == 'pull_request' - permissions: - pull-requests: write uses: ./.github/workflows/_pr-awareness-comment.yml with: workflow_kind: pr-test @@ -130,7 +105,6 @@ jobs: always() && !cancelled() && github.event_name == 'pull_request' && - !inputs.target_stage && inputs.test_parallel_dispatch != true && (needs.check-changes.outputs.main_package == 'true' || needs.check-changes.outputs.sgl_kernel == 'true') && (needs.call-gate.result == 'success' || needs.call-gate.result == 'skipped') @@ -159,7 +133,6 @@ jobs: always() && !cancelled() && github.event_name == 'pull_request' && - !inputs.target_stage && inputs.test_parallel_dispatch != true && (needs.check-changes.outputs.main_package == 'true' || needs.check-changes.outputs.sgl_kernel == 'true') && (needs.wait-for-stage-a.result == 'success' || needs.wait-for-stage-a.result == 'skipped') && @@ -188,11 +161,10 @@ jobs: # =============================================== PR Gate ==================================================== call-gate: needs: check-changes - # Skip for scheduled runs (they run all tests) and when target_stage is specified + # Skip for scheduled runs (they run all tests) if: | github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && - !inputs.target_stage && ( needs.check-changes.outputs.main_package == 'true' || needs.check-changes.outputs.sgl_kernel == 'true' || @@ -206,53 +178,35 @@ jobs: sgl-kernel-build-wheels: needs: [check-changes, call-gate] - # Skip for scheduled runs (they run stages independently). Runs in target_stage mode only when - # include_wheel_build is true (i.e. /rerun-stage on a PR with sgl-kernel changes), so the - # target stage can download the freshly-built wheel. - # - # `always()` lets us run when call-gate is skipped (which it always is in target_stage mode by - # design). The explicit needs..result checks preserve old gating for the normal PR path. + # Skip for scheduled runs (they run stages independently). if: | - always() && github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && needs.check-changes.result == 'success' && needs.check-changes.outputs.sgl_kernel == 'true' && - ( - (!inputs.target_stage && needs.call-gate.result == 'success') || - (inputs.target_stage && inputs.include_wheel_build) - ) + needs.call-gate.result == 'success' uses: ./.github/workflows/_pr-test-sgl-kernel-build.yml with: runs_on: x64-kernel-build-node job_display_name: Build Wheel - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true }} secrets: inherit sgl-kernel-build-wheels-arm: needs: [check-changes, call-gate] - # Skip for scheduled runs (they run stages independently). Runs in target_stage mode only when - # include_wheel_build is true (i.e. /rerun-stage on a PR with sgl-kernel changes). - # - # See sgl-kernel-build-wheels above for the always() + result-check rationale. + # Skip for scheduled runs (they run stages independently). if: | - always() && github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && needs.check-changes.result == 'success' && needs.check-changes.outputs.sgl_kernel == 'true' && - ( - (!inputs.target_stage && needs.call-gate.result == 'success') || - (inputs.target_stage && inputs.include_wheel_build) - ) + needs.call-gate.result == 'success' uses: ./.github/workflows/_pr-test-sgl-kernel-build.yml with: runs_on: arm-kernel-build-node job_display_name: Build Wheel Arm arch_suffix: '-aarch64' - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true }} secrets: inherit @@ -262,13 +216,11 @@ jobs: if: | github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && - !inputs.target_stage && needs.check-changes.outputs.sgl_kernel == 'true' uses: ./.github/workflows/pr-test-sgl-kernel.yml with: sgl_kernel: ${{ needs.check-changes.outputs.sgl_kernel }} b200_runner: ${{ needs.check-changes.outputs.b200_runner }} - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true }} secrets: inherit @@ -282,16 +234,13 @@ jobs: !failure() && !cancelled() && github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && - !inputs.target_stage && needs.check-changes.outputs.jit_kernel == 'true' uses: ./.github/workflows/pr-test-jit-kernel.yml with: jit_kernel: ${{ needs.check-changes.outputs.jit_kernel }} sgl_kernel: ${{ needs.check-changes.outputs.sgl_kernel }} b200_runner: ${{ needs.check-changes.outputs.b200_runner }} - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} - target_stage: ${{ inputs.target_stage || '' }} test_parallel_dispatch: ${{ inputs.test_parallel_dispatch == true && 'true' || 'false' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true }} secrets: inherit @@ -317,14 +266,8 @@ jobs: needs: [check-changes, call-gate] if: | always() && - ( - (inputs.target_stage == 'stage-a-test-cpu') || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && - (needs.check-changes.outputs.main_package == 'true') - ) - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + (needs.check-changes.outputs.main_package == 'true') runs-on: ubuntu-latest timeout-minutes: 240 strategy: @@ -341,7 +284,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }} + ref: ${{ inputs.git_ref || github.sha }} - uses: ./.github/actions/check-stage-health @@ -449,29 +392,15 @@ jobs: if: | always() && !cancelled() && - ( - inputs.target_stage == 'multimodal-gen-test-1-gpu' || - inputs.target_stage == 'multimodal-gen-test-2-gpu' || - inputs.target_stage == 'multimodal-gen-component-accuracy' || - inputs.target_stage == 'multimodal-gen-component-accuracy-1-gpu' || - inputs.target_stage == 'multimodal-gen-component-accuracy-2-gpu' || - inputs.target_stage == 'multimodal-gen-test-1-b200' || - inputs.target_stage == 'multimodal-gen-unit-test' || - ( - !inputs.target_stage && - ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && - needs.check-changes.outputs.multimodal_gen == 'true' - ) - ) + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + needs.check-changes.outputs.multimodal_gen == 'true' uses: ./.github/workflows/pr-test-multimodal-gen.yml with: multimodal_gen: ${{ needs.check-changes.outputs.multimodal_gen }} sgl_kernel: ${{ needs.check-changes.outputs.sgl_kernel }} b200_runner: ${{ needs.check-changes.outputs.b200_runner }} continue_on_error: ${{ needs.check-changes.outputs.continue_on_error }} - pr_head_sha: ${{ inputs.pr_head_sha || '' }} git_ref: ${{ inputs.git_ref || '' }} - target_stage: ${{ inputs.target_stage || '' }} test_parallel_dispatch: ${{ inputs.test_parallel_dispatch == true && 'true' || 'false' }} caller_needs_failure: ${{ (needs.call-gate.result == 'failure' || needs.sgl-kernel-build-wheels.result == 'failure' || needs.check-changes.result == 'failure') && 'true' || 'false' }} skip_stage_health_check: ${{ inputs.skip_stage_health_check == true && 'true' || 'false' }} diff --git a/scripts/ci/utils/slash_command_handler.py b/scripts/ci/utils/slash_command_handler.py index 4c29a996f..9beb2f842 100644 --- a/scripts/ci/utils/slash_command_handler.py +++ b/scripts/ci/utils/slash_command_handler.py @@ -20,7 +20,7 @@ def _check_rebase_gate(gh_repo, pr, token): """ Pre-dispatch gate mirroring `.github/actions/check-maintenance/action.yml`. - Without this, /rerun-stage and /rerun-test would dispatch a workflow_run + Without this, /rerun-test would dispatch a workflow_run on a PR that's behind a required base, the action would catch it, and every job in the run would fail at the gate — wasting runner time and producing N error annotations instead of one comment. Pre-checking here @@ -388,221 +388,6 @@ def handle_rerun_failed_ci(gh_repo, pr, comment, user_perms, react_on_success=Tr return False -def handle_rerun_stage( - gh_repo, pr, comment, user_perms, stage_name, token, react_on_success=True -): - """ - Handles the /rerun-stage command. - Triggers a workflow_dispatch to run only the specified stage, skipping dependencies. - Returns True if action was taken, False otherwise. - """ - if not user_perms.get("can_rerun_stage", False): - print("Permission denied: can_rerun_stage is false.") - return False - - if not stage_name: - print("Error: No stage name provided") - comment.create_reaction("confused") - pr.create_issue_comment( - f"⛔ Please specify a stage name: `/rerun-stage `\n\n" - f"Examples: `/rerun-stage unit-test-backend-4-gpu`, `/rerun-stage accuracy-test-1-gpu`" - ) - return False - - print(f"Permission granted. Triggering workflow_dispatch for stage '{stage_name}'.") - - # Valid NVIDIA stage names that support target_stage - nvidia_stages = [ - "stage-a-test-1-gpu-small", - "stage-a-test-cpu", - "stage-b-test-1-gpu-small", - "stage-b-test-1-gpu-large", - "stage-b-test-2-gpu-large", - "stage-b-test-4-gpu-b200", - "stage-c-test-4-gpu-h100", - "stage-c-test-8-gpu-h200", - "stage-c-test-8-gpu-h20", - "stage-c-test-4-gpu-b200", - "stage-c-test-4-gpu-gb200", - "stage-c-test-dsv4-4-gpu-b200", - "stage-c-test-dsv4-8-gpu-h200", - "stage-c-test-deepep-4-gpu-h100", - "stage-c-test-deepep-8-gpu-h200", - "stage-c-test-dsv4-4-gpu-b200", - "stage-c-test-dsv4-8-gpu-h200", - "multimodal-gen-test-1-gpu", - "multimodal-gen-test-2-gpu", - "multimodal-gen-component-accuracy", - "multimodal-gen-component-accuracy-1-gpu", - "multimodal-gen-component-accuracy-2-gpu", - "multimodal-gen-test-1-b200", - ] - - # Valid AMD stage names that support target_stage - amd_stages = [ - "sgl-kernel-unit-test-amd", - "sgl-kernel-unit-test-2-gpu-amd", - "stage-a-test-1-gpu-small-amd", - "stage-b-test-1-gpu-small-amd", - "stage-b-test-1-gpu-small-amd-nondeterministic", - "stage-b-test-1-gpu-small-amd-mi35x", - "stage-b-test-1-gpu-large-amd", - "stage-b-test-2-gpu-large-amd", - "multimodal-gen-test-1-gpu-amd", - "multimodal-gen-test-2-gpu-amd", - "stage-c-test-large-8-gpu-amd", - "stage-c-test-large-8-gpu-amd-mi35x", - ] - - valid_stages = nvidia_stages + amd_stages - is_amd_stage = stage_name in amd_stages - - if stage_name not in valid_stages: - comment.create_reaction("confused") - pr.create_issue_comment( - f"⛔ Stage `{stage_name}` doesn't support isolated runs yet.\n\n" - f"**NVIDIA stages:**\n" - + "\n".join(f"- `{s}`" for s in nvidia_stages) - + "\n\n**AMD stages:**\n" - + "\n".join(f"- `{s}`" for s in amd_stages) - + "\n\nOther stages will be added soon. For now, use `/rerun-failed-ci` for those stages." - ) - return False - - allowed, gate_msg = _check_rebase_gate(gh_repo, pr, token) - if not allowed: - comment.create_reaction("confused") - pr.create_issue_comment(gate_msg) - return False - - try: - # Get the appropriate workflow based on stage type - workflow_name = "PR Test (AMD)" if is_amd_stage else "PR Test" - workflows = gh_repo.get_workflows() - target_workflow = None - for wf in workflows: - if wf.name == workflow_name: - target_workflow = wf - break - - if not target_workflow: - print(f"Error: {workflow_name} workflow not found") - return False - - # Check if PR is from a fork by comparing repo owners - # Handle case where fork repo may have been deleted (pr.head.repo is None) - is_fork = ( - pr.head.repo is None or pr.head.repo.owner.login != gh_repo.owner.login - ) - print(f"PR is from fork: {is_fork}") - - # If the PR modifies sgl-kernel/, the target stage would otherwise use the - # PyPI sgl-kernel wheel instead of the PR's changes (sgl-kernel-build-wheels - # skips in target_stage mode by default). Set include_wheel_build=true so the - # workflow runs sgl-kernel-build-wheels alongside the target stage; the target - # stage waits for the build via its needs list. - kernel_changes = has_sgl_kernel_changes(pr) - if kernel_changes: - print( - "PR modifies sgl-kernel/ - setting include_wheel_build=true so the " - "target stage gets the freshly-built wheel instead of the PyPI one." - ) - - # pr_head_sha is used for fork PRs (passed to workflow and used for URL lookup) - pr_head_sha = None - - if is_fork: - # For fork PRs: dispatch on main and pass SHA as input - # This is needed because fork branch names don't exist in the main repo - ref = "main" - pr_head_sha = pr.head.sha - print( - f"Triggering {workflow_name} workflow on ref: {ref}, PR head SHA: {pr_head_sha}" - ) - inputs = { - "target_stage": stage_name, - "pr_head_sha": pr_head_sha, - } - else: - # For non-fork PRs: dispatch on the PR branch directly - # This allows testing workflow changes before merge - ref = pr.head.ref - print(f"Triggering {workflow_name} workflow on branch: {ref}") - inputs = {"target_stage": stage_name} - - # For NVIDIA stages, honor the sgl-kernel / include_wheel_build flow. AMD is - # a separate workflow that doesn't share the same wheel-build pipeline. - if kernel_changes and not is_amd_stage: - inputs["include_wheel_build"] = "true" - # include_wheel_build relies on filter-api detecting kernel changes, which - # requires pr_head_sha. Ensure it's set even for non-fork PRs, and keep - # the local pr_head_sha in sync so find_workflow_run_url builds the - # expected display_title with the SHA suffix (the workflow's run-name - # includes the SHA whenever inputs.pr_head_sha is set). - if not is_fork: - inputs["pr_head_sha"] = pr.head.sha - pr_head_sha = pr.head.sha - - # Record dispatch time before triggering - dispatch_time = time.time() - - # Use requests directly as PyGithub's create_dispatch only accepts HTTP 204 - dispatch_url = f"https://api.github.com/repos/{gh_repo.full_name}/actions/workflows/{target_workflow.id}/dispatches" - dispatch_resp = requests.post( - dispatch_url, - json={"ref": ref, "inputs": inputs}, - headers={ - "Authorization": f"Bearer {token}", - "Accept": "application/vnd.github+json", - }, - ) - success = dispatch_resp.status_code in (200, 204) - if not success: - print(f"Dispatch failed: {dispatch_resp.status_code} {dispatch_resp.text}") - - if success: - print(f"Successfully triggered workflow for stage '{stage_name}'") - if react_on_success: - comment.create_reaction("+1") - - run_url = find_workflow_run_url( - gh_repo, - target_workflow.id, - ref, - stage_name, - token, - dispatch_time, - pr_head_sha=pr_head_sha, - max_wait=30, - ) - if run_url: - pr.create_issue_comment( - f"🚀 Triggered `{stage_name}` to run independently" - f" (skipping dependencies)." - f" [View workflow run]({run_url})" - ) - else: - pr.create_issue_comment( - f"🚀 Triggered `{stage_name}` to run independently" - f" (skipping dependencies).\n" - f"⚠️ Could not retrieve workflow run URL. " - f"Check the [Actions tab](https://github.com/{gh_repo.full_name}/actions) for progress." - ) - return True - else: - print("Failed to trigger workflow_dispatch") - return False - - except Exception as e: - print(f"Error triggering workflow_dispatch: {e}") - comment.create_reaction("confused") - pr.create_issue_comment( - f"⛔ Failed to trigger workflow: {str(e)}\n\n" - f"Please check the logs or contact maintainers." - ) - return False - - CUDA_SUITE_TO_RUNNER = { # PR test suites "stage-a-test-1-gpu-small": "1-gpu-5090", @@ -1259,7 +1044,7 @@ def main(): # PR authors can always rerun failed CI and rerun individual UTs on their own PRs, # even if they are not listed in CI_PERMISSIONS.json. - # Note: /tag-run-ci-label and /rerun-stage still require CI_PERMISSIONS.json. + # Note: /tag-run-ci-label still requires CI_PERMISSIONS.json. # Note: /rerun-test is blocked entirely for fork PRs in handle_rerun_test() itself. if pr.user.login == user_login: if user_perms is None: @@ -1313,10 +1098,33 @@ def main(): print("Combined command finished, but no actions were taken.") elif first_line.startswith("/rerun-stage"): - # Extract stage name from command - parts = first_line.split(maxsplit=1) - stage_name = parts[1].strip() if len(parts) > 1 else None - handle_rerun_stage(repo, pr, comment, user_perms, stage_name, token) + # /rerun-stage is deprecated. Stage-level granularity is too coarse to map to + # a specific feature, and a stage rerun re-pays the cost of all unrelated tests + # in that stage. Use /rerun-test for selective UT runs, or /rerun-failed-ci / + # `run-ci` / `run-ci-extra` labels for a full rerun. + print("/rerun-stage is deprecated; posting deprecation notice.") + comment.create_reaction("-1") + pr.create_issue_comment( + "⚠️ **`/rerun-stage` has been deprecated.**\n\n" + "Stage granularity is too coarse — a stage usually doesn't map to one " + "feature, so rerunning a stage re-pays the cost of unrelated tests. " + "If you don't know which exact test files to rerun, you shouldn't be " + "using `/rerun-stage` or `/rerun-test` in the first place.\n\n" + "**Use one of these instead:**\n" + "- **Selective tests** (you know exactly which files to rerun):\n" + " ```\n" + " /rerun-test test_foo.py test_bar.py\n" + " ```\n" + "- **Rerun only failed jobs**:\n" + " ```\n" + " /rerun-failed-ci\n" + " ```\n" + "- **Full CI rerun** (with extra coverage): add the `run-ci` or " + "`run-ci-extra` label and push a new commit (or use `/tag-and-rerun-ci`).\n\n" + "**AMD CI**: stage-level dispatch is still available via " + "Actions UI → *PR Test (AMD)* / *PR Test ROCm 7.2 (AMD)* → " + "*Run workflow* → pick a stage from the dropdown." + ) elif first_line.startswith("/rerun-group"): group_names = first_line.split()[1:]