Skip to content

Run E2E xcodebuild in GUI bootstrap - #4940

Merged
lawrencecchen merged 2 commits into
mainfrom
feat-e2e-gui-bootstrap
May 28, 2026
Merged

lawrencecchen merged 2 commits into
mainfrom
feat-e2e-gui-bootstrap

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Moves hosted E2E xcodebuild into the console user GUI bootstrap when the runner exposes one, then removes the FeedSidebar launch expected-failure mask as the first coverage restoration.

This makes foreground activation a workflow invariant instead of a per-test non-strict expected failure.

Validation:

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@vercel

vercel Bot commented May 28, 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 May 28, 2026 9:32am
cmux-staging Building Building Preview, Comment May 28, 2026 9:32am

@coderabbitai

coderabbitai Bot commented May 28, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Runs xcodebuild inside the console GUI user's session with Automation Mode when available and captures its output via a RUN_XCODEBUILD wrapper. FeedSidebarUITests now calls app.launch() directly, removing the prior XCTExpectFailure tolerance.

Changes

UI Test Execution Reliability

Layer / File(s) Summary
Workflow xcodebuild environment and GUI user bootstrap
.github/workflows/test-e2e.yml
Workflow constructs explicit XCODEBUILD_ENV and RUN_XCODEBUILD wrapper, detects non-root console GUI user, optionally enables macOS Automation Mode via automationmodetool, and uses passwordless sudo + launchctl asuser to run xcodebuild in the GUI session; output capture now always invokes ${RUN_XCODEBUILD[@]} "${XCODEBUILD_CMD[@]}".
Test invocation and strict app launch
cmuxUITests/FeedSidebarUITests.swift, .github/workflows/test-e2e.yml
FeedSidebarUITests.launchAndEnsureUsable now calls app.launch() unconditionally (removing XCTExpectFailure), and CI output capture always runs xcodebuild via the RUN_XCODEBUILD wrapper (combined stdout/stderr).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#1938: Changes to FeedSidebarUITests directly address the same app-activation problem described in this issue.
  • manaflow-ai/cmux-dev-artifacts#1895: Workflow bootstrap into the console GUI user and test adjustments target the WorkspaceDescriptionUITests app activation/flakiness noted here.
  • manaflow-ai/cmux-dev-artifacts#1893: Running xcodebuild in the GUI session and removing the XCTExpectFailure wrapper relate to SidebarHelpMenuUITests activation failures described in this issue.

Possibly related PRs

  • manaflow-ai/cmux#4922: Also modifies .github/workflows/test-e2e.yml's Run UI tests step and xcodebuild invocation/argument handling.
  • manaflow-ai/cmux#4928: Related changes to FeedSidebarUITests.swift, removing tolerant app.launch() behavior.

Poem

🐰 I nudge the GUI session awake at dawn,
With sudo and launchctl I carry on,
Automation Mode hums, xcodebuild starts to play,
The app must launch now — no more tucked-away,
Tests march forward bright as day!

