44#
55# The Rust binary stands alone (USB-stick-portable, single-machine). chapel/ is
66# a detachable multi-machine harness on top. This workflow exercises the harness
7- # and the Rust↔Chapel contract surface. Path triggers are scoped so a pure-Rust
8- # PR that doesn't touch chapel/ or src/main.rs leaves these jobs unrun, and
9- # removing chapel/ entirely leaves the Rust CI path (rust-ci.yml) green.
7+ # and the Rust↔Chapel contract surface.
108#
11- # Six strict jobs (no continue-on-error):
9+ # **Why an aggregator gate?** The 6 gate jobs are path-filtered (they only do
10+ # real work when chapel/** or the Rust contract files change). But path-filtered
11+ # workflows that don't trigger leave required status checks "expected but not
12+ # reported" — which blocks unrelated PRs from merging when the gates are in
13+ # the Base ruleset. Solution: a single `chapel-ci-gate` job that ALWAYS runs
14+ # and aggregates. The ruleset requires only the gate. The gate reports:
15+ # - SUCCESS immediately if no chapel-relevant paths changed.
16+ # - SUCCESS if all 6 underlying jobs succeeded on a relevant change.
17+ # - FAILURE if any underlying job failed.
18+ #
19+ # Six strict jobs (no continue-on-error anywhere):
1220# 1. chapel-parse-check — chpl --parse-only on every module
13- # 2. chapel-build — just chapel- build-ci (no toolbox)
21+ # 2. chapel-build — chpl build of mass-panic + smoke (no toolbox)
1422# 3. chapel-smoke — chapel/smoke/two_repo_smoke (Chapel data flow)
15- # 4. chapel-e2e — mass-panic end-to-end (-nl 1) on a synthetic
16- # 2-repo manifest. True -nl 2 requires CHPL_COMM=gasnet
17- # which the stock .deb doesn't ship; tracked for Wave 2.
18- # 5. chapel-cli-contract — assert panic-attack describe-contract matches fixture
19- # 6. chapel-rust-diff — rayon assemblyline vs Chapel single-locale aggregates
23+ # 4. chapel-e2e — mass-panic -nl 1 on a synthetic 2-repo manifest
24+ # True -nl 2 requires CHPL_COMM=gasnet which the
25+ # stock .deb doesn't ship; tracked for Wave 2.
26+ # 5. chapel-cli-contract — panic-attack describe-contract vs expected fixture
27+ # 6. chapel-rust-diff — rayon assemblyline vs Chapel single-locale parity
28+ #
29+ # Plus the always-on aggregator: `chapel-ci-gate`.
2030#
2131# Wave 2 hardening tracker: SHA-pin the Chapel 2.8.0 .deb download. Today the
22- # workflow trusts the HTTPS endpoint at chapel-lang/chapel releases. Acceptable
23- # for the harness scaffold; harden before promoting Chapel to a production gate.
32+ # workflow trusts the HTTPS endpoint at chapel-lang/chapel releases.
2433
2534name : chapel-ci
2635
2736on :
2837 push :
2938 branches : [main]
30- paths :
31- - ' chapel/**'
32- - ' Justfile'
33- - ' .github/workflows/chapel-ci.yml'
34- - ' src/main.rs'
35- - ' src/types.rs'
36- - ' Cargo.toml'
37- - ' Cargo.lock'
3839 pull_request :
39- paths :
40- - ' chapel/**'
41- - ' Justfile'
42- - ' .github/workflows/chapel-ci.yml'
43- - ' src/main.rs'
44- - ' src/types.rs'
45- - ' Cargo.toml'
46- - ' Cargo.lock'
4740
4841permissions :
4942 contents : read
5750 CHAPEL_DEB_URL : " https://github.com/chapel-lang/chapel/releases/download/2.8.0/chapel-2.8.0-1.ubuntu22.amd64.deb"
5851
5952jobs :
53+ detect-relevant-changes :
54+ name : detect-relevant-changes
55+ runs-on : ubuntu-22.04
56+ outputs :
57+ relevant : ${{ steps.f.outputs.relevant }}
58+ steps :
59+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
60+ with :
61+ fetch-depth : 2
62+ - id : f
63+ name : Detect chapel-relevant paths
64+ run : |
65+ set -euo pipefail
66+ BASE="${{ github.event.pull_request.base.sha || github.event.before }}"
67+ if [[ -z "$BASE" || "$BASE" == "0000000000000000000000000000000000000000" ]]; then
68+ # First push or detached state — be safe and run the full gate.
69+ echo "relevant=true" >> "$GITHUB_OUTPUT"
70+ echo "detect: BASE missing/zero — treating as relevant"
71+ exit 0
72+ fi
73+ git fetch origin "$BASE" --depth=1 2>/dev/null || true
74+ CHANGED=$(git diff --name-only "$BASE" HEAD || true)
75+ echo "Changed files:"
76+ echo "$CHANGED"
77+ if echo "$CHANGED" | grep -qE '^(chapel/|Justfile$|\.github/workflows/chapel-ci\.yml$|src/main\.rs$|src/types\.rs$|Cargo\.toml$|Cargo\.lock$)'; then
78+ echo "relevant=true" >> "$GITHUB_OUTPUT"
79+ echo "detect: chapel-relevant paths changed — running gates"
80+ else
81+ echo "relevant=false" >> "$GITHUB_OUTPUT"
82+ echo "detect: no chapel-relevant paths — gates skipped via if-guard"
83+ fi
84+
6085 chapel-parse-check :
6186 name : chapel-parse-check
87+ needs : detect-relevant-changes
88+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
6289 runs-on : ubuntu-22.04
6390 steps :
6491 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6592 - name : Install Chapel ${{ env.CHAPEL_VERSION }}
6693 run : |
6794 set -euo pipefail
68- # Chapel .deb's apt dep: libunwind-dev. Install first so dpkg
69- # doesn't bail out on unmet dependencies.
7095 sudo apt-get update -qq
7196 sudo apt-get install -y libunwind-dev
7297 curl -fsSL --retry 3 -o /tmp/chapel.deb "${{ env.CHAPEL_DEB_URL }}"
@@ -81,15 +106,14 @@ jobs:
81106
82107 chapel-build :
83108 name : chapel-build
84- needs : chapel-parse-check
109+ needs : [detect-relevant-changes, chapel-parse-check]
110+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
85111 runs-on : ubuntu-22.04
86112 steps :
87113 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
88114 - name : Install Chapel ${{ env.CHAPEL_VERSION }}
89115 run : |
90116 set -euo pipefail
91- # Chapel .deb's apt dep: libunwind-dev. Install first so dpkg
92- # doesn't bail out on unmet dependencies.
93117 sudo apt-get update -qq
94118 sudo apt-get install -y libunwind-dev
95119 curl -fsSL --retry 3 -o /tmp/chapel.deb "${{ env.CHAPEL_DEB_URL }}"
@@ -112,15 +136,14 @@ jobs:
112136
113137 chapel-smoke :
114138 name : chapel-smoke
115- needs : chapel-build
139+ needs : [detect-relevant-changes, chapel-build]
140+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
116141 runs-on : ubuntu-22.04
117142 steps :
118143 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
119144 - name : Install Chapel ${{ env.CHAPEL_VERSION }}
120145 run : |
121146 set -euo pipefail
122- # Chapel .deb's apt dep: libunwind-dev. Install first so dpkg
123- # doesn't bail out on unmet dependencies.
124147 sudo apt-get update -qq
125148 sudo apt-get install -y libunwind-dev
126149 curl -fsSL --retry 3 -o /tmp/chapel.deb "${{ env.CHAPEL_DEB_URL }}"
@@ -137,15 +160,14 @@ jobs:
137160
138161 chapel-e2e :
139162 name : chapel-e2e
140- needs : chapel-build
163+ needs : [detect-relevant-changes, chapel-build]
164+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
141165 runs-on : ubuntu-22.04
142166 steps :
143167 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
144168 - name : Install Chapel ${{ env.CHAPEL_VERSION }}
145169 run : |
146170 set -euo pipefail
147- # Chapel .deb's apt dep: libunwind-dev. Install first so dpkg
148- # doesn't bail out on unmet dependencies.
149171 sudo apt-get update -qq
150172 sudo apt-get install -y libunwind-dev
151173 curl -fsSL --retry 3 -o /tmp/chapel.deb "${{ env.CHAPEL_DEB_URL }}"
@@ -174,6 +196,8 @@ jobs:
174196
175197 chapel-cli-contract :
176198 name : chapel-cli-contract
199+ needs : detect-relevant-changes
200+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
177201 runs-on : ubuntu-22.04
178202 steps :
179203 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -192,7 +216,8 @@ jobs:
192216
193217 chapel-rust-diff :
194218 name : chapel-rust-diff
195- needs : chapel-build
219+ needs : [detect-relevant-changes, chapel-build]
220+ if : needs.detect-relevant-changes.outputs.relevant == 'true'
196221 runs-on : ubuntu-22.04
197222 steps :
198223 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -207,8 +232,6 @@ jobs:
207232 - name : Install Chapel ${{ env.CHAPEL_VERSION }}
208233 run : |
209234 set -euo pipefail
210- # Chapel .deb's apt dep: libunwind-dev. Install first so dpkg
211- # doesn't bail out on unmet dependencies.
212235 sudo apt-get update -qq
213236 sudo apt-get install -y libunwind-dev
214237 curl -fsSL --retry 3 -o /tmp/chapel.deb "${{ env.CHAPEL_DEB_URL }}"
@@ -224,3 +247,58 @@ jobs:
224247 run : cargo build --release --locked
225248 - name : rayon vs Chapel single-locale aggregate parity
226249 run : ./chapel/tests/rayon_vs_chapel_diff.sh
250+
251+ # Always-on aggregator. This is the ONLY job listed in the Base ruleset's
252+ # required_status_checks rule. If detect-relevant-changes determined nothing
253+ # in this PR touches Chapel-relevant paths, the gate passes immediately
254+ # (the six per-task jobs above skip via their `if:` guard). If a relevant
255+ # change is present, the gate inspects each job's result and only passes
256+ # when ALL six succeeded.
257+ chapel-ci-gate :
258+ name : chapel-ci-gate
259+ needs :
260+ - detect-relevant-changes
261+ - chapel-parse-check
262+ - chapel-build
263+ - chapel-smoke
264+ - chapel-e2e
265+ - chapel-cli-contract
266+ - chapel-rust-diff
267+ if : always()
268+ runs-on : ubuntu-22.04
269+ steps :
270+ - name : Aggregate chapel-ci results
271+ env :
272+ RELEVANT : ${{ needs.detect-relevant-changes.outputs.relevant }}
273+ R_PARSE : ${{ needs.chapel-parse-check.result }}
274+ R_BUILD : ${{ needs.chapel-build.result }}
275+ R_SMOKE : ${{ needs.chapel-smoke.result }}
276+ R_E2E : ${{ needs.chapel-e2e.result }}
277+ R_CLI : ${{ needs.chapel-cli-contract.result }}
278+ R_DIFF : ${{ needs.chapel-rust-diff.result }}
279+ run : |
280+ set -euo pipefail
281+ echo "detect-relevant-changes.outputs.relevant=$RELEVANT"
282+ printf 'parse-check=%s\nbuild=%s\nsmoke=%s\ne2e=%s\ncli-contract=%s\nrust-diff=%s\n' \
283+ "$R_PARSE" "$R_BUILD" "$R_SMOKE" "$R_E2E" "$R_CLI" "$R_DIFF"
284+ if [[ "$RELEVANT" != "true" ]]; then
285+ echo "chapel-ci-gate: SKIP (no chapel-relevant paths changed) → PASS"
286+ exit 0
287+ fi
288+ # If detect itself failed, we never confirmed relevance — fail safe.
289+ if [[ "${{ needs.detect-relevant-changes.result }}" != "success" ]]; then
290+ echo "chapel-ci-gate: detect-relevant-changes did not succeed → FAIL"
291+ exit 1
292+ fi
293+ fail=0
294+ for r in "$R_PARSE" "$R_BUILD" "$R_SMOKE" "$R_E2E" "$R_CLI" "$R_DIFF"; do
295+ case "$r" in
296+ success) ;;
297+ *) fail=$((fail + 1)) ;;
298+ esac
299+ done
300+ if [[ $fail -gt 0 ]]; then
301+ echo "chapel-ci-gate: $fail dependent job(s) did not succeed → FAIL"
302+ exit 1
303+ fi
304+ echo "chapel-ci-gate: all six gates green → PASS"
0 commit comments