Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 49 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ on:
# workflow (cache-poisoning).
branches: [main]
pull_request:
# The merge queue tests each queued PR merged onto the tip of main (plus
# the PRs ahead of it) before it lands. `ci-ok` below is the required
# check, so this event has to run the same pull_request-tier job set.
merge_group:
types: [checks_requested]
schedule:
# Nightly on main: the `full` tier (e2e-full, cargo-vex-matrix-full,
# yarn-berry-full) and e2e-docker, which pull_request runs skip.
Expand All @@ -27,13 +32,14 @@ permissions:
contents: read

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

jobs:
Expand Down Expand Up @@ -1706,7 +1712,8 @@ jobs:
# v5 landings, the nightly schedule and dispatch run them with the `e2e`
# steps.
e2e-full:
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
# merge_group runs the pull_request tier: the queue gates on ci-ok.
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
needs: [test, coverage, e2e-build]
strategy:
fail-fast: false
Expand Down Expand Up @@ -1927,7 +1934,8 @@ jobs:
# Skipped on pull_request (except v5 landings), like e2e-full.
yarn-berry-full:
name: yarn-berry ${{ matrix.yarn }} (${{ matrix.os }})
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
# merge_group runs the pull_request tier: the queue gates on ci-ok.
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
needs: [test, coverage]
strategy:
fail-fast: false
Expand Down Expand Up @@ -2019,7 +2027,8 @@ jobs:

cargo-vex-matrix-full:
name: cargo ${{ matrix.toolchain }} lock-v${{ matrix.lock || 'own' }} (${{ matrix.os }})
if: github.event_name != 'pull_request' || github.head_ref == 'release/v5-prerelease'
# merge_group runs the pull_request tier: the queue gates on ci-ok.
if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease'
needs: [test, coverage, e2e-build]
runs-on: ${{ matrix.os }}
timeout-minutes: 40
Expand Down Expand Up @@ -2081,7 +2090,8 @@ jobs:
cargo test -p socket-patch-cli --test e2e_vendor_cargo_build -- old_toolchain --nocapture

# ----------------------------------------------------------------------
# Hosted-mode production e2e — REQUIRED status check, with a kill switch.
Comment thread
mikolalysenko marked this conversation as resolved.
# Hosted-mode production e2e — merge-blocking through `ci-ok`, with a kill
# switch.
#
# Drives `scan --mode hosted` against the REAL production endpoints
# (patches-api.socket.dev + patch.socket.dev) and the REAL upstream
Expand All @@ -2093,8 +2103,8 @@ jobs:
# The suite itself is `#[ignore]`-gated, so it stays OUT of the `test` and
# `e2e` jobs and only runs where it is explicitly asked for — here.
#
# INVARIANTS (this job is registered in branch protection as a required
# check named exactly `hosted-e2e`):
# INVARIANTS (`ci-ok` needs this job, and older rulesets may still name the
# check `hosted-e2e` directly):
# * NO job-level `if:` — a *skipped* required check is ambiguous to branch
# protection and can wedge a PR at "Expected — waiting for status".
# The kill switch gates the STEPS, never the job.
Expand All @@ -2113,15 +2123,17 @@ jobs:
# hosted_e2e = force (ignore the variable) | skip (bypass this run).
# ----------------------------------------------------------------------
hosted-e2e:
name: hosted-e2e # registered in branch protection; do not rename
name: hosted-e2e # may be a required check; do not rename
Comment thread
mikolalysenko marked this conversation as resolved.
runs-on: ubuntu-latest
permissions:
contents: read
timeout-minutes: 30
concurrency:
# These are real requests against a real production service — keep it to
# one run per ref rather than one per push.
group: hosted-e2e-${{ github.ref }}
# one run per PR ref rather than one per push. Main pushes group per
# commit like the workflow: a group holds ONE pending job, so a shared
# main group cancelled queued pushes and ci-ok failed them.
group: hosted-e2e-${{ (github.event_name == 'push' && github.sha) || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
HOSTED_E2E_DISABLED: ${{ vars.HOSTED_E2E_DISABLED }}
Expand Down Expand Up @@ -2309,3 +2321,25 @@ jobs:
done
echo "::error title=hosted-e2e::the vendored vlt production proof failed on all 3 attempts"
exit 1

# The single required status check for the merge queue (and PRs). It needs
# every job above, so adding a job here is how it becomes merge-blocking.
# Skipped jobs (the nightly `full` tier) pass; failed or cancelled ones fail.
ci-ok:
name: ci-ok # registered as a required check; do not rename
if: always()
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]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check every needed job
env:
RESULTS: ${{ toJSON(needs) }}
run: |
echo "$RESULTS" | python3 -c '
import json, sys
bad = {k: v["result"] for k, v in json.load(sys.stdin).items()
if v["result"] not in ("success", "skipped")}
for k, v in sorted(bad.items()):
print(f"::error::{k}: {v}")
sys.exit(1 if bad else 0)'
5 changes: 4 additions & 1 deletion scripts/tests/test_ci_e2e_tiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ def test_full_jobs_skip_pull_requests_and_share_steps(self):
("cargo-vex-matrix-full", "cargo-vex-steps")):
with self.subTest(job=job):
text = job_text(job)
self.assertIn("if: github.event_name != 'pull_request'", text)
# The merge queue runs the pull_request tier, so the full tier
# skips merge_group too.
self.assertIn("if: (github.event_name != 'pull_request' && github.event_name != 'merge_group')",
text)
self.assertIn(f"steps: *{anchor}", text)
self.assertIn(f"steps: &{anchor}", TEXT)

Expand Down
Loading