cmux/.github/workflows/ci-macos-compat.yml
Lawrence Chen 1fc4bcba11
Add macOS 26 (Tahoe) compat tests, skip zig build via stub (#1590)
Zig 0.15.2's MachO linker can't resolve libSystem on macOS 26 (the
version number jump from 15 to 26 breaks zig's SDK handling). The unit
tests don't need the CLI helper binary at runtime, so we skip the zig
build on macOS 26 by setting CMUX_SKIP_ZIG_BUILD=1, which creates a
stub binary to satisfy the Xcode Run Script file check.

Smoke test (full app build + launch) is skipped on macOS 26 since it
needs the real CLI helper.

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 01:44:42 -07:00

195 lines
7.7 KiB
YAML

name: macOS Compatibility
on:
push:
branches:
- main
pull_request:
jobs:
compat-tests:
# Only run for the repo itself, not forks (GhosttyKit download needs repo access).
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
strategy:
fail-fast: false
matrix:
include:
- os: warp-macos-15-arm64-6x
timeout: 20
smoke: true
skip_zig: false
- os: warp-macos-26-arm64-6x
timeout: 20
smoke: false
skip_zig: true # zig 0.15.2 MachO linker can't resolve libSystem on macOS 26
runs-on: ${{ matrix.os }}
timeout-minutes: ${{ matrix.timeout }}
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: recursive
- name: Select Xcode
run: |
set -euo pipefail
# Pick the latest Xcode installed on the runner. GitHub-hosted macos-14
# defaults to Xcode 15.4, but the project needs Xcode 16+ (Swift tools
# version 6.0 required by sentry-cocoa).
XCODE_APP="$(ls -d /Applications/Xcode_*.app 2>/dev/null | sort | tail -n 1)"
if [ -z "$XCODE_APP" ]; then
XCODE_APP="/Applications/Xcode.app"
fi
XCODE_DIR="$XCODE_APP/Contents/Developer"
if [ ! -d "$XCODE_DIR" ]; then
echo "No Xcode found under /Applications" >&2
exit 1
fi
echo "Selected: $XCODE_APP"
echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV"
export DEVELOPER_DIR="$XCODE_DIR"
XCODE_VER="$(xcodebuild -version | head -1)"
echo "XCODE_VER=$XCODE_VER" >> "$GITHUB_ENV"
echo "$XCODE_VER"
xcrun --sdk macosx --show-sdk-path
sw_vers
- name: Cache GhosttyKit.xcframework
id: cache-ghosttykit
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: GhosttyKit.xcframework
key: ghosttykit-${{ hashFiles('.gitmodules', 'ghostty') }}
- name: Download pre-built GhosttyKit.xcframework
if: steps.cache-ghosttykit.outputs.cache-hit != 'true'
run: |
./scripts/download-prebuilt-ghosttykit.sh
- name: Install zig
if: ${{ !matrix.skip_zig }}
run: |
ZIG_REQUIRED="0.15.2"
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
echo "zig ${ZIG_REQUIRED} already installed"
else
echo "Installing zig ${ZIG_REQUIRED} from tarball"
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-aarch64-macos-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
tar xf /tmp/zig.tar.xz -C /tmp
sudo mkdir -p /usr/local/bin /usr/local/lib
sudo cp -f /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/zig /usr/local/bin/zig
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
export PATH="/usr/local/bin:$PATH"
zig version
fi
- name: Cache DerivedData
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: ~/Library/Developer/Xcode/DerivedData/GhosttyTabs-*
key: deriveddata-${{ matrix.os }}-${{ env.XCODE_VER }}-${{ hashFiles('GhosttyTabs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}-${{ hashFiles('GhosttyTabs.xcodeproj/project.pbxproj') }}
restore-keys: |
deriveddata-${{ matrix.os }}-${{ env.XCODE_VER }}-${{ hashFiles('GhosttyTabs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}-
deriveddata-${{ matrix.os }}-${{ env.XCODE_VER }}-
- name: Cache Swift packages
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: .ci-source-packages
key: spm-${{ matrix.os }}-${{ hashFiles('GhosttyTabs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}
restore-keys: spm-${{ matrix.os }}-
- name: Resolve Swift packages
run: |
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
mkdir -p "$SOURCE_PACKAGES_DIR"
for attempt in 1 2 3; do
if xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-resolvePackageDependencies; then
exit 0
fi
if [ "$attempt" -eq 3 ]; then
echo "Failed to resolve Swift packages after 3 attempts" >&2
exit 1
fi
echo "Package resolution failed on attempt $attempt, retrying..."
sleep $((attempt * 5))
done
- name: Run unit tests
env:
CMUX_SKIP_ZIG_BUILD: ${{ matrix.skip_zig && '1' || '0' }}
run: |
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
run_unit_tests() {
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-disableAutomaticPackageResolution \
-destination "platform=macOS" test 2>&1
}
set +e
OUTPUT=$(run_unit_tests)
EXIT_CODE=$?
set -e
# SwiftPM binary artifact resolution can occasionally fail on ephemeral
# runners. Retry once after clearing caches.
if [ "$EXIT_CODE" -ne 0 ] && echo "$OUTPUT" | grep -q "Could not resolve package dependencies"; then
echo "SwiftPM package resolution failed, clearing caches and retrying once"
rm -rf ~/Library/Caches/org.swift.swiftpm
mkdir -p ~/Library/Caches/org.swift.swiftpm
rm -rf ~/Library/Developer/Xcode/DerivedData/GhosttyTabs-*
set +e
OUTPUT=$(run_unit_tests)
EXIT_CODE=$?
set -e
fi
echo "$OUTPUT"
if [ "$EXIT_CODE" -ne 0 ]; then
SUMMARY=$(echo "$OUTPUT" | grep "Executed.*tests.*with.*failures" | tail -1)
if echo "$SUMMARY" | grep -q "(0 unexpected)"; then
echo "All failures are expected, treating as pass"
else
echo "Unexpected test failures detected"
exit 1
fi
fi
- name: Create virtual display
if: matrix.smoke
run: |
set -euo pipefail
echo "=== Display before ==="
system_profiler SPDisplaysDataType 2>/dev/null || echo "(no display info)"
echo ""
clang -framework Foundation -framework CoreGraphics \
-o /tmp/create-virtual-display scripts/create-virtual-display.m
/tmp/create-virtual-display &
VDISPLAY_PID=$!
echo "VDISPLAY_PID=$VDISPLAY_PID" >> "$GITHUB_ENV"
sleep 3
echo "=== Display after ==="
system_profiler SPDisplaysDataType 2>/dev/null || echo "(no display info)"
- name: Build app for smoke test
if: matrix.smoke
run: |
set -euo pipefail
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
-disableAutomaticPackageResolution \
-destination "platform=macOS" build
- name: Smoke test
if: matrix.smoke
run: |
set -euo pipefail
chmod +x scripts/smoke-test-ci.sh
scripts/smoke-test-ci.sh