Skip to content

Fix nightly Xcode selection on single-Xcode runners - #5694

Merged
lawrencecchen merged 1 commit into
mainfrom
feat-nightly-xcode26-helper-fallback
Jun 9, 2026
Merged

lawrencecchen merged 1 commit into
mainfrom
feat-nightly-xcode26-helper-fallback

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • replace the inline nightly Xcode selector with a tested script
  • keep macOS 26 SDK selection required for the app
  • fall back to the app Xcode for the Ghostty helper when no pre-26 Xcode is installed, while keeping the universal helper build and lipo checks required
  • wire guard tests for one-Xcode runners and the current universal nightly workflow

Failure fixed

Verification

  • ./tests/test_ci_nightly_xcode_selection.sh
  • bash ./tests/test_nightly_universal_build.sh
  • ./tests/test_ci_release_sdk_lane.sh
  • git diff --check origin/main...HEAD

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Medium Risk
Changes nightly signing/build toolchain selection and helper SDK fallback; mis-selection or a failed universal helper link on SDK 26 could break nightlies, though behavior is regression-tested in CI guards.

Overview
Fixes nightly macOS CI failing on runners that only ship Xcode 26 (macOS 26 SDK), where the old inline Select Xcode step hard-required a separate pre-26 Xcode for the Ghostty CLI helper.

Nightly workflow now calls scripts/select-nightly-xcodes.sh instead of inlined bash. The script still requires a macOS 26+ SDK Xcode for the Swift app (Liquid Glass on Tahoe) and prefers a pre-26 Xcode for the universal helper when present, but falls back to the app Xcode when no pre-26 install exists—while keeping the universal helper build and lipo arm64/x86_64 checks mandatory. Workflow comments were updated to document that behavior.

CI guard tests were added in ci.yml: test_ci_nightly_xcode_selection.sh (mocked Xcode layouts: one-Xcode, dual-Xcode, missing 26+ failure) and an updated test_nightly_universal_build.sh wired into workflow-guard-tests. test_ci_release_sdk_lane.sh comments now point at these nightly-specific guards instead of inline workflow steps.

Reviewed by Cursor Bugbot for commit d03dceb. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fix nightly Xcode selection to work on single‑Xcode runners by moving selection into a tested script with a safe helper fallback. The app still builds with a macOS 26 SDK; the Ghostty helper prefers a pre‑26 SDK but falls back to the app Xcode, with universal build and lipo checks enforced.

  • Bug Fixes

    • Nightly “Select Xcode” no longer fails when the runner only has Xcode 26; the helper falls back to the app’s Xcode if no pre‑26 Xcode is present.
  • Refactors

    • Replaced inline selection with scripts/select-nightly-xcodes.sh and invoked it from nightly.yml (exports DEVELOPER_DIR and HELPER_DEVELOPER_DIR).
    • Added CI guards: test_ci_nightly_xcode_selection.sh for one‑Xcode runners and stronger test_nightly_universal_build.sh; wired into ci.yml.

Written for commit d03dceb. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Chores

    • Enhanced nightly CI pipeline with improved Xcode selection logic and validation steps for universal builds.
    • Refactored nightly macOS workflow to streamline SDK version management.
  • Tests

    • Added regression tests to validate nightly Xcode selection behavior across different runner configurations.
    • Added validation tests for universal nightly build configurations and architecture verification.

@vercel

vercel Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 9, 2026 10:19am
cmux-staging Building Building Preview, Comment Jun 9, 2026 10:19am

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d03dcebc21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +75 to +77
HELPER_DEVELOPER_DIR="$APP_DEVELOPER_DIR"
HELPER_SDK_VER="$APP_SDK_VER"
echo "No pre-26 Xcode found for the Ghostty CLI helper; falling back to the app Xcode. The universal helper build and lipo verification remain required." >&2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the helper off the macOS 26 SDK

On single-Xcode runners this fallback sets HELPER_DEVELOPER_DIR to the same Xcode 26 SDK selected for the app, but the very next nightly step runs the real build-ghostty-cli-helper.sh --universal with that value as DEVELOPER_DIR. The repo's release lane still builds this helper on the macOS 15/pre-26 lane because Zig 0.15.2 cannot link it on macOS 26, so the intended single-Xcode nightly will get past selection only to fail during the required helper build rather than producing a nightly.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5bcc7ada-b957-4eab-ab88-cb5668f249d6

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb5db0 and d03dceb.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/nightly.yml
  • scripts/select-nightly-xcodes.sh
  • tests/test_ci_nightly_xcode_selection.sh
  • tests/test_ci_release_sdk_lane.sh
  • tests/test_nightly_universal_build.sh

📝 Walkthrough

Walkthrough

The PR refactors nightly macOS Xcode selection from inline workflow logic into a dedicated script, adds comprehensive regression tests for Xcode selection behavior, updates the universal nightly build validation to cover a unified track instead of dual tracks, and integrates these new tests into the CI guard workflow.