🚥 Pre-merge checks | ✅ 16 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning PR description lacks required sections (Testing, Demo Video) and is overly technical without clear summary of what changed and why. Add Testing section (how tested, manual verification), Demo Video section if applicable, and Review Trigger comment block. Clarify the summary of what changed and why in plain language.
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Run E2E xcodebuild in GUI bootstrap' directly and clearly summarizes the main change: moving the hosted E2E xcodebuild invocation to run in the console GUI user's bootstrap context.
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.
Cmux Swift Actor Isolation ✅ Passed PR contains only workflow configuration (YAML) and test file changes (FeedSidebarUITests.swift). No production Swift code modifications; actor isolation rules explicitly allow test changes.
Cmux Swift Blocking Runtime ✅ Passed PR changes only affect test files (cmuxUITests/FeedSidebarUITests.swift) and workflow config; Thread.sleep calls are deterministic test-only scaffolding explicitly allowed by the rule.
Cmux No Hacky Sleeps ✅ Passed PR changes are out of scope: test-e2e.yml is GitHub Actions YAML (explicitly excluded), FeedSidebarUITests.swift is Swift code (covered by separate rule).
Cmux Algorithmic Complexity ✅ Passed Changes are in test code (cmuxUITests) and CI workflow, both explicitly exempted as "Test-only scaffolding" per the rule's Pass section. No production code with scalable collections affected.
Cmux Swift Concurrency ✅ Passed XCTest code uses Thread.sleep polling; no DispatchQueue.global, DispatchGroup, Combine, or fire-and-forget Tasks. Test-only synchronization patterns are permitted.
Cmux Swift @Concurrent ✅ Passed No async functions, @concurrent annotations, or actor isolation patterns found in the Swift changes; only synchronous code modifications present.
Cmux Swift File And Package Boundaries ✅ Passed PR modifies only test code (cmuxUITests/) and workflow configuration, no production Swift files. Test files are explicitly allowed per the boundary rules.
Cmux Swift Logging ✅ Passed PR modifies only test file (FeedSidebarUITests.swift) and workflow config. Test file contains no print/debugPrint/dump/NSLog, and tests are explicitly allowed per swift-logging.md rules.
Cmux User-Facing Error Privacy ✅ Passed PR contains only CI workflow and test changes. Messages in test code are developer-only (excluded per rule). Workflow warnings are operational logs, not user-facing.
Cmux Full Internationalization ✅ Passed Both files are exempt from internationalization: test-e2e.yml is operational code, FeedSidebarUITests.swift is developer-only test code with no user-facing strings.
Cmux Swiftui State Layout ✅ Passed PR contains no SwiftUI code changes: only workflow YAML and XCTest test file modifications. The SwiftUI state layout check is not applicable to these non-SwiftUI files.
Cmux Architecture Rethink ✅ Passed PR removes XCTExpectFailure workaround and adjusts CI workflow; test-only synchronization with clear invariants and no architectural debt introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only modifies test code (FeedSidebarUITests.swift) and workflow config (.github/workflows/test-e2e.yml). No Swift window code added or changed; test-only fixtures are exempt.

✏️ 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-e2e-gui-bootstrap

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 May 28, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR moves the hosted E2E xcodebuild invocation into the console GUI user's bootstrap session on macOS self-hosted runners, fixing foreground activation failures in UI tests. It then removes the XCTExpectFailure wrapper in FeedSidebarUITests that was masking those failures, converting activation into a real test assertion.

  • The workflow now detects the console GUI user via stat -f %Su /dev/console, enables Automation Mode when available, and chains sudo -n launchctl asuser "$GUI_UID" sudo -n -H -u "$GUI_USER" to run xcodebuild in the correct bootstrap with a reconstructed environment; passwordless-sudo and GUI-user detection failures both warn and fall back gracefully.
  • FeedSidebarUITests.launchAndEnsureUsable drops the non-strict XCTExpectFailure around app.launch(), making foreground activation a hard assertion now that GUI bootstrap is expected to be a CI invariant.

Confidence Score: 5/5

Safe to merge; the double-sudo chain correctly resolves the previously flagged root-owned DerivedData problem and the fallback paths are non-fatal.

Both changed files make targeted, well-reasoned changes. The workflow correctly addresses the previous root-process concern by chaining an inner sudo re-identification so xcodebuild never runs as root. Detection and fallback paths are guarded with warnings. The Swift change cleanly removes a non-strict expected-failure mask now that the underlying CI activation issue is fixed at the workflow level.

.github/workflows/test-e2e.yml — the HOME/USER env vars in XCODEBUILD_ENV reflect the runner user's identity and override sudo -H's home-dir substitution; worth a second look if the runner user and console GUI user are ever different accounts.

Important Files Changed

Filename Overview
.github/workflows/test-e2e.yml Adds GUI user detection + double-sudo launch wrapper; correctly addresses the previously flagged root-owned DerivedData issue; minor HOME/USER mismatch risk when runner user differs from GUI user.
cmuxUITests/FeedSidebarUITests.swift Removes non-strict XCTExpectFailure wrapper; app.launch() is now a real assertion aligned with the workflow fix.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Actions Runner
    participant Shell as Bootstrap Step
    participant LC as launchctl asuser
    participant GUI as GUI User Process
    participant XC as xcodebuild

    GH->>Shell: start "Run xcodebuild" step
    Shell->>Shell: "stat -f %Su /dev/console -> GUI_USER"
    alt Non-root GUI user found AND passwordless sudo available
        Shell->>Shell: automationmodetool enable (optional)
        Shell->>LC: sudo -n launchctl asuser GUI_UID
        LC->>GUI: sudo -n -H -u GUI_USER /usr/bin/env XCODEBUILD_ENV[]
        GUI->>XC: xcodebuild test (GUI bootstrap context)
        XC-->>Shell: exit code + output
    else No GUI user OR no passwordless sudo
        Shell->>Shell: warn ::warning::
        Shell->>XC: env XCODEBUILD_ENV[] xcodebuild test (fallback)
        XC-->>Shell: exit code + output
    end
    Shell->>GH: OUTPUT / EXIT_CODE
