pr-states: dispatch from pr-test* notify job (fix rerun status) (#25812)
This commit is contained in:
@@ -2,26 +2,38 @@ name: PR States
|
|||||||
# Maintains the CI-states block at the bottom of the PR body. Uses
|
# Maintains the CI-states block at the bottom of the PR body. Uses
|
||||||
# pull_request_target (not pull_request) for fork-PR write access; safe
|
# pull_request_target (not pull_request) for fork-PR write access; safe
|
||||||
# because we never check out PR head code, only API-read and PATCH the body.
|
# because we never check out PR head code, only API-read and PATCH the body.
|
||||||
|
#
|
||||||
|
# Three triggers, each covering a gap:
|
||||||
|
# - pull_request_target: push / open / label change (all PRs incl forks).
|
||||||
|
# - workflow_run: initial pr-test* completion (incl fork PRs; the
|
||||||
|
# notify-job below can't fire on forks — their pull_request
|
||||||
|
# GITHUB_TOKEN is forced read-only). Does NOT re-fire for rerun
|
||||||
|
# attempts, which is why workflow_dispatch is needed too.
|
||||||
|
# - workflow_dispatch: rerun completions for non-fork PRs, dispatched by
|
||||||
|
# pr-test*'s notify-pr-states job. workflow_dispatch is the only event
|
||||||
|
# GITHUB_TOKEN can cascade-create.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||||
workflow_run:
|
workflow_run:
|
||||||
# Listen to pr-test* lifecycle so reruns initiated by slash commands
|
|
||||||
# (run.rerun / run.rerun_failed_jobs via GITHUB_TOKEN) -- which don't
|
|
||||||
# refire pull_request_target -- still refresh the CI-states block.
|
|
||||||
workflows: ["PR Test Base", "PR Test Extra"]
|
workflows: ["PR Test Base", "PR Test Extra"]
|
||||||
types: [requested, completed]
|
types: [requested, completed]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
pr_number:
|
||||||
|
description: 'PR number whose CI-states block should be refreshed.'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
actions: read
|
actions: read
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
# Dedupe per commit SHA across both event sources so simultaneous
|
# Per-SHA dedupe (PR number for workflow_dispatch). Queues concurrent
|
||||||
# synchronize + workflow_run firings on the same push queue instead
|
# fires across the three triggers so they don't race on the body PATCH.
|
||||||
# of racing on the body PATCH.
|
group: pr-states-${{ github.event.pull_request.head.sha || github.event.workflow_run.head_sha || inputs.pr_number }}
|
||||||
group: pr-states-${{ github.event.pull_request.head.sha || github.event.workflow_run.head_sha }}
|
|
||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -40,14 +52,16 @@ jobs:
|
|||||||
|
|
||||||
// Event-agnostic PR lookup.
|
// Event-agnostic PR lookup.
|
||||||
// - pull_request_target: PR is in the payload.
|
// - pull_request_target: PR is in the payload.
|
||||||
// - workflow_run: pull_requests[] is populated for same-repo PRs;
|
// - workflow_run: pull_requests[] is populated for same-repo
|
||||||
// fork PRs need a head-ref reverse lookup ("forkOwner:branch")
|
// PRs; fork PRs need a head-ref reverse lookup
|
||||||
// because listPullRequestsAssociatedWithCommit requires the commit
|
// ("forkOwner:branch") because
|
||||||
// to be in the default branch. Bail when no open PR matches.
|
// listPullRequestsAssociatedWithCommit requires the commit to
|
||||||
|
// be in the default branch. Bail when no open PR matches.
|
||||||
|
// - workflow_dispatch: pr_number is an explicit input.
|
||||||
let prNumber;
|
let prNumber;
|
||||||
if (context.payload.pull_request) {
|
if (context.payload.pull_request) {
|
||||||
prNumber = context.payload.pull_request.number;
|
prNumber = context.payload.pull_request.number;
|
||||||
} else {
|
} else if (context.eventName === 'workflow_run') {
|
||||||
const wr = context.payload.workflow_run;
|
const wr = context.payload.workflow_run;
|
||||||
if (wr.pull_requests && wr.pull_requests.length > 0) {
|
if (wr.pull_requests && wr.pull_requests.length > 0) {
|
||||||
prNumber = wr.pull_requests[0].number;
|
prNumber = wr.pull_requests[0].number;
|
||||||
@@ -71,6 +85,18 @@ jobs:
|
|||||||
core.info(`workflow_run has no PR linkage; skipping.`);
|
core.info(`workflow_run has no PR linkage; skipping.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (context.eventName === 'workflow_dispatch') {
|
||||||
|
// Reject non-digit pr_number; parseInt('123abc', 10) returns
|
||||||
|
// 123 and would silently truncate trailing garbage.
|
||||||
|
const raw = context.payload.inputs.pr_number;
|
||||||
|
if (!/^\d+$/.test(raw)) {
|
||||||
|
core.setFailed(`workflow_dispatch: invalid pr_number input '${raw}' (must be digits only)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prNumber = parseInt(raw, 10);
|
||||||
|
} else {
|
||||||
|
core.info(`Unsupported event '${context.eventName}'; skipping.`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const { data: pr } = await github.rest.pulls.get({
|
const { data: pr } = await github.rest.pulls.get({
|
||||||
owner: context.repo.owner,
|
owner: context.repo.owner,
|
||||||
|
|||||||
@@ -221,3 +221,67 @@ jobs:
|
|||||||
partitions: ${{ needs.check-changes.outputs.partitions }}
|
partitions: ${{ needs.check-changes.outputs.partitions }}
|
||||||
run_timeout_minutes: '60'
|
run_timeout_minutes: '60'
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
# =============================================== aggregator ====================================================
|
||||||
|
# Mirrors pr-test.yml's `pr-test-finish` so notify-pr-states below only
|
||||||
|
# depends on one job rather than re-listing every stage. Fails if any
|
||||||
|
# dependent failed/cancelled.
|
||||||
|
pr-test-extra-finish:
|
||||||
|
needs:
|
||||||
|
[
|
||||||
|
check-changes,
|
||||||
|
call-gate,
|
||||||
|
sgl-kernel-build-wheels,
|
||||||
|
extra-a-test-1-gpu-small,
|
||||||
|
extra-a-test-1-gpu-large,
|
||||||
|
extra-a-test-2-gpu-large,
|
||||||
|
extra-b-test-4-gpu-h100,
|
||||||
|
extra-b-test-4-gpu-b200,
|
||||||
|
extra-b-test-8-gpu-h200,
|
||||||
|
extra-b-test-deepep-8-gpu-h200,
|
||||||
|
]
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check all dependent job statuses
|
||||||
|
run: |
|
||||||
|
json_needs='${{ toJson(needs) }}'
|
||||||
|
job_names=$(echo "$json_needs" | jq -r 'keys_unsorted[]')
|
||||||
|
for job in $job_names; do
|
||||||
|
result=$(echo "$json_needs" | jq -r --arg j "$job" '.[$j].result')
|
||||||
|
echo "$job: $result"
|
||||||
|
if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then
|
||||||
|
echo "The above jobs failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "All jobs completed successfully"
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# =============================================== notify pr-states ====================================================
|
||||||
|
# Dispatches pr-states.yml after every attempt (initial + every rerun).
|
||||||
|
# workflow_run.completed only fires on the initial completion (one
|
||||||
|
# workflow_run record across attempts), so we explicitly dispatch —
|
||||||
|
# workflow_dispatch is the only event GITHUB_TOKEN can cascade-create.
|
||||||
|
#
|
||||||
|
# Fork PRs are excluded: their pull_request GITHUB_TOKEN is forced
|
||||||
|
# read-only regardless of declared `actions: write`, so dispatch 403s.
|
||||||
|
# Fork PRs get pr-states updates via the workflow_run subscription
|
||||||
|
# there (initial completion) and pull_request_target (push / label).
|
||||||
|
notify-pr-states:
|
||||||
|
needs: [pr-test-extra-finish]
|
||||||
|
if: |
|
||||||
|
always() &&
|
||||||
|
github.event_name == 'pull_request' &&
|
||||||
|
github.event.pull_request.head.repo.full_name == github.repository
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Dispatch pr-states refresh
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
gh workflow run pr-states.yml \
|
||||||
|
--repo ${{ github.repository }} \
|
||||||
|
--ref main \
|
||||||
|
-f pr_number="$PR_NUMBER"
|
||||||
|
|||||||
@@ -563,3 +563,31 @@ jobs:
|
|||||||
# If the loop completes, all jobs were successful
|
# If the loop completes, all jobs were successful
|
||||||
echo "All jobs completed successfully"
|
echo "All jobs completed successfully"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
# =============================================== notify pr-states ====================================================
|
||||||
|
# Dispatches pr-states.yml after every attempt (initial + every rerun).
|
||||||
|
# workflow_run.completed only fires on the initial completion (one
|
||||||
|
# workflow_run record across attempts), so we explicitly dispatch —
|
||||||
|
# workflow_dispatch is the only event GITHUB_TOKEN can cascade-create.
|
||||||
|
#
|
||||||
|
# Fork PRs are excluded: their pull_request GITHUB_TOKEN is forced
|
||||||
|
# read-only regardless of declared `actions: write`, so dispatch 403s.
|
||||||
|
# Fork PRs get pr-states updates via the workflow_run subscription
|
||||||
|
# there (initial completion) and pull_request_target (push / label).
|
||||||
|
notify-pr-states:
|
||||||
|
needs: [pr-test-finish]
|
||||||
|
if: |
|
||||||
|
always() &&
|
||||||
|
github.event_name == 'pull_request' &&
|
||||||
|
github.event.pull_request.head.repo.full_name == github.repository
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Dispatch pr-states refresh
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
|
run: |
|
||||||
|
gh workflow run pr-states.yml \
|
||||||
|
--repo ${{ github.repository }} \
|
||||||
|
--ref main \
|
||||||
|
-f pr_number="$PR_NUMBER"
|
||||||
|
|||||||
Reference in New Issue
Block a user