Skip to content

fix(ci): bootstrap generated Xcode project in CI - #1

Merged
SamGu-NRX merged 4 commits into
mainfrom
codex/fix-ios-ci
Mar 31, 2026
Merged

SamGu-NRX merged 4 commits into
mainfrom
codex/fix-ios-ci

Conversation

@SamGu-NRX

@SamGu-NRX SamGu-NRX commented Mar 30, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • install XcodeGen in CI and generate the project before test and Periphery jobs
  • make local scripts regenerate ignored Xcode artifacts when needed
  • align stale source-inspection tests with current implementations
  • make capture shutdown reset published camera state deterministically

Verification

  • ./scripts/run_ios_tests.sh
  • ./scripts/run_periphery_scan.sh

Summary by CodeRabbit

  • Chores

    • Improved iOS CI and local tooling to ensure Xcode project generation and more reliable simulator selection before builds and scans.
  • Refactor

    • Consolidated camera state updates for more consistent session handling.
  • Tests

    • Updated tests to reflect new concurrency/isolation patterns and revised lifecycle expectations.

@coderabbitai

coderabbitai Bot commented Mar 30, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9df4aaa-d487-476d-8928-97539859bfc9

📥 Commits

Reviewing files that changed from the base of the PR and between 09eb9b4 and 0d035ab.

📒 Files selected for processing (1)
  • scripts/ensure_xcode_project.sh
✅ Files skipped from review due to trivial changes (1)
  • scripts/ensure_xcode_project.sh

📝 Walkthrough

Walkthrough

Centralizes Xcode project generation via a new scripts/ensure_xcode_project.sh, updates CI and several iOS helper scripts to invoke it, enhances simulator resolution to prefer Xcode-based lookups with simctl fallback, and consolidates published-state updates in FLCaptureSessionCoordinator via a new private helper.

Changes

Cohort / File(s) Summary
CI Workflow
\.github/workflows/ios-ci.yml
Installs XcodeGen and runs scripts/ensure_xcode_project.sh in build-and-test and dead-code-advisory jobs; changes simulator resolution invocation to call the resolver without the iPhone argument.
Xcode project orchestration
scripts/ensure_xcode_project.sh, scripts/open_ios_project.sh, scripts/run_ios_tests.sh, scripts/run_periphery_scan.sh, scripts/verify_healthkit_entitlement.sh
Adds new ensure_xcode_project.sh that validates/generates Xcode project outputs with xcodegen. Other scripts now delegate project validation/generation to this script and no longer run xcodegen inline.
Simulator resolution
scripts/resolve_ios_sim_destination.sh
Changes default preferred device to iPhone 17 Pro; adds project/scheme detection and two resolution strategies: xcodebuild -showdestinations first (when project exists) then simctl fallback; introduces helpers to extract UUIDs and try named/generic patterns.
Capture session state refactor
apps/ios/DesignSystem/Components/FLCaptureSessionCoordinator.swift
Introduces private updatePublishedState(cameraReady:flashAvailable:flashOn:isCapturingPhoto:) to centralize and main-thread state updates; replaces scattered Task { @mainactor ... } updates with calls to the helper.
Tests updated
apps/ios/Tests/CaptureLifecycleRegressionTests.swift, apps/ios/Tests/GeminiLiveTutorialFlowTests.swift, apps/ios/Tests/OnboardingPerformanceRemediationTests.swift
Annotates one test with @MainActor; adjusts recipe-promotion test assertions to expect context.completeObjective()/side-effect changes; updates a UI/performance test to expect .task(id:) usage and a @MainActor async helper.

Sequence Diagram(s)

sequenceDiagram
    participant CI as GitHub Actions
    participant Script as ensure_xcode_project.sh
    participant XcodeGen as xcodegen
    participant XcodeBuild as xcodebuild
    participant SimCtl as simctl
    participant Periphery as periphery

    CI->>Script: invoke ensure_xcode_project.sh
    Script->>XcodeGen: run xcodegen generate (if needed) --> rgba(100,150,255,0.5)
    Script-->>CI: exit success
    CI->>XcodeBuild: xcodebuild -showdestinations (if project present)
    alt xcodebuild returns UUID
        XcodeBuild-->>CI: destination UUID
    else fallback
        CI->>SimCtl: simctl list devices available
        SimCtl-->>CI: destination UUID
    end
    CI->>Periphery: run periphery / xcodebuild with resolved destination
    Periphery-->>CI: scan results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through scripts and tidy logs,
