feat(apple): Add non-interactive Apple Snapshots mode#1297
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
c5849cc to
4309c60
Compare
1ecaccd to
0e81310
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Setup failures exit zero
- Added abort() calls at lines 79 and 88 to ensure non-zero exit code when target resolution fails in non-interactive mode.
Or push these changes by commenting:
@cursor push b0e0508f41
Preview (b0e0508f41)
diff --git a/src/apple/snapshots/apple-snapshots-wizard.ts b/src/apple/snapshots/apple-snapshots-wizard.ts
--- a/src/apple/snapshots/apple-snapshots-wizard.ts
+++ b/src/apple/snapshots/apple-snapshots-wizard.ts
@@ -6,6 +6,7 @@
import { withTelemetry } from '../../telemetry';
import {
+ abort,
abortIfCancelled,
askForItemSelection,
confirmContinueIfNoOrDirtyGitRepo,
@@ -75,7 +76,7 @@
const appTargetName = await resolveAppTargetName(xcProject, options);
if (!appTargetName) {
- return;
+ await abort();
}
const hostedTestTargetName = await resolveHostedTestTargetName(
@@ -84,7 +85,7 @@
options,
);
if (!hostedTestTargetName) {
- return;
+ await abort();
}
const selectedTargetHasSwiftPreviews = targetHasSwiftPreviews(You can send follow-ups to the cloud agent here.
4309c60 to
d5375ef
Compare
0e81310 to
7d5069f
Compare
d5375ef to
18e0e3e
Compare
7d5069f to
1156eb3
Compare
18e0e3e to
df4041e
Compare
fe68f49 to
a291a73
Compare
cb5aea2 to
e05dc8b
Compare
a291a73 to
a12c102
Compare
e05dc8b to
2d53259
Compare
2d53259 to
5d69d75
Compare
a12c102 to
842c852
Compare
01ff854 to
f1f61e5
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Wrong non-interactive no-app-target error
- Separated the zero-targets case from multiple-targets case in non-interactive mode to show 'No application target found.' instead of misleadingly suggesting --app-target when no targets exist.
Or push these changes by commenting:
@cursor push 29a69bdb06
Preview (29a69bdb06)
diff --git a/src/apple/snapshots/apple-snapshots-wizard.ts b/src/apple/snapshots/apple-snapshots-wizard.ts
--- a/src/apple/snapshots/apple-snapshots-wizard.ts
+++ b/src/apple/snapshots/apple-snapshots-wizard.ts
@@ -191,15 +191,22 @@
return undefined;
}
- if (options.nonInteractive && appTargetNames.length !== 1) {
- clack.log.error(
- [
- 'Could not automatically select an Xcode app target in non-interactive mode.',
- `Available app targets: ${formatList(appTargetNames)}.`,
- 'Pass --app-target <target-name> to select the app target that SnapshotPreviews should use.',
- ].join(' '),
- );
- return undefined;
+ if (options.nonInteractive) {
+ if (appTargetNames.length === 0) {
+ clack.log.error('No application target found.');
+ return undefined;
+ }
+
+ if (appTargetNames.length !== 1) {
+ clack.log.error(
+ [
+ 'Could not automatically select an Xcode app target in non-interactive mode.',
+ `Available app targets: ${formatList(appTargetNames)}.`,
+ 'Pass --app-target <target-name> to select the app target that SnapshotPreviews should use.',
+ ].join(' '),
+ );
+ return undefined;
+ }
}
return await selectXcodeTarget(xcodeProject, {You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit f1f61e5. Configure here.
itaybre
left a comment
There was a problem hiding this comment.
Some comments here and there.
I am mainly concern about using undefined in the tests and not testing for false too
| skipConnect: boolean; | ||
| debug: boolean; | ||
| quiet: boolean; | ||
| nonInteractive: boolean; |
There was a problem hiding this comment.
l: If nonInteractive is either true / false here, why it is optional in other places?
There was a problem hiding this comment.
I've simplified this now, this is no longer optional where it's used exclusively by snapshot wizard codepaths, where it was threaded into existing shared functions like for example confirmContinueIfNoOrDirtyGitRepo we keep as an optional as apple-wizard doesn't need to pass argument as it's always interactive this avoid a ton of churn adding in explicit false at all the callsites.
| options, | ||
| ); | ||
| if (!hostedTestTargetName) { | ||
| return await abort('Apple Snapshots setup did not complete.'); |
There was a problem hiding this comment.
m: Should we tell the user why it didn't complete
There was a problem hiding this comment.
In all abort paths we have clack.log.error(...) which prints the underlying error message.
e2831b8 to
abe66f5
Compare
3fc21e5 to
2e5797b
Compare
abe66f5 to
e4e647a
Compare
Merge activity
|
## Stack This is **1/3** in the Apple Snapshots stack replacing the original unified PR #1293. - 1/3: #1295 — Xcode project primitives (this PR) - 2/3: #1296 — Interactive Apple Snapshots wizard - 3/3: #1297 — Non-interactive Apple Snapshots mode The top of the stack is intended to be an exact, lossless re-expression of #1293. ## Summary This PR refactors the existing Apple/Xcode project infrastructure needed by the Apple Snapshots wizard, without exposing the new `appleSnapshots` wizard yet. The goal is to make the shared Xcode helpers reviewable independently before adding the user-facing SnapshotPreviews flow. Existing Sentry Apple setup remains routed through the current `ios` wizard; this layer should be shared infrastructure, not a new runtime setup behavior. ## What changed - Split Xcode project lookup/selection helpers so target discovery can be reused by the snapshots flow. - Move Sentry Swift package metadata into a reusable package spec. - Extend `XcodeProject` with reusable helpers for: - hosted XCTest target detection via `TEST_HOST` - app bundle ID / executable lookup - Swift package product linking - source file resolution - Swift source insertion - synchronized-folder source membership support - Preserve existing `configureXcodeProject` / `updateXcodeProject` behavior for the normal Apple SDK setup path. - Add focused tests for the refactored project lookup, Xcode mutation, and git helper behavior. ## What this PR intentionally does not do - Does not add the `appleSnapshots` integration option. - Does not add the Apple Snapshots wizard entrypoint. - Does not configure SnapshotPreviews yet. - Does not configure Sentry auth, DSNs, runtime SDK initialization, dSYM upload scripts, Fastlane setup, MCP config, or CI workflow files. Those pieces land in the upstack PRs. ## Suggested review focus - `.pbxproj` mutation correctness and idempotency. - Shared Swift package product linking behavior. - Hosted XCTest target detection via `TEST_HOST`. - Ensuring existing `ios` wizard behavior did not accidentally change. - Whether the helper boundaries are general enough for both normal Apple SDK setup and SnapshotPreviews setup. ## Risk Medium. This refactors shared Apple/Xcode project mutation code used by existing setup paths. The risk is primarily around unusual Xcode project graphs, package product linking, target discovery, and source membership handling. ## Validation Before submitting the stack: - `yarn test` passed: 947 passed, 4 skipped - `yarn build` passed - Final stack tree matched original PR #1293 exactly - `gt submit --stack --dry-run` passed Co-Authored-By: GPT-5 Codex <noreply@openai.com>
## Stack This is **2/3** in the Apple Snapshots stack replacing the original unified PR #1293. - 1/3: #1295 — Xcode project primitives - 2/3: #1296 — Interactive Apple Snapshots wizard (this PR) - 3/3: #1297 — Non-interactive Apple Snapshots mode This PR builds on #1295. The top of the stack is intended to be an exact, lossless re-expression of #1293. ## Summary Adds a standalone **Apple Snapshots** wizard for configuring Sentry SnapshotPreviews in Apple/Xcode projects without running the normal iOS runtime SDK setup. The new `appleSnapshots` integration is available from the wizard picker and via `--integration appleSnapshots`. It reuses the Xcode project discovery path from #1295, asks for the app target that hosts Swift previews, then selects a hosted XCTest target for running SnapshotPreviews. This is intentionally separate from the existing `ios` wizard. Snapshot setup is related to Apple projects, but it should not silently configure normal runtime SDK behavior. Keeping this as its own wizard makes the user-visible behavior narrower: project wiring plus explicit next-step guidance for snapshot export/upload. ## What changed - Adds the `appleSnapshots` integration and CLI routing. - Adds SnapshotPreviews package configuration. - Links: - `SnapshottingTests` to the hosted test target - `SnapshotPreferences` to the selected app target only when Swift previews are detected - Creates or reuses a generated `SnapshotTest` subclass. - Ensures the generated test file belongs to the selected XCTest target. - Adds scheme inference for generated `xcodebuild test` guidance only. - Prints local export/upload guidance for: - `xcodebuild` - `sentry-cli snapshots upload` - existing Fastlane snapshot upload lanes - Adds tests for SnapshotPreviews package setup, generated test files, source insertion, smoke coverage, scheme inference, preflight behavior, CLI constants, and run routing. - Updates the help snapshot and changelog for the interactive wizard surface. ## Behavior contract in this layer - App target selection follows the existing interactive wizard pattern. - Hosted XCTest target selection uses hosted test target detection from #1295. - Missing Swift previews are not fatal. Interactive mode asks whether to continue. - Snapshot scheme inference is used only to generate `xcodebuild test` guidance. - If the correct scheme cannot be inferred safely, the wizard still completes and prints guidance without a scheme. - The wizard does not configure Sentry auth, DSNs, runtime SDK initialization, dSYM upload scripts, Fastlane dSYM setup, MCP config, or CI workflow files. ## What this PR intentionally does not do - Does not add unattended/non-interactive behavior. - Does not add `--non-interactive`, `--app-target`, or `--hosted-test-target` flags for Apple Snapshots. - Does not guarantee prompt-free execution for agentic runs. Those pieces land in #1297. ## Suggested review focus - SnapshotPreviews package URL, minimum version, and product names. - `.pbxproj` mutation correctness and idempotency for package/product linking. - Generated snapshot test file placement/reuse for both classic source phases and synchronized folders. - Hosted XCTest target selection behavior in interactive mode. - Scheme inference being limited to generated `xcodebuild test` guidance. - Ensuring the existing `ios` wizard did not pick up accidental runtime behavior changes. ## Risk Medium. The new wizard mutates Xcode project graphs, links package products, and creates/reuses source files. The new `appleSnapshots` flow is isolated from auth/runtime/dSYM/CI configuration, but unusual Xcode project structures, ambiguous schemes, or non-standard hosted test target settings are the areas most likely to need reviewer scrutiny. ## Validation Before submitting the stack: - `yarn test` passed: 947 passed, 4 skipped - `yarn build` passed - Final stack tree matched original PR #1293 exactly - `gt submit --stack --dry-run` passed Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com> # Conflicts: # src/apple/snapshots/apple-snapshots-wizard.ts # test/apple/snapshots/apple-snapshots-wizard.test.ts
Require non-interactive Apple Snapshots setup to opt into snapshots preflight behavior explicitly. Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Report a missing application target directly before handling non-interactive ambiguity. This avoids suggesting --app-target when the project has no selectable app targets. Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Previously `nonInteractive` was an optional flag threaded through the Apple snapshots wizard and git-check helpers as `boolean | undefined`, forcing every call site to reason about the undefined case. Default it to `false` at each boundary and treat it as a required boolean so the flag carries a single, explicit meaning. Add unit tests covering the non-interactive abort paths of confirmContinueIfNoOrDirtyGitRepo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When linking the SnapshotPreviews products or adding the test file fails, the wizard used clack.outro and returned, which exited cleanly and recorded no failure telemetry. Use abort instead so the run is marked as failed and exits with a non-zero status, matching the other failure paths. Also extract the repeated "Apple Snapshots setup did not complete." message into a shared constant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e4e647a to
8fb7b90
Compare



Stack
This is 3/3 in the Apple Snapshots stack replacing the original unified PR #1293.
This is the top of the stack. The final tree of this stack was verified to exactly match original PR #1293.
Summary
Adds unattended/agent-friendly execution for the Apple Snapshots wizard introduced in #1296.
The main goal is that non-interactive mode never waits on stdin. It either proceeds from explicit arguments and safe single-target assumptions, or it fails with actionable manual setup instructions and the CLI flag needed to continue.
What changed
--non-interactive--app-target--hosted-test-targetBehavior contract in this layer
--app-targetwhen provided.--app-target, the wizard auto-selects only when there is a single app target.--app-target.--hosted-test-targetwhen provided, as long as the target exists and has a non-emptyTEST_HOST.--hosted-test-target, the wizard first narrows hosted XCTest targets to those whoseTEST_HOSTmatches the selected app target's bundle/executable names.--hosted-test-target.What this PR intentionally does not do
ioswizard into a SnapshotPreviews setup path.Suggested review focus
TEST_HOSTand app bundle/executable name matching.Risk
Medium. This layer controls unattended behavior and is the most important one for agentic setup safety. The main risk is choosing the wrong app/test target in unusual projects or leaving a prompt path reachable in non-interactive mode.
Validation
Before submitting the stack:
yarn testpassed: 947 passed, 4 skippedyarn buildpassedgt submit --stack --dry-runpassedCo-Authored-By: GPT-5 Codex noreply@openai.com