Skip to content

Commit cc7340a

Browse files
committed
ci: add OS-49 phase 5 shadow workflows
Signed-off-by: Jonas Toelke <jtoelke@nvidia.com>
1 parent 78f0b6f commit cc7340a

9 files changed

Lines changed: 490 additions & 11 deletions

File tree

.github/actions/pr-gate/action.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ name: PR Gate
22
description: >
33
Resolve PR metadata for a `pull-request/<N>` push from copy-pr-bot and decide
44
whether the workflow should run. Sets `should-run=true` only when the pushed
5-
SHA still matches the PR head SHA and the PR carries the required label. For
6-
non-`push` events (e.g. `workflow_dispatch`), always sets `should-run=true`.
5+
SHA still matches the PR head SHA. If `required_label` is provided, the PR
6+
must also carry that label. For non-`push` events (e.g. `workflow_dispatch`),
7+
always sets `should-run=true`.
78
89
inputs:
910
required_label:
10-
description: PR label required to enable the run (e.g. "test:e2e").
11-
required: true
11+
description: Optional PR label required to enable the run (e.g. "test:e2e").
12+
required: false
13+
default: ""
1214

1315
outputs:
1416
should_run:
@@ -43,10 +45,14 @@ runs:
4345
fi
4446
4547
head_sha="$(jq -r '.head.sha' <<< "$PR_INFO")"
46-
has_label="$(jq -r --arg L "$REQUIRED_LABEL" '[.labels[].name] | index($L) != null' <<< "$PR_INFO")"
48+
if [ -z "$REQUIRED_LABEL" ]; then
49+
has_label=true
50+
else
51+
has_label="$(jq -r --arg L "$REQUIRED_LABEL" '[.labels[].name] | index($L) != null' <<< "$PR_INFO")"
52+
fi
4753
4854
# Only trust copied pull-request/* pushes that still match the PR head
49-
# SHA and carry the required label.
55+
# SHA and, when configured, carry the required label.
5056
if [ "$head_sha" = "$GITHUB_SHA_VALUE" ] && [ "$has_label" = "true" ]; then
5157
should_run=true
5258
else

.github/workflows/docker-build.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ on:
3232
required: false
3333
type: string
3434
default: ""
35+
image-tag:
36+
description: "Image tag base to build/push (defaults to the GitHub SHA)"
37+
required: false
38+
type: string
39+
default: ""
3540