Summoned Xcode, chased away bogs,
State snugged safe in one small nook,
Simulators found by sleuth and look,
Tests and CI dance—hip, hop, hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective: ensuring the Xcode project is generated/bootstrapped in CI before builds and tests.

✏️ 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 codex/fix-ios-ci

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.

@SamGu-NRX
SamGu-NRX marked this pull request as ready for review March 30, 2026 20:48

@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

🧹 Nitpick comments (3)
apps/ios/Tests/OnboardingPerformanceRemediationTests.swift (1)

99-101: Make the new helper-signature assertion whitespace-tolerant.

Line 101 currently depends on exact newline/indentation ("@MainActor\n private ..."), so harmless formatting changes can break the test. Prefer a regex (or split token assertions) so this checks structure rather than spacing.

Suggested change
-    XCTAssertTrue(
-      backgroundSource.contains(
-        "@MainActor\n  private func requestGrainImage(for size: CGSize) async"))
+    XCTAssertTrue(
+      backgroundSource.range(
+        of: #"@MainActor\s+private func requestGrainImage\(for size: CGSize\) async"#,
+        options: .regularExpression
+      ) != nil
+    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/Tests/OnboardingPerformanceRemediationTests.swift` around lines 99 -
101, The test currently asserts exact whitespace for the helper signature by
checking backgroundSource.contains("@MainActor\n  private func
requestGrainImage(for size: CGSize) async"); change this to a
whitespace-tolerant check, e.g. use backgroundSource.range(of:
"@MainActor\\s*private func requestGrainImage\\(for size: CGSize\\)\\s*async",
options: .regularExpression) != nil (or use NSRegularExpression) so the
assertion targets the structure of requestGrainImage(for:) rather than exact
newlines/indentation.
apps/ios/Tests/GeminiLiveTutorialFlowTests.swift (1)

36-38: Strengthen source-inspection assertions to verify branch structure, not just token presence

These checks are directionally correct, but plain contains can pass even when logic is moved outside the recipe-promotion path. Consider asserting a scoped regex pattern for handleRecipeSelection(_:) so the test verifies control-flow intent too.

Suggested test-hardening diff
   XCTAssertTrue(source.contains("liveAssistantCoordinator.storeRecipeMatch"))
-  XCTAssertTrue(source.contains("context.completeObjective()"))
-  XCTAssertTrue(source.contains("didPromoteRecipeMatchLesson = true"))
-  XCTAssertTrue(source.contains("selectedRecipe = scored"))
+  let promotionPattern = #"""
+  if let context = tutorialFlowContext,
+  \s*context.activeQuest == \.pickRecipeMatch,
+  \s*!didPromoteRecipeMatchLesson
+  \s*\{
+  \s*storeRecipeForAssistant\(scored\)
+  \s*didPromoteRecipeMatchLesson = true
+  \s*context.completeObjective\(\)
+  \s*return
+  \s*\}
+  """#
+  XCTAssertNotNil(source.range(of: promotionPattern, options: .regularExpression))
+  XCTAssertTrue(source.contains("selectedRecipe = scored"))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/Tests/GeminiLiveTutorialFlowTests.swift` around lines 36 - 38, The
assertions currently only check token presence in `source` and can be fooled if
the tokens are moved out of the recipe-promotion branch; update the test to
assert a scoped pattern for `handleRecipeSelection(_:)` instead: locate the
function body for `handleRecipeSelection(_:)` in `source` and use a regex that
matches the function signature and its braces, then assert that within that body
the sequence (or presence) of `context.completeObjective()`,
`didPromoteRecipeMatchLesson = true`, and `selectedRecipe = scored` appears in
the intended order (or at least all three) so the test verifies the
branch/control-flow rather than global token presence.
apps/ios/DesignSystem/Components/FLCaptureSessionCoordinator.swift (1)

122-159: Consider a brief comment explaining the dual state reset.

Both calls at lines 123-128 (before async) and 153-158 (after cleanup) set identical values. This is intentional for determinism—the first provides immediate UI feedback, the second ensures final consistency. A short comment on the first call (e.g., // Reset published state immediately for deterministic UI update) would clarify this to future readers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ios/DesignSystem/Components/FLCaptureSessionCoordinator.swift` around
lines 122 - 159, Add a brief inline comment above the first call to
updatePublishedState in shutdownSession to explain the intentional dual state
reset: note that the first call provides immediate UI feedback/deterministic
update while the second (inside sessionQueue.async after cleanup) ensures final
consistency; place the comment near the first updatePublishedState call and
reference shutdownSession and sessionQueue.async so future readers understand
the purpose of both resets.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/ensure_xcode_project.sh`:
- Around line 5-12: The script allows overriding PROJECT_PATH/project_spec but
only checks required_outputs once; after the project generation step you must
re-validate that each required output (the entries in required_outputs, e.g.,
"$project_path/project.pbxproj", "$repo_root/Xcode/FridgeLuck-Info.plist",
"$repo_root/Xcode/FridgeLuck.entitlements") exists and exit non-zero if any are
missing. Update ensure_xcode_project.sh to run the same existence checks for
required_outputs immediately after the generation command (the block that
creates the Xcode project) and return a clear error message referencing
project_path when a file is absent so downstream xcodebuild won’t run on an
incomplete project.

---

Nitpick comments:
In `@apps/ios/DesignSystem/Components/FLCaptureSessionCoordinator.swift`:
- Around line 122-159: Add a brief inline comment above the first call to
updatePublishedState in shutdownSession to explain the intentional dual state
reset: note that the first call provides immediate UI feedback/deterministic
update while the second (inside sessionQueue.async after cleanup) ensures final
consistency; place the comment near the first updatePublishedState call and
reference shutdownSession and sessionQueue.async so future readers understand
the purpose of both resets.

In `@apps/ios/Tests/GeminiLiveTutorialFlowTests.swift`:
- Around line 36-38: The assertions currently only check token presence in
`source` and can be fooled if the tokens are moved out of the recipe-promotion
branch; update the test to assert a scoped pattern for
`handleRecipeSelection(_:)` instead: locate the function body for
`handleRecipeSelection(_:)` in `source` and use a regex that matches the
function signature and its braces, then assert that within that body the
sequence (or presence) of `context.completeObjective()`,
`didPromoteRecipeMatchLesson = true`, and `selectedRecipe = scored` appears in
the intended order (or at least all three) so the test verifies the
branch/control-flow rather than global token presence.

In `@apps/ios/Tests/OnboardingPerformanceRemediationTests.swift`:
- Around line 99-101: The test currently asserts exact whitespace for the helper
signature by checking backgroundSource.contains("@MainActor\n  private func
requestGrainImage(for size: CGSize) async"); change this to a
whitespace-tolerant check, e.g. use backgroundSource.range(of:
"@MainActor\\s*private func requestGrainImage\\(for size: CGSize\\)\\s*async",
options: .regularExpression) != nil (or use NSRegularExpression) so the
assertion targets the structure of requestGrainImage(for:) rather than exact
newlines/indentation.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32a7cb44-2a9d-40f1-ac17-f7c358a4553a

📥 Commits

Reviewing files that changed from the base of the PR and between c1b3248 and 09eb9b4.

📒 Files selected for processing (11)
  • .github/workflows/ios-ci.yml
  • apps/ios/DesignSystem/Components/FLCaptureSessionCoordinator.swift
  • apps/ios/Tests/CaptureLifecycleRegressionTests.swift
  • apps/ios/Tests/GeminiLiveTutorialFlowTests.swift
  • apps/ios/Tests/OnboardingPerformanceRemediationTests.swift
  • scripts/ensure_xcode_project.sh
  • scripts/open_ios_project.sh
  • scripts/resolve_ios_sim_destination.sh
  • scripts/run_ios_tests.sh
  • scripts/run_periphery_scan.sh
  • scripts/verify_healthkit_entitlement.sh

Comment thread scripts/ensure_xcode_project.sh
@SamGu-NRX

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 31, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@SamGu-NRX
SamGu-NRX merged commit bcabc8f into main Mar 31, 2026
3 checks passed
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