Skip to content

Commit 2a24bd1

Browse files
mikolalysenkoclaude
andcommitted
Merge branch 'main' into arch-fix/governing-locks
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2 parents 054e4b2 + 05ecc6e commit 2a24bd1

2 files changed

Lines changed: 53 additions & 16 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ on:
99
# workflow (cache-poisoning).
1010
branches: [main]
1111
pull_request:
12+
# The merge queue tests each queued PR merged onto the tip of main (plus
13+
# the PRs ahead of it) before it lands. `ci-ok` below is the required
14+
# check, so this event has to run the same pull_request-tier job set.
15+
merge_group:
16+
types: [checks_requested]
1217
schedule:
1318
# Nightly on main: the `full` tier (e2e-full, cargo-vex-matrix-full,
1419
# yarn-berry-full) and e2e-docker, which pull_request runs skip.
@@ -27,13 +32,14 @@ permissions:
2732
contents: read
2833

2934
# A newer push to the same PR supersedes its older run; nothing else is
30-
# cancelled. Push, dispatch and schedule runs always finish: main runs are
31-
# the ONLY rust-cache writers (save-if) and must not die mid-save, and a
32-
# dispatched base-branch run is the base's only CI verdict. The nightly
33-
# gets its own group: a group holds one pending run, so sharing main's would
34-
# let a queued push and the nightly cancel each other.
35+
# cancelled. Push runs are grouped per commit: a concurrency group holds only
36+
# ONE pending run, so a shared `refs/heads/main` group silently cancelled every
37+
# queued push but the newest during a merge burst, and most main commits never
38+
# got a verdict. Merge-group refs (gh-readonly-queue/...) are unique per queue
39+
# entry already. The nightly keeps its own group so it never queues behind (or
40+
# cancels) a push.
3541
concurrency:
36-
group: ci-${{ github.event.pull_request.number || github.ref }}${{ github.event_name == 'schedule' && '-nightly' || '' }}
42+
group: ci-${{ github.event.pull_request.number || (github.event_name == 'push' && github.sha) || github.ref }}${{ github.event_name == 'schedule' && '-nightly' || '' }}
3743
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
3844

