Skip to content

Commit 52ac6fd

Browse files
committed
ci: separate Community CI coordination
Keep the Stable executor contract unchanged while moving trusted snapshot and lane tracking into a dedicated coordinator. Show Stable and Dev as explicit advisory branches and keep executor failures linked to their own runs. Signed-off-by: chaofengw <chaofengw@nvidia.com>
1 parent 16847dd commit 52ac6fd

3 files changed

Lines changed: 440 additions & 320 deletions

File tree

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Track a Community CI lane
5+
description: Dispatch or reuse one Community CI run and publish its exact result.
6+
7+
inputs:
8+
token:
9+
description: GitHub token used to dispatch, inspect, and publish the run.
10+
required: true
11+
lane:
12+
description: Stable or Dev execution lane.
13+
required: true
14+
ci-ref:
15+
description: Branch containing the selected Community CI implementation.
16+
required: true
17+
pr-number:
18+
description: Pull request number.
19+
required: true
20+
head-sha:
21+
description: Frozen pull request head SHA.
22+
required: true
23+
source-snapshot:
24+
description: Frozen pull request source snapshot.
25+
required: true
26+
stable-run-id:
27+
description: Existing Stable pull_request run to reuse when available.
28+
required: false
29+
default: ""
30+
run-gpu-smoke:
31+
description: Whether a manual request enabled the GPU smoke test.
32+
required: false
33+
default: "false"
34+
status-context:
35+
description: Commit status context for this lane.
36+
required: true
37+
38+
runs:
39+
using: composite
40+
steps:
41+
- name: Mark the selected CI pending
42+
shell: bash
43+
env:
44+
GH_TOKEN: ${{ inputs.token }}
45+
HEAD_SHA: ${{ inputs.head-sha }}
46+
STATUS_CONTEXT: ${{ inputs.status-context }}
47+
run: |
48+
set -euo pipefail
49+
gh api --silent --method POST \
50+
"/repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \
51+
-f state=pending -f context="$STATUS_CONTEXT" \
52+
-f description="Community CI is starting" \
53+
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"
54+
55+
- name: Dispatch the selected Community CI implementation
56+
id: execution
57+
shell: bash
58+
env:
59+
GH_TOKEN: ${{ inputs.token }}
60+
PR_NUMBER: ${{ inputs.pr-number }}
61+
CI_REF: ${{ inputs.ci-ref }}
62+
LANE: ${{ inputs.lane }}
63+
SOURCE_SNAPSHOT: ${{ inputs.source-snapshot }}
64+
HEAD_SHA: ${{ inputs.head-sha }}
65+
STABLE_RUN_ID: ${{ inputs.stable-run-id }}
66+
RUN_GPU_SMOKE: ${{ inputs.run-gpu-smoke }}
67+
STATUS_CONTEXT: ${{ inputs.status-context }}
68+
run: |
69+
set -euo pipefail
70+
if [ "$LANE" = stable ] && [ -n "${STABLE_RUN_ID:-}" ]; then
71+
[[ "$STABLE_RUN_ID" =~ ^[1-9][0-9]*$ ]]
72+
echo "run_id=$STABLE_RUN_ID" >> "$GITHUB_OUTPUT"
73+
echo "ci_ref=main" >> "$GITHUB_OUTPUT"
74+
echo "existing_stable=true" >> "$GITHUB_OUTPUT"
75+
exit 0
76+
fi
77+
78+
umask 077
79+
dispatch_nonce="$(openssl rand -hex 16)"
80+
[[ "$dispatch_nonce" =~ ^[0-9a-f]{32}$ ]]
81+
payload="$RUNNER_TEMP/community-ci-${LANE}-dispatch.json"
82+
trap 'rm -f "$payload"' EXIT
83+
jq -n \
84+
--arg pr_number "$PR_NUMBER" \
85+
--arg ref "$CI_REF" \
86+
--arg lane "$LANE" \
87+
--arg snapshot "$SOURCE_SNAPSHOT" \
88+
--arg dispatch_nonce "$dispatch_nonce" \
89+
--argjson run_gpu_smoke "${RUN_GPU_SMOKE:-false}" \
90+
'{
91+
ref: $ref,
92+
return_run_details: true,
93+
inputs: {
94+
pr_number: $pr_number,
95+
ci_lane: $lane,
96+
source_snapshot: $snapshot,
97+
request_id: $dispatch_nonce,
98+
run_gpu_smoke: $run_gpu_smoke
99+
}
100+
}' > "$payload"
101+
dispatched="$(gh api --method POST \
102+
-H 'X-GitHub-Api-Version: 2026-03-10' \
103+
"/repos/$GITHUB_REPOSITORY/actions/workflows/community-ci.yml/dispatches" \
104+
--input "$payload")"
105+
run_id="$(jq -er '.workflow_run_id' <<< "$dispatched")"
106+
[[ "$run_id" =~ ^[1-9][0-9]*$ ]]
107+
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
108+
echo "ci_ref=$CI_REF" >> "$GITHUB_OUTPUT"
109+
gh api --silent --method POST \
110+
"/repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \
111+
-f state=pending -f context="$STATUS_CONTEXT" \
112+
-f description="Community CI is running" \
113+
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$run_id"
114+
115+
- name: Publish the complete workflow conclusion
116+
id: verdict
117+
shell: bash
118+
env:
119+
GH_TOKEN: ${{ inputs.token }}
120+
PIPELINE_RUN_ID: ${{ steps.execution.outputs.run_id }}
121+
EXISTING_STABLE: ${{ steps.execution.outputs.existing_stable }}
122+
CI_BRANCH: ${{ steps.execution.outputs.ci_ref }}
123+
LANE: ${{ inputs.lane }}
124+
PR_NUMBER: ${{ inputs.pr-number }}
125+
HEAD_SHA: ${{ inputs.head-sha }}
126+
SOURCE_SNAPSHOT: ${{ inputs.source-snapshot }}
127+
STATUS_CONTEXT: ${{ inputs.status-context }}
128+
run: |
129+
set -euo pipefail
130+
[[ "$PIPELINE_RUN_ID" =~ ^[1-9][0-9]*$ ]]
131+
role=Stable
132+
if [ "$LANE" = dev ]; then role=Dev; else test "$CI_BRANCH" = main; fi
133+
merge_sha="$(jq -er '.merge_sha' <<< "$SOURCE_SNAPSHOT")"
134+
expected_title="$role Community CI · PR #$PR_NUMBER · head $HEAD_SHA · merge $merge_sha"
135+
if [ "${EXISTING_STABLE:-}" = true ]; then
136+
test "$LANE" = stable
137+
expected_title="PR #$PR_NUMBER · community CI · head $HEAD_SHA · merge $merge_sha"
138+
fi
139+
deadline=$((SECONDS + 18000))
140+
while [ "$SECONDS" -lt "$deadline" ]; do
141+
run="$(gh api "/repos/$GITHUB_REPOSITORY/actions/runs/$PIPELINE_RUN_ID")"
142+
if [ "$(jq -r '.status' <<< "$run")" = completed ]; then
143+
if ! jq -e --arg title "$expected_title" --arg branch "$CI_BRANCH" \
144+
--arg head "$HEAD_SHA" --arg existing "${EXISTING_STABLE:-false}" \
145+
'.path == ".github/workflows/community-ci.yml" and .display_title == $title
146+
and (if $existing == "true" then .event == "pull_request" and .head_sha == $head
147+
else .event == "workflow_dispatch" and .head_branch == $branch end)' \
148+
<<< "$run" > /dev/null; then
149+
echo "::error::Completed Community CI does not match the requested branch and snapshot."
150+
jq '{path,event,head_branch,display_title,status}' <<< "$run"
151+
exit 1
152+
fi
153+
state=failure
154+
if [ "$(jq -r '.conclusion' <<< "$run")" = success ]; then state=success; fi
155+
gh api --silent --method POST \
156+
"/repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \
157+
-f state="$state" -f context="$STATUS_CONTEXT" \
158+
-f description="Complete Community CI: $state" \
159+
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$PIPELINE_RUN_ID"
160+
echo "reported=true" >> "$GITHUB_OUTPUT"
161+
icon='❌'
162+
if [ "$state" = success ]; then icon='✅'; fi
163+
printf '### %s Community CI\n\n%s `%s` · [execution run](%s/%s/actions/runs/%s)\n' \
164+
"$role" "$icon" "$state" "$GITHUB_SERVER_URL" "$GITHUB_REPOSITORY" \
165+
"$PIPELINE_RUN_ID" >> "$GITHUB_STEP_SUMMARY"
166+
# The executor and its commit status own the validation verdict.
167+
# This coordinator fails only when it cannot establish or publish it.
168+
if [ "$state" != success ]; then
169+
echo "::warning::$role Community CI failed; the lane result links to run $PIPELINE_RUN_ID."
170+
fi
171+
exit 0
172+
fi
173+
sleep 30
174+
done
175+
echo "::error::Community CI did not complete within five hours."
176+
exit 1
177+
178+
- name: Report a failed CI request
179+
if: ${{ failure() && steps.verdict.outputs.reported != 'true' }}
180+
shell: bash
181+
env:
182+
GH_TOKEN: ${{ inputs.token }}
183+
HEAD_SHA: ${{ inputs.head-sha }}
184+
STATUS_CONTEXT: ${{ inputs.status-context }}
185+
run: |
186+
set -euo pipefail
187+
gh api --silent --method POST \
188+
"/repos/$GITHUB_REPOSITORY/statuses/$HEAD_SHA" \
189+
-f state=failure -f context="$STATUS_CONTEXT" \
190+
-f description="Community CI could not complete" \
191+
-f target_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID"

0 commit comments

Comments
 (0)