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>
195 lines
7.7 KiB
YAML
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
|