name: CI on: push: branches: - main pull_request: jobs: web-typecheck: runs-on: ubuntu-latest defaults: run: working-directory: web steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 - name: Install dependencies run: bun install --frozen-lockfile - name: Typecheck run: bun tsc --noEmit ui-tests: runs-on: self-hosted concurrency: group: self-hosted-build cancel-in-progress: false steps: - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - name: Select Xcode run: | set -euo pipefail if [ -d "/Applications/Xcode.app/Contents/Developer" ]; then XCODE_DIR="/Applications/Xcode.app/Contents/Developer" else XCODE_APP="$(ls -d /Applications/Xcode*.app 2>/dev/null | head -n 1 || true)" if [ -n "$XCODE_APP" ]; then XCODE_DIR="$XCODE_APP/Contents/Developer" else echo "No Xcode.app found under /Applications" >&2 exit 1 fi fi echo "DEVELOPER_DIR=$XCODE_DIR" >> "$GITHUB_ENV" export DEVELOPER_DIR="$XCODE_DIR" xcodebuild -version xcrun --sdk macosx --show-sdk-path - name: Build GhosttyKit.xcframework run: | set -euo pipefail if ! command -v zig >/dev/null 2>&1; then if command -v brew >/dev/null 2>&1; then brew install zig else echo "zig is required to build GhosttyKit.xcframework. Install zig and retry." >&2 exit 1 fi fi (cd ghostty && zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=native) rm -rf GhosttyKit.xcframework cp -R ghostty/macos/GhosttyKit.xcframework GhosttyKit.xcframework test -d GhosttyKit.xcframework - name: Clean DerivedData run: | # Remove stale build cache to avoid incremental build errors rm -rf ~/Library/Developer/Xcode/DerivedData/GhosttyTabs-* - name: Run UI tests run: | set -euo pipefail # Policy: run macOS UI tests in the UTM VM (never on the host runner). Host GUI # state is frequently non-interactive on CI and causes false failures. vm_user="${CMUX_VM_USER:-cmux}" ssh_opts=( -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ConnectionAttempts=1 -o NumberOfPasswordPrompts=0 -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no -o ChallengeResponseAuthentication=no -o GSSAPIAuthentication=no -o LogLevel=ERROR ) vm_candidates=() if [ -n "${CMUX_VM_HOST:-}" ]; then vm_candidates+=("$CMUX_VM_HOST") else vm_candidates+=("cmux-vm" "cmux-vm.local" "192.168.64.73") fi vm_host="" for h in "${vm_candidates[@]}"; do if ssh "${ssh_opts[@]}" "$vm_user@$h" 'true' >/dev/null 2>&1; then vm_host="$h" break fi done if [ -z "$vm_host" ]; then echo "ERROR: Could not SSH into the UI-test VM; UI tests are required." echo "Tried:" for h in "${vm_candidates[@]}"; do echo " - $vm_user@$h" done echo "Fix: set CMUX_VM_HOST (repo secret or runner env), or add a working 'cmux-vm' Host entry in ~/.ssh/config on the self-hosted runner." exit 1 fi echo "Running UI tests on $vm_user@$vm_host..." rsync -e "ssh ${ssh_opts[*]}" -a --delete \ --exclude build \ --exclude .git \ --exclude "GhosttyTabs.xcodeproj/project.xcworkspace" \ ./ "$vm_user@$vm_host":/Users/cmux/GhosttyTabs/ ssh "${ssh_opts[@]}" "$vm_user@$vm_host" 'cd /Users/cmux/GhosttyTabs && xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination "platform=macOS" -only-testing:GhosttyTabsUITests/UpdatePillUITests test'