From 00d1911bb4c8c3721c3b6e438c10eaa1bf95ce71 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Sat, 19 Sep 2026 21:48:44 -0700 Subject: [PATCH 1/3] ci: retain branch-scoped compiler state across cancellations --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d9f9b436907..655a67f40563 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2308,6 +2308,25 @@ jobs: set -euo pipefail echo "fingerprint=$(scripts/ci/compile-app-host-test-product.sh fingerprint "$CMUX_COMPILE_ADMISSION_DERIVED_DATA")" >> "$GITHUB_OUTPUT" + - name: Select persistent compilation cache + id: persistent-compilation-cache + env: + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + PR_NUMBER: ${{ github.event.pull_request.number || 'push' }} + COMPILATION_FINGERPRINT: ${{ steps.compilation-cache-key.outputs.fingerprint }} + run: | + set -euo pipefail + # A cancelled run may leave valid Xcode CAS entries behind. Keep the + # local state scoped to this branch so it cannot cross PR trust + # boundaries into another contributor's build. + scope="$(printf 'pr-%s-%s' "$PR_NUMBER" "$BRANCH_NAME" | tr -c 'A-Za-z0-9._-' '-' | cut -c1-120)" + [ -n "$scope" ] || scope=default + cas_path="$RUNNER_TOOL_CACHE/cmux-ci-compile-admission/$scope/$COMPILATION_FINGERPRINT" + mkdir -p "$cas_path" + echo "CMUX_COMPILE_ADMISSION_CAS=$cas_path" >> "$GITHUB_ENV" + echo "path=$cas_path" >> "$GITHUB_OUTPUT" + echo "Using branch-scoped compilation CAS: $cas_path" + # Read-only on purpose: nightly.yml `refresh-test-compilation-cache` is the # only writer. A cache saved here would be scoped to this pull request and # would spend the cache budget that keeps the main seed alive. @@ -2328,6 +2347,19 @@ jobs: "$CMUX_COMPILE_ADMISSION_CAS" \ "$RUNNER_TEMP/cmux-compile-admission.txt" + - name: Report reusable compilation state + if: ${{ !cancelled() }} + run: | + set -euo pipefail + cas_size="$(du -sh "$CMUX_COMPILE_ADMISSION_CAS" | awk '{print $1}')" + echo "Compilation CAS retained for superseding runs: $cas_size" + { + echo "### Reusable compilation state" + echo + echo "- Branch-scoped Xcode CAS: \`$cas_size\`" + echo "- Scope: retained on the self-hosted runner for replacement runs on this branch" + } >> "$GITHUB_STEP_SUMMARY" + - name: Package compiled app-host test product id: package-products run: | From 7edfab5f21c57fd3230a4f8b7a6b4591f93966d7 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Sat, 19 Sep 2026 21:55:41 -0700 Subject: [PATCH 2/3] ci: gate macos fanout on package tests --- .github/workflows/ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 655a67f40563..0a6d518e898d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -728,13 +728,14 @@ jobs: needs: - changes - linux-preflight + - swift-package-tests - macos-compile-admission # !cancelled() disables the implicit success() gate, which GitHub evaluates # over the transitive needs chain: linux-preflight runs behind routed linux # jobs that legitimately skip (web/go/agent-session paths), and that # transitive skip otherwise marks every macOS job skipped even when # linux-preflight itself succeeds. Require the direct needs explicitly. - if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.macos-compile-admission.result == 'success' && needs.changes.outputs.macos == 'true' }} + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.swift-package-tests.result == 'success' && needs.macos-compile-admission.result == 'success' && needs.changes.outputs.macos == 'true' }} name: app-host unit tests (${{ matrix.shard }}/6) # App-host XCTest needs a runner that can broker testmanagerd control # sessions, so route through the shared MACOS_RUNNER_15 var like the other @@ -2225,12 +2226,13 @@ jobs: needs: - changes - linux-preflight + - swift-package-tests # Spend one macOS slot proving that the app-host test product compiles # before starting the six test shards. The shards download this run's # build products and run test-without-building, so a compiler failure # cannot fan out across every macOS worker and a successful build is not # repeated six times. - if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.changes.outputs.macos == 'true' }} + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.swift-package-tests.result == 'success' && needs.changes.outputs.macos == 'true' }} runs-on: ${{ vars.MACOS_RUNNER_15 || 'blacksmith-6vcpu-macos-15' }} timeout-minutes: 75 outputs: @@ -2396,13 +2398,14 @@ jobs: needs: - changes - linux-preflight + - swift-package-tests - macos-compile-admission # !cancelled() disables the implicit success() gate, which GitHub evaluates # over the transitive needs chain: linux-preflight runs behind routed linux # jobs that legitimately skip (web/go/agent-session paths), and that # transitive skip otherwise marks every macOS job skipped even when # linux-preflight itself succeeds. Require the direct needs explicitly. - if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.macos-compile-admission.result == 'success' && needs.changes.outputs.macos == 'true' }} + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.swift-package-tests.result == 'success' && needs.macos-compile-admission.result == 'success' && needs.changes.outputs.macos == 'true' }} # Build the full cmux scheme once, then run the required display/runtime # regressions from the same DerivedData instead of queuing a second display # runner for UI-only checks. From c8f34358e0d3f7ff6c724b913fac38a8bfb285dc Mon Sep 17 00:00:00 2001 From: Leo Li Date: Sat, 19 Sep 2026 22:01:48 -0700 Subject: [PATCH 3/3] test: update macos dependency guard expectations --- tests/test_ci_change_areas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_ci_change_areas.py b/tests/test_ci_change_areas.py index 4fccc3115621..214e1ed72a4a 100644 --- a/tests/test_ci_change_areas.py +++ b/tests/test_ci_change_areas.py @@ -969,7 +969,7 @@ def test_macos_jobs_wait_for_linux_preflight() -> None: assert " - linux-preflight" in block assert "if: ${{ needs.changes.outputs.macos == 'true' }}" not in block expected_needs = ["changes", "linux-preflight"] - if job_name == "release-build": + if job_name in {"app-host-unit-tests", "macos-compile-admission", "tests-build-and-lag", "release-build"}: expected_needs.append("swift-package-tests") if job_name in {"app-host-unit-tests", "tests-build-and-lag", "release-build"}: expected_needs.append("macos-compile-admission")