Loading

Reviews (3): Last reviewed commit: "Run E2E xcodebuild in GUI bootstrap" | Re-trigger Greptile

Comment thread .github/workflows/test-e2e.yml Outdated
Comment on lines +310 to +311
if [ "$GUI_USER" = "$CURRENT_USER" ]; then
RUN_XCODEBUILD=(sudo -n launchctl asuser "$GUI_UID" /usr/bin/env "${XCODEBUILD_ENV[@]}")

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 Root-owned DerivedData on persistent self-hosted runners

When GUI_USER == CURRENT_USER, the command is sudo -n launchctl asuser "$GUI_UID" /usr/bin/env … xcodebuild. launchctl asuser only sets the bootstrap context; it does not re-identify the process — so xcodebuild runs as root (UID 0). Even though HOME is forwarded explicitly, all files written under ~/Library/Developer/Xcode/DerivedData will be owned by root. On a persistent self-hosted runner the subsequent rm -rf ~/Library/Developer/Xcode/DerivedData/cmux-* (run as the non-root runner user, no sudo) will fail with permission denied on the next job, breaking the clean-up step. The GUI_USER != CURRENT_USER branch avoids this by chaining an inner sudo -n -H -u "$GUI_USER" to re-identify as the GUI user — the same technique could be used here (i.e. sudo -n launchctl asuser "$GUI_UID" sudo -n -H -u "$GUI_USER" /usr/bin/env …).

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 96275e3. Configure here.

Comment thread .github/workflows/test-e2e.yml Outdated

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In @.github/workflows/test-e2e.yml:
- Around line 286-316: The RUN_XCODEBUILD invocation can end up running
xcodebuild as root or with a caller's env instead of the console GUI user: in
the GUI_USER == CURRENT_USER branch replace the current sudo -n launchctl asuser
... /usr/bin/env invocation with a sudo -n -H -u "$GUI_USER" launchctl asuser
"$GUI_UID" /usr/bin/env ... (so the process runs with the GUI_USER credentials),
and in the other branch stop forcing caller-specific vars
(HOME/USER/LOGNAME/TMPDIR) into XCODEBUILD_ENV — either construct XCODEBUILD_ENV
from the target user's environment via sudo -u -H /usr/bin/env or remove those
overrides so launchctl asuser + sudo -u run with the target user's
HOME/USER/LOGNAME/TMPDIR to avoid desyncs; update the RUN_XCODEBUILD assignments
accordingly (symbols: XCODEBUILD_ENV, RUN_XCODEBUILD, GUI_USER, CURRENT_USER,
GUI_UID, launchctl asuser, sudo -n -H -u).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 924a32f9-739e-4947-955e-82a08e203efe

📥 Commits

Reviewing files that changed from the base of the PR and between 95d4c2f and 96275e3.

📒 Files selected for processing (2)
  • .github/workflows/test-e2e.yml
  • cmuxUITests/FeedSidebarUITests.swift

Comment thread .github/workflows/test-e2e.yml Outdated
@lawrencecchen
lawrencecchen merged commit 6dcddde into main May 28, 2026
20 checks passed
@lawrencecchen
lawrencecchen deleted the feat-e2e-gui-bootstrap branch May 28, 2026 09:51
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request May 28, 2026
- a791621 Reduce browser WebView input latency (manaflow-ai#4863)
- f2dbc31 Fix file preview Open With menu (manaflow-ai#4932)
- 95d4c2f Wait for E2E virtual display readiness (manaflow-ai#4928)
- 86558d1 Add cmux diff CodeView command (manaflow-ai#4451)
- 6dcddde Run E2E xcodebuild in GUI bootstrap (manaflow-ai#4940)

Conflicts resolved:
- CLINotifyProcessIntegrationRegressionTests.swift: kept both fork and upstream test additions.
- Workspace.swift: kept fork's per-layoutTab snapshot logic; rawLayout aliases the selected tab's layout to satisfy upstream's downstream uses.

This branch was successfully deployed

1 active deployment
Preview – cmux — 75ec1ac5 Deployed May 28, 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