3945
jobs:
@@ -1706,7 +1712,8 @@ jobs:
17061712
# v5 landings, the nightly schedule and dispatch run them with the `e2e`
17071713
# steps.
17081714
e2e-full:
1709-
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
1715+
# merge_group runs the pull_request tier: the queue gates on ci-ok.
1716+
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
17101717
needs: [test, coverage, e2e-build]
17111718
strategy:
17121719
fail-fast: false
@@ -1927,7 +1934,8 @@ jobs:
19271934
# Skipped on pull_request (except v5 landings), like e2e-full.
19281935
yarn-berry-full:
19291936
name: yarn-berry ${{ matrix.yarn }} (${{ matrix.os }})
1930-
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
1937+
# merge_group runs the pull_request tier: the queue gates on ci-ok.
1938+
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
19311939
needs: [test, coverage]
19321940
strategy:
19331941
fail-fast: false
@@ -2019,7 +2027,8 @@ jobs:
20192027
20202028
cargo-vex-matrix-full:
20212029
name: cargo ${{ matrix.toolchain }} lock-v${{ matrix.lock || 'own' }} (${{ matrix.os }})
2022-
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
2030+
# merge_group runs the pull_request tier: the queue gates on ci-ok.
2031+
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
20232032
needs: [test, coverage, e2e-build]
20242033
runs-on: ${{ matrix.os }}
20252034
timeout-minutes: 40
@@ -2081,7 +2090,8 @@ jobs:
20812090
cargo test -p socket-patch-cli --test e2e_vendor_cargo_build -- old_toolchain --nocapture
20822091
20832092
# ----------------------------------------------------------------------
2084-
# Hosted-mode production e2e — REQUIRED status check, with a kill switch.
2093+
# Hosted-mode production e2e — merge-blocking through `ci-ok`, with a kill
2094+
# switch.
20852095
#
20862096
# Drives `scan --mode hosted` against the REAL production endpoints
20872097
# (patches-api.socket.dev + patch.socket.dev) and the REAL upstream
@@ -2093,8 +2103,8 @@ jobs:
20932103
# The suite itself is `#[ignore]`-gated, so it stays OUT of the `test` and
20942104
# `e2e` jobs and only runs where it is explicitly asked for — here.
20952105
#
2096-
# INVARIANTS (this job is registered in branch protection as a required
2097-
# check named exactly `hosted-e2e`):
2106+
# INVARIANTS (`ci-ok` needs this job, and older rulesets may still name the
2107+
# check `hosted-e2e` directly):
20982108
# * NO job-level `if:` — a *skipped* required check is ambiguous to branch
20992109
# protection and can wedge a PR at "Expected — waiting for status".
21002110
# The kill switch gates the STEPS, never the job.
@@ -2113,15 +2123,17 @@ jobs:
21132123
# hosted_e2e = force (ignore the variable) | skip (bypass this run).
21142124
# ----------------------------------------------------------------------
21152125
hosted-e2e:
2116-
name: hosted-e2e # registered in branch protection; do not rename
2126+
name: hosted-e2e # may be a required check; do not rename
21172127
runs-on: ubuntu-latest
21182128
permissions:
21192129
contents: read
21202130
timeout-minutes: 30
21212131
concurrency:
21222132
# These are real requests against a real production service — keep it to
2123-
# one run per ref rather than one per push.
2124-
group: hosted-e2e-${{ github.ref }}
2133+
# one run per PR ref rather than one per push. Main pushes group per
2134+
# commit like the workflow: a group holds ONE pending job, so a shared
2135+
# main group cancelled queued pushes and ci-ok failed them.
2136+
group: hosted-e2e-${{ (github.event_name == 'push' && github.sha) || github.ref }}
21252137
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
21262138
env:
21272139
HOSTED_E2E_DISABLED: ${{ vars.HOSTED_E2E_DISABLED }}
@@ -2309,3 +2321,25 @@ jobs:
23092321
done
23102322
echo "::error title=hosted-e2e::the vendored vlt production proof failed on all 3 attempts"
23112323
exit 1
2324+
2325+
# The single required status check for the merge queue (and PRs). It needs
2326+
# every job above, so adding a job here is how it becomes merge-blocking.
2327+
# Skipped jobs (the nightly `full` tier) pass; failed or cancelled ones fail.
2328+
ci-ok:
2329+
name: ci-ok # registered as a required check; do not rename
2330+
if: always()
2331+
needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, e2e, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e]
2332+
runs-on: ubuntu-latest
2333+
timeout-minutes: 5
2334+
steps:
2335+
- name: Check every needed job
2336+
env:
2337+
RESULTS: ${{ toJSON(needs) }}
2338+
run: |
2339+
echo "$RESULTS" | python3 -c '
2340+
import json, sys
2341+
bad = {k: v["result"] for k, v in json.load(sys.stdin).items()
2342+
if v["result"] not in ("success", "skipped")}
2343+
for k, v in sorted(bad.items()):
2344+
print(f"::error::{k}: {v}")
2345+
sys.exit(1 if bad else 0)'

‎scripts/tests/test_ci_e2e_tiers.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ def test_full_jobs_skip_pull_requests_and_share_steps(self):
6464
("cargo-vex-matrix-full", "cargo-vex-steps")):
6565
with self.subTest(job=job):
6666
text = job_text(job)
67-
self.assertIn("if: github.event_name != 'pull_request'", text)
67+
# The merge queue runs the pull_request tier, so the full tier
68+
# skips merge_group too.
69+
self.assertIn("if: (github.event_name != 'pull_request' && github.event_name != 'merge_group')",
70+
text)
6871
self.assertIn(f"steps: *{anchor}", text)
6972
self.assertIn(f"steps: &{anchor}", TEXT)
7073

0 commit comments

Comments
 (0)