Changes

Nightly Xcode Selection and Universal Build Validation

Layer / File(s) Summary
Xcode selection script
scripts/select-nightly-xcodes.sh
New Bash script that scans /Applications for Xcode installations, parses macOS SDK versions, ranks candidates by major and minor version, selects the best app Xcode with SDK major ≥26, selects a pre-26 helper Xcode, and exports DEVELOPER_DIR and HELPER_DEVELOPER_DIR to GitHub Actions. Falls back to using the app Xcode as helper when no pre-26 helper is found; fails if no qualifying SDK major ≥26 Xcode is available.
Xcode selection regression test
tests/test_ci_nightly_xcode_selection.sh
Comprehensive Bash regression test with three scenarios: (1) single Xcode with macOS 26+ SDK is selected for both app and helper builds; (2) dual Xcodes split selection by SDK major version; (3) missing macOS 26+ SDK Xcode fails with clear error. Uses mocked xcrun and temporary Xcode directory structures to validate selection logic in isolation.
Nightly workflow refactoring
.github/workflows/nightly.yml
Replaces ~50 lines of inline Xcode discovery and ranking logic in the "Select Xcode" step with a call to ./scripts/select-nightly-xcodes.sh. Updates job-level documentation to clarify SDK selection behavior and helper cross-linking requirements. Removes now-redundant comment about zig pre-26 cross-linking limitation.
Universal nightly build test updates
tests/test_nightly_universal_build.sh
Updates regression test from validating separate nightly tracks (Apple Silicon arm-only vs universal) to a single unified universal nightly track. Adds assertions for universal build destinations, Ghostty universal helper build/verification via lipo -archs, universal binary slices for app/CLI/helper, unified bundle ID com.cmuxterm.app.nightly, and appcast generation as appcast-universal.xml. Refines artifact upload and release publish assertions for the unified track.
CI guard test integration
.github/workflows/ci.yml, tests/test_ci_release_sdk_lane.sh
Adds two new guard test steps to the workflow-guard-tests job to invoke nightly Xcode selection validation and universal nightly build validation. Updates release lane test documentation to clarify that nightly.yml is guarded by separate helper tests, not this lane.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#5077: Extends prior Xcode selection and universal nightly build flow by extracting selection logic into a reusable script with regression test coverage.

Poem

A rabbit hops through Xcode trees,
Selecting SDKs with such ease,
Universal helpers join the dance,
While tests confirm each build's advance,
macOS 26 shines bright! 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: fixing nightly Xcode selection on single-Xcode runners, which directly addresses the core issue across the changeset.
Description check ✅ Passed The description provides a clear summary of changes and reasons, lists specific verification tests, and includes a reference to the failure fixed; however, it lacks explicit sections for 'Testing' (methodology) and 'Checklist' items as specified in the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-nightly-xcode26-helper-fallback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extracts the inline nightly Xcode selection logic into scripts/select-nightly-xcodes.sh and adds a fallback so that single-Xcode runners (carrying only a macOS 26 SDK Xcode) no longer hard-fail at the "Select Xcode" step; instead, the same Xcode is used for both the app build and the Ghostty CLI helper, with the universal helper build and lipo checks remaining required.

  • scripts/select-nightly-xcodes.sh: New tested script replacing the inline workflow block; adds sdk_major/sdk_rank helpers, an APPLICATIONS_DIR override for testing, and the helper fallback path.
  • tests/test_ci_nightly_xcode_selection.sh + test_nightly_universal_build.sh: New and updated regression tests wired into CI covering the one-Xcode fallback, the dual-Xcode selection, the no-macOS-26 hard-fail, and the unified universal build/lipo pipeline.
  • nightly.yml: Consolidated from a dual ARM64 + universal track to a single unified universal nightly track; the "Select Xcode" step now delegates to the new script.

Confidence Score: 3/5

Safe to merge only after confirming that build-ghostty-cli-helper.sh --universal can produce a valid arm64+x86_64 binary when DEVELOPER_DIR points to a macOS 26 SDK Xcode.

The selection script and tests are clean, but the fallback silently reuses the macOS 26 SDK Xcode for the Ghostty CLI helper build. The nightly.yml app-build step still documents that zig must skip the in-Xcode x86_64 cross-link against macOS 26 SDK, yet no equivalent note exists on the standalone helper-build step. If build-ghostty-cli-helper.sh --universal shares the same limitation, the CI failure just moves from Select Xcode to Build universal Ghostty CLI helper and the fix is incomplete.

scripts/select-nightly-xcodes.sh (fallback path) and .github/workflows/nightly.yml (Build universal Ghostty CLI helper step).

Important Files Changed