3641
env:
3742
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -55,6 +60,7 @@ jobs:
5560
binary_component: ${{ steps.resolve.outputs.binary_component }}
5661
binary_name: ${{ steps.resolve.outputs.binary_name }}
5762
artifact_prefix: ${{ steps.resolve.outputs.artifact_prefix }}
63+
image_tag_base: ${{ steps.resolve.outputs.image_tag_base }}
5864
steps:
5965
- name: Resolve component and platform matrix
6066
id: resolve
@@ -77,6 +83,11 @@ jobs:
7783
;;
7884
esac
7985
86+
image_tag_base="${{ inputs['image-tag'] }}"
87+
if [[ -z "$image_tag_base" ]]; then
88+
image_tag_base="$GITHUB_SHA"
89+
fi
90+
8091
platform_input="${{ inputs.platform }}"
8192
platform_input="${platform_input//[[:space:]]/}"
8293
if [[ -z "$platform_input" ]]; then
@@ -122,6 +133,7 @@ jobs:
122133
echo "binary_component=$binary_component"
123134
echo "binary_name=$binary_name"
124135
echo "artifact_prefix=rust-binary-${component}-${binary_component}"
136+
echo "image_tag_base=$image_tag_base"
125137
} >> "$GITHUB_OUTPUT"
126138
127139
rust-binary:
@@ -162,7 +174,7 @@ jobs:
162174
# inside the container so setup-buildx can read it.
163175
- /etc/buildkit:/etc/buildkit:ro
164176
env:
165-
IMAGE_TAG: ${{ needs.resolve.outputs.platform_count == '1' && github.sha || format('{0}-{1}', github.sha, matrix.arch) }}
177+
IMAGE_TAG: ${{ needs.resolve.outputs.platform_count == '1' && needs.resolve.outputs.image_tag_base || format('{0}-{1}', needs.resolve.outputs.image_tag_base, matrix.arch) }}
166178
IMAGE_REGISTRY: ghcr.io/nvidia/openshell
167179
DOCKER_PUSH: ${{ inputs.push && '1' || '0' }}
168180
DOCKER_PLATFORM: ${{ matrix.platform }}
@@ -264,9 +276,9 @@ jobs:
264276
image="ghcr.io/nvidia/openshell/${{ inputs.component }}"
265277
refs=()
266278
for arch in ${{ needs.resolve.outputs.arches }}; do
267-
refs+=("${image}:${GITHUB_SHA}-${arch}")
279+
refs+=("${image}:${{ needs.resolve.outputs.image_tag_base }}-${arch}")
268280
done
269281
docker buildx imagetools create \
270282
--prefer-index=false \
271-
-t "${image}:${GITHUB_SHA}" \
283+
-t "${image}:${{ needs.resolve.outputs.image_tag_base }}" \
272284
"${refs[@]}"
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
name: Shadow Branch Checks
2+
3+
# OS-129 Phase 5: non-required branch-check coverage on supported shared CPU
4+
# runners. Pull request coverage uses copy-pr-bot's trusted pull-request/*
5+
# mirror branches; workflow_dispatch is for ad hoc bake runs.
6+
7+
on:
8+
push:
9+
branches:
10+
- "pull-request/[0-9]+"
11+
workflow_dispatch:
12+
13+
permissions:
14+
contents: read
15+
packages: read
16+
17+
env:
18+
CARGO_TERM_COLOR: always
19+
CARGO_INCREMENTAL: "0"
20+
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
21+
SCCACHE_GHA_ENABLED: "true"
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
jobs:
28+
pr_metadata:
29+
name: Resolve PR metadata
30+
runs-on: ubuntu-latest
31+
permissions:
32+
contents: read
33+
pull-requests: read
34+
outputs:
35+
should_run: ${{ steps.gate.outputs.should_run }}
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- id: gate
40+
uses: ./.github/actions/pr-gate
41+
42+
mise-lockfile:
43+
name: mise Lockfile
44+
needs: pr_metadata
45+
if: needs.pr_metadata.outputs.should_run == 'true'
46+
runs-on: linux-amd64-cpu8
47+
container:
48+
image: ghcr.io/nvidia/openshell/ci:latest
49+
credentials:
50+
username: ${{ github.actor }}
51+
password: ${{ secrets.GITHUB_TOKEN }}
52+
steps:
53+
- uses: actions/checkout@v4
54+
55+
- name: Mark workspace as safe for git
56+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
57+
58+
- name: Detect mise config changes
59+
id: changed
60+
uses: tj-actions/changed-files@aa08304bd477b800d468db44fe10f6c61f7f7b11 # v42.1.0
61+
with:
62+
files: |
63+
mise.toml
64+
mise.lock
65+
66+
- name: Verify mise.lock is in sync with mise.toml
67+
if: steps.changed.outputs.any_changed == 'true'
68+
run: |
69+
mise lock
70+
if ! git diff --exit-code mise.lock; then
71+
echo "::error::mise.lock is out of sync with mise.toml. Run 'mise lock' locally and commit the result." >&2
72+
exit 1
73+
fi
74+
75+
license-headers:
76+
name: License Headers
77+
needs: pr_metadata
78+
if: needs.pr_metadata.outputs.should_run == 'true'
79+
runs-on: linux-amd64-cpu8
80+
container:
81+
image: ghcr.io/nvidia/openshell/ci:latest
82+
credentials:
83+
username: ${{ github.actor }}
84+
password: ${{ secrets.GITHUB_TOKEN }}
85+
steps:
86+
- uses: actions/checkout@v4
87+
88+
- name: Install tools
89+
run: mise install --locked
90+
91+
- name: Check license headers
92+
run: mise run license:check
93+
94+
rust:
95+
name: Rust (${{ matrix.runner }})
96+
needs: pr_metadata
97+
if: needs.pr_metadata.outputs.should_run == 'true'
98+
strategy:
99+
fail-fast: false
100+
matrix:
101+
runner: [linux-amd64-cpu8, linux-arm64-cpu8]
102+
runs-on: ${{ matrix.runner }}
103+
env:
104+
SCCACHE_GHA_VERSION: shadow-branch-checks-rust-${{ matrix.runner }}
105+
container:
106+
image: ghcr.io/nvidia/openshell/ci:latest
107+
credentials:
108+
username: ${{ github.actor }}
109+
password: ${{ secrets.GITHUB_TOKEN }}
110+
steps:
111+
- uses: actions/checkout@v4
112+
113+
- name: Install tools
114+
run: mise install --locked
115+
116+
- name: Configure GHA sccache backend
117+
uses: mozilla-actions/sccache-action@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
118+
119+
- name: Cache Rust target and registry
120+
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
121+
with:
122+
shared-key: shadow-branch-checks-rust-${{ matrix.runner }}
123+
cache-directories: .cache/sccache
124+
125+
- name: Format
126+
run: mise run rust:format:check
127+
128+
- name: Lint
129+
run: mise run rust:lint
130+
131+
- name: Test
132+
run: mise run test:rust
133+
134+
- name: sccache stats
135+
if: always()
136+
run: |
137+
set +e
138+
stats_bin="${SCCACHE_PATH:-sccache}"
139+
"$stats_bin" --show-stats
140+
status=$?
141+
if [[ $status -ne 0 ]]; then
142+
echo "::warning::sccache stats unavailable (exit $status)"
143+
fi
144+
exit 0
145+
146+
python:
147+
name: Python (${{ matrix.runner }})
148+
needs: pr_metadata
149+
if: needs.pr_metadata.outputs.should_run == 'true'
150+
strategy:
151+
fail-fast: false
152+
matrix:
153+
runner: [linux-amd64-cpu8, linux-arm64-cpu8]
154+
runs-on: ${{ matrix.runner }}
155+
container:
156+
image: ghcr.io/nvidia/openshell/ci:latest
157+
credentials:
158+
username: ${{ github.actor }}
159+
password: ${{ secrets.GITHUB_TOKEN }}
160+
steps:
161+
- uses: actions/checkout@v4
162+
163+
- name: Install tools
164+
run: mise install --locked
165+
166+
- name: Install dependencies
167+
run: uv sync --frozen
168+
169+
- name: Lint
170+
run: mise run python:lint
171+
172+
- name: Test
173+
run: mise run test:python
174+
175+
markdown:
176+
name: Markdown
177+
needs: pr_metadata
178+
if: needs.pr_metadata.outputs.should_run == 'true'
179+
runs-on: linux-amd64-cpu8
180+
container:
181+
image: ghcr.io/nvidia/openshell/ci:latest
182+
credentials:
183+
username: ${{ github.actor }}
184+
password: ${{ secrets.GITHUB_TOKEN }}
185+
steps:
186+
- uses: actions/checkout@v4
187+
188+
- name: Install tools
189+
run: mise install --locked
190+
191+
- name: Lint
192+
run: mise run markdown:lint
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Shadow Branch E2E
2+
3+
# OS-129 Phase 5: non-required Branch E2E coverage on supported shared CPU
4+
# runners. Trusted PR mirrors stay gated by the existing test:e2e label.
5+
6+
on:
7+
push:
8+
branches:
9+
- "pull-request/[0-9]+"
10+
workflow_dispatch:
11+
12+
permissions: {}
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
pr_metadata:
20+
name: Resolve PR metadata
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
pull-requests: read
25+
outputs:
26+
should_run: ${{ steps.gate.outputs.should_run }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- id: gate
31+
uses: ./.github/actions/pr-gate
32+
with:
33+
required_label: test:e2e
34+
35+
build-gateway:
36+
needs: [pr_metadata]
37+
if: needs.pr_metadata.outputs.should_run == 'true'
38+
permissions:
39+
contents: read
40+
packages: write
41+
uses: ./.github/workflows/docker-build.yml
42+
with:
43+
component: gateway
44+
platform: linux/arm64
45+
image-tag: shadow-branch-e2e-${{ github.sha }}
46+
secrets: inherit
47+
48+
build-cluster:
49+
needs: [pr_metadata]
50+
if: needs.pr_metadata.outputs.should_run == 'true'
51+
permissions:
52+
contents: read
53+
packages: write
54+
uses: ./.github/workflows/docker-build.yml
55+
with:
56+
component: cluster
57+
platform: linux/arm64
58+
image-tag: shadow-branch-e2e-${{ github.sha }}
59+
secrets: inherit
60+
61+
e2e:
62+
needs: [pr_metadata, build-gateway, build-cluster]
63+
if: needs.pr_metadata.outputs.should_run == 'true'
64+
permissions:
65+
contents: read
66+
packages: read
67+
uses: ./.github/workflows/e2e-test.yml
68+
with:
69+
image-tag: shadow-branch-e2e-${{ github.sha }}
70+
runner: linux-arm64-cpu8
71+
secrets: inherit

0 commit comments

Comments
 (0)