Commit 31040a1
authored
feat: Xcode multi-platform template with deploy & screenshot scripts (#129)
* feat: add Xcode multi-platform template with deploy and screenshot scripts
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.
* address review: fix Xcode template scheme/script issues and add endpoint 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
* address review: restrict script checks to Xcode types, add win32 chmod 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
* address review: scope deploy tests to iOS builds, use fs.chmod in scaffold
- 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
* address review: consistent xcodeScripts in API response, safer bundle 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)
* address review: expand tilde in deploy script KEY_PATH
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.
* address review: fix Swift compilation, dynamic simulator detection, dedupe 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
* address review: use shared XCODE_BUNDLE_PREFIX in iOS scaffold, parse 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
* address review: toBundleId fallback, quoted YAML handling, chmod error recovery, service tests
- toBundleId falls back to 'app' suffix for names with no alphanumeric chars
- deriveProjectInfo strips YAML wrapping quotes from scalar values
- chmod failure pushed to errors array instead of throwing 500
- Add 20 unit tests for xcodeScripts service (toBundleId, toTargetName,
checkScripts, generateDeployScript, generateScreenshotScript, etc.)
* address review: validate repoPath existence in checkScripts and install 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
* address review: validate project.yml values against strict allowlists
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.
* address review: guard git commit in deploy.sh, skip chmod on win32 in scaffold
- deploy.sh git commit only runs inside git repos with staged changes
- scaffoldXcode skips chmod on Windows (consistent with installScripts)
* address review: fix bash tilde expansion bug and expand installScripts 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.
* address review: restore process.platform descriptor cleanly in win32 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.
* address review: scope Xcode scripts by app type and validate via Zod 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.
* address review: harden toTargetName and quote .env example with spaces
- 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.1 parent f883273 commit 31040a1
13 files changed
Lines changed: 2206 additions & 20 deletions
File tree
- .changelog
- client/src
- components/apps
- tabs
- pages
- services
- server
- routes
- services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
1 | 11 | | |
2 | 12 | | |
3 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | | - | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
13 | 19 | | |
14 | 20 | | |
15 | 21 | | |
16 | 22 | | |
17 | 23 | | |
18 | 24 | | |
| 25 | + | |
19 | 26 | | |
20 | 27 | | |
21 | 28 | | |
| |||
43 | 50 | | |
44 | 51 | | |
45 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
46 | 71 | | |
47 | 72 | | |
48 | 73 | | |
| |||
90 | 115 | | |
91 | 116 | | |
92 | 117 | | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
93 | 163 | | |
94 | 164 | | |
95 | 165 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
71 | 75 | | |
72 | 76 | | |
73 | 77 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
71 | 72 | | |
72 | 73 | | |
73 | 74 | | |
74 | | - | |
| 75 | + | |
75 | 76 | | |
76 | 77 | | |
77 | 78 | | |
| |||
125 | 126 | | |
126 | 127 | | |
127 | 128 | | |
128 | | - | |
| 129 | + | |
| 130 | + | |
129 | 131 | | |
130 | 132 | | |
131 | 133 | | |
| |||
183 | 185 | | |
184 | 186 | | |
185 | 187 | | |
186 | | - | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
187 | 207 | | |
188 | 208 | | |
189 | 209 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
61 | 74 | | |
62 | 75 | | |
63 | 76 | | |
64 | 77 | | |
65 | 78 | | |
66 | 79 | | |
| 80 | + | |
67 | 81 | | |
68 | 82 | | |
69 | 83 | | |
| |||
639 | 653 | | |
640 | 654 | | |
641 | 655 | | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
642 | 741 | | |
0 commit comments