Filename Overview
scripts/select-nightly-xcodes.sh New script extracting inline Xcode selection logic from nightly.yml; adds a fallback that reuses the macOS 26 SDK Xcode for the helper when no pre-26 Xcode is present — correctness depends on whether build-ghostty-cli-helper.sh is exempt from the zig x86_64 macOS 26 SDK limitation documented elsewhere in the workflow.
.github/workflows/nightly.yml Replaces inline Select Xcode script block with a call to the new select-nightly-xcodes.sh; drops the per-step comment explaining the zig pre-26 SDK requirement; lipo and helper build requirements remain in place.
tests/test_ci_nightly_xcode_selection.sh New regression test covering one-Xcode fallback, dual-Xcode selection, and hard-fail on missing macOS 26+ Xcode; does not test highest-rank selection among multiple macOS 26+ Xcodes.
tests/test_nightly_universal_build.sh Updated from dual-track (ARM64 + universal) to single unified universal track; awk matchers updated to match the new step names and assertion patterns in nightly.yml.
.github/workflows/ci.yml Two new validation steps wired into CI to run the nightly Xcode selection and universal build tests on every push.
tests/test_ci_release_sdk_lane.sh Comment-only update pointing to the new test scripts that guard the nightly workflow; no logic changed.

Reviews (1): Last reviewed commit: "Fix nightly Xcode selection on single-Xc..." | Re-trigger Greptile

Comment on lines +74 to +78
if [ -z "$HELPER_DEVELOPER_DIR" ]; then
HELPER_DEVELOPER_DIR="$APP_DEVELOPER_DIR"
HELPER_SDK_VER="$APP_SDK_VER"
echo "No pre-26 Xcode found for the Ghostty CLI helper; falling back to the app Xcode. The universal helper build and lipo verification remain required." >&2
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Fallback may not unblock single-Xcode runners if zig still can't link x86_64 against macOS 26 SDK

The nightly.yml app-build step still carries a comment saying the in-Xcode zig build "would fail to cross-link x86_64 against the macOS 26 SDK" — and that step explicitly sets CMUX_SKIP_ZIG_BUILD=1 to skip it. The "Build universal Ghostty CLI helper" step also invokes a zig-driven universal build under DEVELOPER_DIR: ${{ env.HELPER_DEVELOPER_DIR }}. When the fallback here sets HELPER_DEVELOPER_DIR to the macOS 26 SDK Xcode, the standalone build-ghostty-cli-helper.sh --universal will run with that same macOS 26 SDK. If build-ghostty-cli-helper.sh shares the same zig x86_64 cross-link limitation, the CI will still fail on single-Xcode runners — just at the helper-build step instead of "Select Xcode". A brief inline comment confirming that the standalone script is exempt from the zig macOS 26 SDK limitation would make the fallback logic self-documenting.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +54 to +71
make_xcode "Xcode.app" "26.2"
ONLY_OUT="$TMP_DIR/only.out"
ONLY_ENV="$TMP_DIR/only.env"
run_selector "$ONLY_OUT" "$ONLY_ENV"
assert_env_line "$ONLY_ENV" "DEVELOPER_DIR=$APPS_DIR/Xcode.app/Contents/Developer"
assert_env_line "$ONLY_ENV" "HELPER_DEVELOPER_DIR=$APPS_DIR/Xcode.app/Contents/Developer"
if ! grep -Fq "falling back to the app Xcode" "$ONLY_OUT"; then
echo "FAIL: one-Xcode selection must explain the helper fallback" >&2
cat "$ONLY_OUT" >&2
exit 1
fi

make_xcode "Xcode_16.app" "15.5"
DUAL_OUT="$TMP_DIR/dual.out"
DUAL_ENV="$TMP_DIR/dual.env"
run_selector "$DUAL_OUT" "$DUAL_ENV"
assert_env_line "$DUAL_ENV" "DEVELOPER_DIR=$APPS_DIR/Xcode.app/Contents/Developer"
assert_env_line "$DUAL_ENV" "HELPER_DEVELOPER_DIR=$APPS_DIR/Xcode_16.app/Contents/Developer"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 No test for highest-rank selection among multiple macOS 26+ Xcodes

The dual-Xcode case tests one macOS 26 Xcode and one pre-26 Xcode. There is no test with two macOS 26+ Xcodes (e.g. Xcode.app at 26.2 and Xcode_26_3.app at 26.3) to verify that the highest-ranked app Xcode is actually chosen. Without this, a regression in the sdk_rank comparison path for the app side would go undetected.

@lawrencecchen
lawrencecchen merged commit a05dc1c into main Jun 9, 2026
28 checks passed
@lawrencecchen
lawrencecchen deleted the feat-nightly-xcode26-helper-fallback branch June 9, 2026 10:45

This branch was successfully deployed

1 active deployment
Preview – cmux — d03dcebc Deployed Jun 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant