From 80b3895aaf2ba8c9d4ffd515e5520368eebf8b64 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Sat, 20 Jun 2026 00:32:15 -0700 Subject: [PATCH] Speed up macOS CI lanes --- .github/workflows/ci.yml | 24 +++++-------- .github/workflows/nightly.yml | 51 +++++++++++++++++---------- tests/test_nightly_universal_build.sh | 10 +++--- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cfcee7c9f78..4827af8b6104 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -349,6 +349,9 @@ jobs: shard: [1, 2, 3, 4] env: CMUX_SKIP_ZIG_BUILD: "1" + # Keep one-off focused gates on the lightest measured shard so shard 1 no + # longer carries the full shard plus every extra regression guard. + CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD: "4" # XCTest app-host crashes can leave xcodebuild waiting in Swift's crash # backtracer until the job timeout. Keep crash handling non-interactive # and cheap so xcodebuild can restart/finish the suite. @@ -412,21 +415,10 @@ jobs: run: | ./scripts/download-prebuilt-ghosttykit.sh - - name: Install zig - run: | - ./scripts/install-zig-ci.sh - - name: Install Rust run: | ./scripts/install-rust-ci.sh - - name: Cache Zig packages - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: ~/.cache/zig - key: zig-packages-${{ hashFiles('ghostty/build.zig.zon', 'ghostty/build.zig.zon.json') }} - restore-keys: zig-packages- - - name: Cache Swift packages uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -475,7 +467,7 @@ jobs: done - name: Run Ghostty split-theme appearance regression - if: ${{ matrix.shard == 1 }} + if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | set -euo pipefail DERIVED_DATA_PATH="${RUNNER_TEMP:-/tmp}/cmux-terminal-core-split-theme" @@ -504,7 +496,7 @@ jobs: fi - name: Run browser system proxy mirror regression - if: ${{ matrix.shard == 1 }} + if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | # Focused gate for https://github.com/manaflow-ai/cmux/issues/5888. # The full "Run unit tests" step tolerates app-host crashes by @@ -526,7 +518,7 @@ jobs: test - name: Run Option/Alt sided-modifier regression - if: ${{ matrix.shard == 1 }} + if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | set -euo pipefail SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages" @@ -626,14 +618,14 @@ jobs: fi - name: Run bundled Ghostty theme picker helper regression - if: ${{ matrix.shard == 1 }} + if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | set -euo pipefail CMUX_SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages" \ ./tests/test_bundled_ghostty_theme_picker_helper.sh - name: Run CLI no-socket regressions - if: ${{ matrix.shard == 1 }} + if: ${{ matrix.shard == fromJSON(env.CMUX_APP_HOST_FOCUSED_REGRESSION_SHARD) }} run: | set -euo pipefail diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 150e57878deb..501555161cf7 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -185,18 +185,6 @@ jobs: chmod +x "$wrapper_dir/create-dmg" echo "$wrapper_dir" >> "$GITHUB_PATH" - - name: Build universal Ghostty CLI helper - if: needs.decide.outputs.should_publish != 'true' || steps.current_head_prebuild.outputs.still_current == 'true' - env: - DEVELOPER_DIR: ${{ env.HELPER_DEVELOPER_DIR }} - run: | - set -euo pipefail - ./scripts/build-ghostty-cli-helper.sh --universal --output /tmp/cmux-ghostty-helper-universal - ARCHS_OUT="$(lipo -archs /tmp/cmux-ghostty-helper-universal)" - echo "Universal Ghostty CLI helper architectures: $ARCHS_OUT" - case " $ARCHS_OUT " in *" arm64 "*) ;; *) echo "helper missing arm64 slice" >&2; exit 1 ;; esac - case " $ARCHS_OUT " in *" x86_64 "*) ;; *) echo "helper missing x86_64 slice" >&2; exit 1 ;; esac - - name: Download pre-built GhosttyKit.xcframework if: needs.decide.outputs.should_publish != 'true' || steps.current_head_prebuild.outputs.still_current == 'true' run: | @@ -233,20 +221,45 @@ jobs: echo "Derived Sparkle public key: $DERIVED_PUBLIC_KEY" echo "SPARKLE_PUBLIC_KEY=$DERIVED_PUBLIC_KEY" >> "$GITHUB_ENV" - - name: Build universal nightly app (Release) + - name: Build universal nightly app and Ghostty CLI helper (Release) if: needs.decide.outputs.should_publish != 'true' || steps.current_head_prebuild.outputs.still_current == 'true' - env: - # Skip the in-Xcode zig helper build; it would fail to cross-link - # x86_64 against the macOS 26 SDK. The real universal helper is built - # by the "Build universal Ghostty CLI helper" step and injected below. - CMUX_SKIP_ZIG_BUILD: "1" run: | - xcodebuild -scheme cmux -configuration Release -derivedDataPath build-universal \ + set -euo pipefail + HELPER_LOG="$RUNNER_TEMP/cmux-nightly-ghostty-helper.log" + ( + set -euo pipefail + export DEVELOPER_DIR="$HELPER_DEVELOPER_DIR" + ./scripts/build-ghostty-cli-helper.sh --universal --output /tmp/cmux-ghostty-helper-universal + ARCHS_OUT="$(lipo -archs /tmp/cmux-ghostty-helper-universal)" + echo "Universal Ghostty CLI helper architectures: $ARCHS_OUT" + case " $ARCHS_OUT " in *" arm64 "*) ;; *) echo "helper missing arm64 slice" >&2; exit 1 ;; esac + case " $ARCHS_OUT " in *" x86_64 "*) ;; *) echo "helper missing x86_64 slice" >&2; exit 1 ;; esac + ) >"$HELPER_LOG" 2>&1 & + HELPER_PID=$! + + APP_STATUS=0 + set +e + # Skip only the in-Xcode helper build; the background helper process + # above must build the real universal Zig helper, not the CI stub. + CMUX_SKIP_ZIG_BUILD=1 xcodebuild -scheme cmux -configuration Release -derivedDataPath build-universal \ -destination 'generic/platform=macOS' \ -clonedSourcePackagesDirPath .spm-cache \ ARCHS="arm64 x86_64" \ ONLY_ACTIVE_ARCH=NO \ CODE_SIGNING_ALLOWED=NO ASSETCATALOG_COMPILER_APPICON_NAME=AppIcon-Nightly build + APP_STATUS=$? + set -e + HELPER_STATUS=0 + wait "$HELPER_PID" || HELPER_STATUS=$? + cat "$HELPER_LOG" + if [ "$APP_STATUS" -ne 0 ]; then + echo "Universal nightly app build failed" >&2 + exit "$APP_STATUS" + fi + if [ "$HELPER_STATUS" -ne 0 ]; then + echo "Universal Ghostty CLI helper build failed" >&2 + exit "$HELPER_STATUS" + fi - name: Inject universal Ghostty CLI helper if: needs.decide.outputs.should_publish != 'true' || steps.current_head_prebuild.outputs.still_current == 'true' diff --git a/tests/test_nightly_universal_build.sh b/tests/test_nightly_universal_build.sh index cdfcec7a9d84..0c476e4e0397 100644 --- a/tests/test_nightly_universal_build.sh +++ b/tests/test_nightly_universal_build.sh @@ -6,7 +6,7 @@ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" WORKFLOW_FILE="$ROOT_DIR/.github/workflows/nightly.yml" if ! awk ' - /^ - name: Build universal nightly app \(Release\)/ { in_universal=1; next } + /^ - name: Build universal nightly app and Ghostty CLI helper \(Release\)/ { in_universal=1; next } in_universal && /^ - name:/ { in_universal=0 } in_universal && /-destination '\''generic\/platform=macOS'\''/ { saw_universal_destination=1 } in_universal && /ARCHS="arm64 x86_64"/ { saw_universal_archs=1 } @@ -20,14 +20,16 @@ if ! awk ' fi if ! awk ' - /^ - name: Build universal Ghostty CLI helper/ { in_helper=1; next } + /^ - name: Build universal nightly app and Ghostty CLI helper \(Release\)/ { in_helper=1; next } in_helper && /^ - name:/ { in_helper=0 } in_helper && /build-ghostty-cli-helper\.sh --universal/ { saw_build=1 } in_helper && /helper missing arm64 slice/ { saw_arm64_assert=1 } in_helper && /helper missing x86_64 slice/ { saw_x86_assert=1 } - END { exit !(saw_build && saw_arm64_assert && saw_x86_assert) } + in_helper && /wait "\$HELPER_PID"/ { saw_wait=1 } + in_helper && /cat "\$HELPER_LOG"/ { saw_log=1 } + END { exit !(saw_build && saw_arm64_assert && saw_x86_assert && saw_wait && saw_log) } ' "$WORKFLOW_FILE"; then - echo "FAIL: nightly workflow must build and verify the real universal Ghostty helper" + echo "FAIL: nightly workflow must build and verify the real universal Ghostty helper alongside the app build" exit 1 fi