Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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

Expand Down
51 changes: 32 additions & 19 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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
Comment thread
cursor[bot] marked this conversation as resolved.
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'
Expand Down
10 changes: 6 additions & 4 deletions tests/test_nightly_universal_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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"
Comment on lines +23 to +32

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert helper failure is enforced, not just observed.

This block verifies wait and log output, but not that a non-zero HELPER_STATUS must fail the step. Add a matcher for the helper failure gate so the regression test truly protects combined exit-code handling.

Proposed patch
 if ! awk '
   /^      - 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 }
   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) }
+  in_helper && /if \[ "\$HELPER_STATUS" -ne 0 \]; then/ { saw_helper_fail_gate=1 }
+  in_helper && /exit "\$HELPER_STATUS"/ { saw_helper_fail_exit=1 }
+  END { exit !(saw_build && saw_arm64_assert && saw_x86_assert && saw_wait && saw_log && saw_helper_fail_gate && saw_helper_fail_exit) }
 ' "$WORKFLOW_FILE"; then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_nightly_universal_build.sh` around lines 23 - 32, The awk pattern
matching in this block validates that the universal helper is built and various
assertions are checked, but does not verify that a non-zero HELPER_STATUS exit
code is actually enforced to fail the workflow step. Add a new pattern matcher
variable (similar to saw_build, saw_arm64_assert, saw_x86_assert, saw_wait, and
saw_log) that searches for the pattern or mechanism in the workflow that
enforces the HELPER_STATUS failure gate, then include this new variable in the
final END block exit condition alongside the existing saw_build,
saw_arm64_assert, saw_x86_assert, saw_wait, and saw_log checks to ensure the
regression test truly validates combined exit-code handling.

exit 1
fi

Expand Down
Loading