Skip to content

feat: Xcode multi-platform template with deploy & screenshot scripts#129

Merged
atomantic merged 16 commits intomainfrom
feat/xcode-multiplatform-template
Apr 6, 2026
Merged

feat: Xcode multi-platform template with deploy & screenshot scripts#129
atomantic merged 16 commits intomainfrom
feat/xcode-multiplatform-template

Conversation

@atomantic
Copy link
Copy Markdown
Owner

Summary

  • New Xcode Multi-Platform app template scaffolds iOS + macOS + watchOS via XcodeGen with generic deploy.sh, take_screenshots.sh, and take_screenshots_macos.sh automation scripts
  • PortOS now detects missing management scripts in Xcode-managed apps and surfaces a warning banner in the app detail overview with one-click install
  • Deploy panel adds --watch (watchOS) flag support for TestFlight deployment

Details

Template (scaffoldXcode.js): Generates a complete XcodeGen project with:

  • iOS, macOS, and watchOS targets with shared code module
  • Platform-conditional SwiftUI entry points and ContentView
  • Unit test + UI test targets (with ScreenshotTests stubs for XCUITest)
  • macOS entitlements, watchOS companion app
  • Generic deploy.sh supporting --ios, --macos, --watch, --all flags
  • Screenshot automation for iOS/iPad and macOS App Store

Script health check (xcodeScripts.js): Service that:

  • Checks which management scripts exist in any Xcode app's repo
  • Generates and installs missing scripts with project-specific names
  • Exposes via POST /api/apps/:id/xcode-scripts/install with Zod validation
  • Shared constants (XCODE_TEAM_ID, toBundleId, toTargetName) used by both scaffold modules

UI changes:

  • OverviewTab: Warning banner when Xcode apps are missing scripts, with Install All / per-script buttons
  • DeployPanel: watchOS flag option in deploy dropdown
  • Templates: MonitorSmartphone icon for the new template

Test plan

  • All 2133 server tests pass
  • Client builds cleanly
  • Import chain verified: xcodeScripts.js (service) owns generators, scaffoldXcode.js (route) imports from service
  • Manual: Create app from "Xcode Multi-Platform" template, verify all files generated
  • Manual: Import existing Xcode app, verify missing scripts banner appears, install works

…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.
Copilot AI review requested due to automatic review settings April 6, 2026 02:12
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 xcodeScripts service 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
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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)
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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
@atomantic atomantic requested a review from Copilot April 6, 2026 03:30
…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
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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)
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

@atomantic atomantic merged commit 31040a1 into main Apr 6, 2026
6 checks passed
@atomantic atomantic deleted the feat/xcode-multiplatform-template branch April 6, 2026 18:48
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.

2 participants