feat: Xcode multi-platform template with deploy & screenshot scripts#129
feat: Xcode multi-platform template with deploy & screenshot scripts#129
Conversation
…ripts New "Xcode Multi-Platform" app template scaffolds iOS + macOS + watchOS via XcodeGen with generic deploy.sh (TestFlight), take_screenshots.sh (iOS/iPad), and take_screenshots_macos.sh (macOS) automation scripts. PortOS now detects missing management scripts in Xcode-managed apps and surfaces a banner in the app detail overview with one-click install. Deploy panel adds --watch (watchOS) flag support.
There was a problem hiding this comment.
Pull request overview
Adds a new Xcode multi-platform scaffolding flow (iOS + macOS + watchOS) with shared deploy/screenshot script generators, plus server + client support to detect and install missing Xcode management scripts and to deploy watchOS via a new --watch flag.
Changes:
- Introduces
xcodeScriptsservice to generate/check/install Xcode management scripts (deploy + screenshots) and exposes an install API endpoint. - Adds a new “Xcode Multi-Platform” scaffold template and wires it into the scaffold route + templates UI.
- Extends deploy flag handling end-to-end to support
--watch(watchOS).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| server/services/xcodeScripts.js | New generators + script health check + install logic for Xcode management scripts |
| server/services/appDeployer.js | Adds --watch to allowed deploy flags |
| server/routes/scaffoldXcode.js | New multi-platform XcodeGen scaffold (iOS/macOS/watchOS) + scripts + CLAUDE.md |
| server/routes/scaffoldIOS.js | Reuses shared Xcode constants/helpers (toBundleId, toTargetName, XCODE_TEAM_ID) |
| server/routes/scaffold.js | Registers new template, skips npm install for it, updates gitignore + app registration |
| server/routes/apps.js | Adds xcodeScripts to app payloads and new install endpoint |
| client/src/services/apiApps.js | Adds installXcodeScripts API helper |
| client/src/pages/Templates.jsx | Adds icon mapping for the new template icon |
| client/src/components/apps/tabs/OverviewTab.jsx | Adds missing-scripts banner + install actions |
| client/src/components/apps/DeployPanel.jsx | Adds --watch option in deploy flag picker |
| .changelog/NEXT.md | Documents newly added template + script health check + deploy flag |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…int tests - Add UITests to iOS scheme testTargets for screenshot automation - Fix watchOS scheme name mismatch (use underscore to match target name) - Replace shell exec with execFile for chmod (avoid injection) - Add win32 platform guard to deriveProjectInfo - Surface partial install errors in OverviewTab toast notifications - Update deployApp JSDoc to include --watch flag - Add 5 tests for POST /api/apps/:id/xcode-scripts/install endpoint
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…d guard, reuse toTargetName - Replace NON_PM2_TYPES with XCODE_TYPES set (excludes 'swift'/SPM apps) - Add win32 platform guard for chmod in installScripts - Reuse shared toTargetName() in scaffold.js instead of inline regex
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ffold - Only run iOS simulator tests when --ios is being built (not for macOS/watchOS-only deploys) - Replace shell exec chmod with fs.promises.chmod in scaffoldXcode.js
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… ID derivation - Add xcodeScripts to PM2 app enrichment for consistent response shape - Derive bundle ID from project name instead of regex match (avoids picking wrong target's PRODUCT_BUNDLE_IDENTIFIER in multi-target configs)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Tilde (~) doesn't expand inside double quotes in bash, so the generated deploy.sh now uses parameter substitution to replace leading ~ with $HOME before the -f check.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…edupe toasts - Add missing attributes: nil to FileManager.createDirectory call - Use sanitized targetName for Swift appName constant - Detect iOS runtime version dynamically instead of hard-coding 18.6 - Remove pinned OS version from deploy.sh test fallback - Fix duplicate error toasts by letting request() handle HTTP errors
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… actual bundle ID - Import XCODE_BUNDLE_PREFIX in scaffoldIOS instead of hard-coding - deriveProjectInfo now parses PRODUCT_BUNDLE_IDENTIFIER from project.yml, filtering out test/watch targets, with fallback to name-derived ID
…ll route - checkScripts short-circuits when repoPath doesn't exist on disk - Install route returns PATH_NOT_FOUND (400) for missing repo paths - Add test for PATH_NOT_FOUND case, fix test mocks for repoPath check
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Parsed target names and bundle IDs from project.yml are now validated against safe character patterns before being interpolated into generated bash scripts. Falls back to sanitized toTargetName/toBundleId on invalid input.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… scaffold - deploy.sh git commit only runs inside git repos with staged changes - scaffoldXcode skips chmod on Windows (consistent with installScripts)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…s test coverage - Generated deploy.sh used \~ instead of ~ in KEY_PATH parameter expansion, which only matched a literal backslash-tilde and left ~/Library/... paths unexpanded, causing the subsequent -f file check to fail. - Tightened the existing tilde expansion test to assert the exact pattern (KEY_PATH/#~/$HOME) so this regression cannot reappear silently. - Added unit tests for installScripts and deriveProjectInfo covering: project.yml parsing (name + bundle id, quote stripping, watchkit/Tests filtering, unsafe-name rejection), .xcodeproj fallback, win32 short-circuit, the never-overwrite guarantee, .env.example creation guard, chmod failure reporting, and the Windows chmod-not-supported message.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…test Capture the original property descriptor via getOwnPropertyDescriptor and re-define with configurable: true so the override can be reverted on Node versions where process.platform is not configurable by default.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…enum - XCODE_MANAGEMENT_SCRIPTS entries now declare which app.types they apply to. ios-native apps no longer surface take_screenshots_macos.sh in the missing- scripts banner, and macos-native apps no longer surface take_screenshots.sh. - installScripts refuses to write a script that does not apply to the target app's type and reports a clear error. - Added scriptsForAppType helper and exported XCODE_SCRIPT_NAMES. - Tightened POST /api/apps/:id/xcode-scripts/install validation to a Zod enum bounded by XCODE_SCRIPT_NAMES, so unknown or oversized payloads are rejected at the validation layer instead of bouncing through installScripts. - Added unit tests covering type-scoped checkScripts/installScripts behavior and updated route tests for the new validation contract.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- toTargetName now produces a guaranteed-valid Swift identifier: trims whitespace, collapses runs of underscores, strips leading/trailing underscores, prefixes with 'App_' when the first character is not [A-Za-z_], and falls back to 'App' for empty/null/undefined input. This prevents the scaffolder from emitting uncompilable Swift like 'struct 123App' when the user names an app starting with a digit. - Quoted APPSTORE_API_PRIVATE_KEY_PATH in XCODE_ENV_EXAMPLE because deploy.sh loads .env via 'source .env' and the example path contains spaces; without quotes the shell would split on whitespace and break sourcing. - Added regression tests for digit-leading names, all-symbol names, runs of symbols collapsing, leading/trailing trimming, and null/undefined input.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
deploy.sh,take_screenshots.sh, andtake_screenshots_macos.shautomation scripts--watch(watchOS) flag support for TestFlight deploymentDetails
Template (
scaffoldXcode.js): Generates a complete XcodeGen project with:--ios,--macos,--watch,--allflagsScript health check (
xcodeScripts.js): Service that:POST /api/apps/:id/xcode-scripts/installwith Zod validationXCODE_TEAM_ID,toBundleId,toTargetName) used by both scaffold modulesUI changes:
OverviewTab: Warning banner when Xcode apps are missing scripts, with Install All / per-script buttonsDeployPanel: watchOS flag option in deploy dropdownTemplates: MonitorSmartphone icon for the new templateTest plan
xcodeScripts.js(service) owns generators,scaffoldXcode.js(route) imports from service