@invarn/cibuild 2.9.6 → 2.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/dist/chunk-35SI42CD.mjs +1 -0
  2. package/dist/chunk-IC45KVLJ.mjs +1 -0
  3. package/dist/chunk-XDY4V23V.mjs +1 -0
  4. package/dist/cli.cjs +14 -14
  5. package/dist/commands.mjs +1 -0
  6. package/dist/lib.mjs +3934 -0
  7. package/package.json +6 -10
  8. package/dist/src/cli.d.ts +0 -3
  9. package/dist/src/cli.d.ts.map +0 -1
  10. package/dist/src/cli.js +0 -399
  11. package/dist/src/commands/a-credential-target-follows-the-flavor-source-set.test.d.ts +0 -38
  12. package/dist/src/commands/a-credential-target-follows-the-flavor-source-set.test.d.ts.map +0 -1
  13. package/dist/src/commands/a-credential-target-follows-the-flavor-source-set.test.js +0 -222
  14. package/dist/src/commands/a-credential-two-workflows-cannot-share-is-declared-per-workflow.test.d.ts +0 -41
  15. package/dist/src/commands/a-credential-two-workflows-cannot-share-is-declared-per-workflow.test.d.ts.map +0 -1
  16. package/dist/src/commands/a-credential-two-workflows-cannot-share-is-declared-per-workflow.test.js +0 -324
  17. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts +0 -2
  18. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.d.ts.map +0 -1
  19. package/dist/src/commands/a-properties-stand-in-declares-the-keys-the-build-reads.test.js +0 -382
  20. package/dist/src/commands/an-already-stored-value-does-not-answer-the-target-question.test.d.ts +0 -29
  21. package/dist/src/commands/an-already-stored-value-does-not-answer-the-target-question.test.d.ts.map +0 -1
  22. package/dist/src/commands/an-already-stored-value-does-not-answer-the-target-question.test.js +0 -160
  23. package/dist/src/commands/android-gms-guard.test.d.ts +0 -9
  24. package/dist/src/commands/android-gms-guard.test.d.ts.map +0 -1
  25. package/dist/src/commands/android-gms-guard.test.js +0 -78
  26. package/dist/src/commands/android-java-version.test.d.ts +0 -12
  27. package/dist/src/commands/android-java-version.test.d.ts.map +0 -1
  28. package/dist/src/commands/android-java-version.test.js +0 -209
  29. package/dist/src/commands/android-scanner-java.test.d.ts +0 -2
  30. package/dist/src/commands/android-scanner-java.test.d.ts.map +0 -1
  31. package/dist/src/commands/android-scanner-java.test.js +0 -130
  32. package/dist/src/commands/android-scanner.d.ts +0 -250
  33. package/dist/src/commands/android-scanner.d.ts.map +0 -1
  34. package/dist/src/commands/android-scanner.js +0 -1639
  35. package/dist/src/commands/build.d.ts +0 -215
  36. package/dist/src/commands/build.d.ts.map +0 -1
  37. package/dist/src/commands/build.js +0 -1433
  38. package/dist/src/commands/build.test.d.ts +0 -13
  39. package/dist/src/commands/build.test.d.ts.map +0 -1
  40. package/dist/src/commands/build.test.js +0 -121
  41. package/dist/src/commands/detect-platform.d.ts +0 -13
  42. package/dist/src/commands/detect-platform.d.ts.map +0 -1
  43. package/dist/src/commands/detect-platform.js +0 -51
  44. package/dist/src/commands/detect-project.d.ts +0 -7
  45. package/dist/src/commands/detect-project.d.ts.map +0 -1
  46. package/dist/src/commands/detect-project.js +0 -12
  47. package/dist/src/commands/each-flavor-is-asked-for-its-own-properties-file.test.d.ts +0 -26
  48. package/dist/src/commands/each-flavor-is-asked-for-its-own-properties-file.test.d.ts.map +0 -1
  49. package/dist/src/commands/each-flavor-is-asked-for-its-own-properties-file.test.js +0 -196
  50. package/dist/src/commands/edit.d.ts +0 -12
  51. package/dist/src/commands/edit.d.ts.map +0 -1
  52. package/dist/src/commands/edit.js +0 -652
  53. package/dist/src/commands/edit.test.d.ts +0 -6
  54. package/dist/src/commands/edit.test.d.ts.map +0 -1
  55. package/dist/src/commands/edit.test.js +0 -45
  56. package/dist/src/commands/fidelity-trim.d.ts +0 -13
  57. package/dist/src/commands/fidelity-trim.d.ts.map +0 -1
  58. package/dist/src/commands/fidelity-trim.js +0 -21
  59. package/dist/src/commands/fidelity-trim.test.d.ts +0 -8
  60. package/dist/src/commands/fidelity-trim.test.d.ts.map +0 -1
  61. package/dist/src/commands/fidelity-trim.test.js +0 -79
  62. package/dist/src/commands/file-secret-collector.d.ts +0 -50
  63. package/dist/src/commands/file-secret-collector.d.ts.map +0 -1
  64. package/dist/src/commands/file-secret-collector.js +0 -217
  65. package/dist/src/commands/flavors-a-convention-plugin-creates-are-still-found.test.d.ts +0 -38
  66. package/dist/src/commands/flavors-a-convention-plugin-creates-are-still-found.test.d.ts.map +0 -1
  67. package/dist/src/commands/flavors-a-convention-plugin-creates-are-still-found.test.js +0 -300
  68. package/dist/src/commands/github-workflow.d.ts +0 -5
  69. package/dist/src/commands/github-workflow.d.ts.map +0 -1
  70. package/dist/src/commands/github-workflow.js +0 -45
  71. package/dist/src/commands/index.d.ts +0 -33
  72. package/dist/src/commands/index.d.ts.map +0 -1
  73. package/dist/src/commands/index.js +0 -33
  74. package/dist/src/commands/init.d.ts +0 -20
  75. package/dist/src/commands/init.d.ts.map +0 -1
  76. package/dist/src/commands/init.js +0 -264
  77. package/dist/src/commands/ios-scanner.d.ts +0 -104
  78. package/dist/src/commands/ios-scanner.d.ts.map +0 -1
  79. package/dist/src/commands/ios-scanner.js +0 -492
  80. package/dist/src/commands/ios-scheme-ranking.test.d.ts +0 -2
  81. package/dist/src/commands/ios-scheme-ranking.test.d.ts.map +0 -1
  82. package/dist/src/commands/ios-scheme-ranking.test.js +0 -264
  83. package/dist/src/commands/local-properties-reaches-every-workflow.test.d.ts +0 -30
  84. package/dist/src/commands/local-properties-reaches-every-workflow.test.d.ts.map +0 -1
  85. package/dist/src/commands/local-properties-reaches-every-workflow.test.js +0 -146
  86. package/dist/src/commands/reset.d.ts +0 -7
  87. package/dist/src/commands/reset.d.ts.map +0 -1
  88. package/dist/src/commands/reset.js +0 -81
  89. package/dist/src/commands/run.d.ts +0 -22
  90. package/dist/src/commands/run.d.ts.map +0 -1
  91. package/dist/src/commands/run.js +0 -141
  92. package/dist/src/commands/secrets-sync-workflow.d.ts +0 -15
  93. package/dist/src/commands/secrets-sync-workflow.d.ts.map +0 -1
  94. package/dist/src/commands/secrets-sync-workflow.js +0 -255
  95. package/dist/src/commands/secrets-upload.d.ts +0 -21
  96. package/dist/src/commands/secrets-upload.d.ts.map +0 -1
  97. package/dist/src/commands/secrets-upload.js +0 -177
  98. package/dist/src/commands/secrets-upload.test.d.ts +0 -5
  99. package/dist/src/commands/secrets-upload.test.d.ts.map +0 -1
  100. package/dist/src/commands/secrets-upload.test.js +0 -60
  101. package/dist/src/commands/validate.d.ts +0 -10
  102. package/dist/src/commands/validate.d.ts.map +0 -1
  103. package/dist/src/commands/validate.js +0 -46
  104. package/dist/src/config.d.ts +0 -3
  105. package/dist/src/config.d.ts.map +0 -1
  106. package/dist/src/config.js +0 -47
  107. package/dist/src/envman/cli.d.ts +0 -21
  108. package/dist/src/envman/cli.d.ts.map +0 -1
  109. package/dist/src/envman/cli.js +0 -240
  110. package/dist/src/envman/envman.d.ts +0 -83
  111. package/dist/src/envman/envman.d.ts.map +0 -1
  112. package/dist/src/envman/envman.js +0 -361
  113. package/dist/src/envman/envman.test.d.ts +0 -5
  114. package/dist/src/envman/envman.test.d.ts.map +0 -1
  115. package/dist/src/envman/envman.test.js +0 -236
  116. package/dist/src/envman/envstore-round-trip.test.d.ts +0 -27
  117. package/dist/src/envman/envstore-round-trip.test.d.ts.map +0 -1
  118. package/dist/src/envman/envstore-round-trip.test.js +0 -130
  119. package/dist/src/envman/index.d.ts +0 -23
  120. package/dist/src/envman/index.d.ts.map +0 -1
  121. package/dist/src/envman/index.js +0 -23
  122. package/dist/src/envman/shim.d.ts +0 -16
  123. package/dist/src/envman/shim.d.ts.map +0 -1
  124. package/dist/src/envman/shim.js +0 -66
  125. package/dist/src/envman/types.d.ts +0 -55
  126. package/dist/src/envman/types.d.ts.map +0 -1
  127. package/dist/src/envman/types.js +0 -12
  128. package/dist/src/lib.d.ts +0 -33
  129. package/dist/src/lib.d.ts.map +0 -1
  130. package/dist/src/lib.js +0 -37
  131. package/dist/src/pipeline.d.ts +0 -3
  132. package/dist/src/pipeline.d.ts.map +0 -1
  133. package/dist/src/pipeline.js +0 -57
  134. package/dist/src/runner-node-step.test.d.ts +0 -12
  135. package/dist/src/runner-node-step.test.d.ts.map +0 -1
  136. package/dist/src/runner-node-step.test.js +0 -61
  137. package/dist/src/runner.d.ts +0 -31
  138. package/dist/src/runner.d.ts.map +0 -1
  139. package/dist/src/runner.js +0 -240
  140. package/dist/src/shared/detect-project.d.ts +0 -57
  141. package/dist/src/shared/detect-project.d.ts.map +0 -1
  142. package/dist/src/shared/detect-project.js +0 -219
  143. package/dist/src/shared/detect-project.test.d.ts +0 -2
  144. package/dist/src/shared/detect-project.test.d.ts.map +0 -1
  145. package/dist/src/shared/detect-project.test.js +0 -161
  146. package/dist/src/shared/git.d.ts +0 -25
  147. package/dist/src/shared/git.d.ts.map +0 -1
  148. package/dist/src/shared/git.js +0 -53
  149. package/dist/src/shared/git.test.d.ts +0 -9
  150. package/dist/src/shared/git.test.d.ts.map +0 -1
  151. package/dist/src/shared/git.test.js +0 -66
  152. package/dist/src/shared/gitignore.d.ts +0 -6
  153. package/dist/src/shared/gitignore.d.ts.map +0 -1
  154. package/dist/src/shared/gitignore.js +0 -26
  155. package/dist/src/shared/gradle-settings.d.ts +0 -49
  156. package/dist/src/shared/gradle-settings.d.ts.map +0 -1
  157. package/dist/src/shared/gradle-settings.js +0 -138
  158. package/dist/src/shared/gradle-settings.test.d.ts +0 -2
  159. package/dist/src/shared/gradle-settings.test.d.ts.map +0 -1
  160. package/dist/src/shared/gradle-settings.test.js +0 -65
  161. package/dist/src/shared/prompts.d.ts +0 -30
  162. package/dist/src/shared/prompts.d.ts.map +0 -1
  163. package/dist/src/shared/prompts.js +0 -121
  164. package/dist/src/shared/xcode-container.test.d.ts +0 -2
  165. package/dist/src/shared/xcode-container.test.d.ts.map +0 -1
  166. package/dist/src/shared/xcode-container.test.js +0 -123
  167. package/dist/src/step-marker.d.ts +0 -12
  168. package/dist/src/step-marker.d.ts.map +0 -1
  169. package/dist/src/step-marker.js +0 -29
  170. package/dist/src/step-marker.test.d.ts +0 -11
  171. package/dist/src/step-marker.test.d.ts.map +0 -1
  172. package/dist/src/step-marker.test.js +0 -45
  173. package/dist/src/types.d.ts +0 -58
  174. package/dist/src/types.d.ts.map +0 -1
  175. package/dist/src/types.js +0 -2
  176. package/dist/src/yaml/a-cache-path-must-not-swallow-a-credential.test.d.ts +0 -28
  177. package/dist/src/yaml/a-cache-path-must-not-swallow-a-credential.test.d.ts.map +0 -1
  178. package/dist/src/yaml/a-cache-path-must-not-swallow-a-credential.test.js +0 -223
  179. package/dist/src/yaml/a-declared-secret-reaches-the-file-step.test.d.ts +0 -20
  180. package/dist/src/yaml/a-declared-secret-reaches-the-file-step.test.d.ts.map +0 -1
  181. package/dist/src/yaml/a-declared-secret-reaches-the-file-step.test.js +0 -201
  182. package/dist/src/yaml/a-declared-slot-may-name-the-workflow-it-belongs-to.test.d.ts +0 -37
  183. package/dist/src/yaml/a-declared-slot-may-name-the-workflow-it-belongs-to.test.d.ts.map +0 -1
  184. package/dist/src/yaml/a-declared-slot-may-name-the-workflow-it-belongs-to.test.js +0 -255
  185. package/dist/src/yaml/a-missing-credential-is-loud.test.d.ts +0 -32
  186. package/dist/src/yaml/a-missing-credential-is-loud.test.d.ts.map +0 -1
  187. package/dist/src/yaml/a-missing-credential-is-loud.test.js +0 -301
  188. package/dist/src/yaml/a-runtime-requirement-names-a-real-provider.test.d.ts +0 -18
  189. package/dist/src/yaml/a-runtime-requirement-names-a-real-provider.test.d.ts.map +0 -1
  190. package/dist/src/yaml/a-runtime-requirement-names-a-real-provider.test.js +0 -66
  191. package/dist/src/yaml/a-scoped-slot-must-name-a-workflow-the-pipeline-has.test.d.ts +0 -34
  192. package/dist/src/yaml/a-scoped-slot-must-name-a-workflow-the-pipeline-has.test.d.ts.map +0 -1
  193. package/dist/src/yaml/a-scoped-slot-must-name-a-workflow-the-pipeline-has.test.js +0 -218
  194. package/dist/src/yaml/a-value-this-instance-stored-is-a-value-it-has.test.d.ts +0 -27
  195. package/dist/src/yaml/a-value-this-instance-stored-is-a-value-it-has.test.d.ts.map +0 -1
  196. package/dist/src/yaml/a-value-this-instance-stored-is-a-value-it-has.test.js +0 -126
  197. package/dist/src/yaml/bitrise-compat.d.ts +0 -65
  198. package/dist/src/yaml/bitrise-compat.d.ts.map +0 -1
  199. package/dist/src/yaml/bitrise-compat.js +0 -206
  200. package/dist/src/yaml/bitrise-compat.test.d.ts +0 -5
  201. package/dist/src/yaml/bitrise-compat.test.d.ts.map +0 -1
  202. package/dist/src/yaml/bitrise-compat.test.js +0 -347
  203. package/dist/src/yaml/cache-key-missing-file.test.d.ts +0 -12
  204. package/dist/src/yaml/cache-key-missing-file.test.d.ts.map +0 -1
  205. package/dist/src/yaml/cache-key-missing-file.test.js +0 -116
  206. package/dist/src/yaml/converter.d.ts +0 -103
  207. package/dist/src/yaml/converter.d.ts.map +0 -1
  208. package/dist/src/yaml/converter.js +0 -420
  209. package/dist/src/yaml/converter.test.d.ts +0 -5
  210. package/dist/src/yaml/converter.test.d.ts.map +0 -1
  211. package/dist/src/yaml/converter.test.js +0 -548
  212. package/dist/src/yaml/e2e.test.d.ts +0 -6
  213. package/dist/src/yaml/e2e.test.d.ts.map +0 -1
  214. package/dist/src/yaml/e2e.test.js +0 -446
  215. package/dist/src/yaml/env-resolver.d.ts +0 -218
  216. package/dist/src/yaml/env-resolver.d.ts.map +0 -1
  217. package/dist/src/yaml/env-resolver.js +0 -591
  218. package/dist/src/yaml/env-resolver.test.d.ts +0 -5
  219. package/dist/src/yaml/env-resolver.test.d.ts.map +0 -1
  220. package/dist/src/yaml/env-resolver.test.js +0 -502
  221. package/dist/src/yaml/every-build-log-witnesses-the-commit-on-disk.test.d.ts +0 -16
  222. package/dist/src/yaml/every-build-log-witnesses-the-commit-on-disk.test.d.ts.map +0 -1
  223. package/dist/src/yaml/every-build-log-witnesses-the-commit-on-disk.test.js +0 -126
  224. package/dist/src/yaml/fidelity-input-digest.d.ts +0 -37
  225. package/dist/src/yaml/fidelity-input-digest.d.ts.map +0 -1
  226. package/dist/src/yaml/fidelity-input-digest.js +0 -208
  227. package/dist/src/yaml/fidelity-input-digest.test.d.ts +0 -2
  228. package/dist/src/yaml/fidelity-input-digest.test.d.ts.map +0 -1
  229. package/dist/src/yaml/fidelity-input-digest.test.js +0 -167
  230. package/dist/src/yaml/fidelity-manifest.d.ts +0 -126
  231. package/dist/src/yaml/fidelity-manifest.d.ts.map +0 -1
  232. package/dist/src/yaml/fidelity-manifest.js +0 -134
  233. package/dist/src/yaml/fidelity-manifest.test.d.ts +0 -12
  234. package/dist/src/yaml/fidelity-manifest.test.d.ts.map +0 -1
  235. package/dist/src/yaml/fidelity-manifest.test.js +0 -251
  236. package/dist/src/yaml/interactive-prompts.d.ts +0 -71
  237. package/dist/src/yaml/interactive-prompts.d.ts.map +0 -1
  238. package/dist/src/yaml/interactive-prompts.js +0 -260
  239. package/dist/src/yaml/meta-helpers.d.ts +0 -28
  240. package/dist/src/yaml/meta-helpers.d.ts.map +0 -1
  241. package/dist/src/yaml/meta-helpers.js +0 -46
  242. package/dist/src/yaml/missing-env-handler.d.ts +0 -45
  243. package/dist/src/yaml/missing-env-handler.d.ts.map +0 -1
  244. package/dist/src/yaml/missing-env-handler.js +0 -64
  245. package/dist/src/yaml/parser.d.ts +0 -33
  246. package/dist/src/yaml/parser.d.ts.map +0 -1
  247. package/dist/src/yaml/parser.js +0 -148
  248. package/dist/src/yaml/parser.test.d.ts +0 -5
  249. package/dist/src/yaml/parser.test.d.ts.map +0 -1
  250. package/dist/src/yaml/parser.test.js +0 -83
  251. package/dist/src/yaml/pipeline-with-secrets.d.ts +0 -25
  252. package/dist/src/yaml/pipeline-with-secrets.d.ts.map +0 -1
  253. package/dist/src/yaml/pipeline-with-secrets.js +0 -76
  254. package/dist/src/yaml/platform-detector.d.ts +0 -83
  255. package/dist/src/yaml/platform-detector.d.ts.map +0 -1
  256. package/dist/src/yaml/platform-detector.js +0 -189
  257. package/dist/src/yaml/platform-detector.test.d.ts +0 -5
  258. package/dist/src/yaml/platform-detector.test.d.ts.map +0 -1
  259. package/dist/src/yaml/platform-detector.test.js +0 -525
  260. package/dist/src/yaml/preflight-validation.d.ts +0 -29
  261. package/dist/src/yaml/preflight-validation.d.ts.map +0 -1
  262. package/dist/src/yaml/preflight-validation.js +0 -21
  263. package/dist/src/yaml/secrets-manager.d.ts +0 -87
  264. package/dist/src/yaml/secrets-manager.d.ts.map +0 -1
  265. package/dist/src/yaml/secrets-manager.js +0 -230
  266. package/dist/src/yaml/shell-assignments.d.ts +0 -40
  267. package/dist/src/yaml/shell-assignments.d.ts.map +0 -1
  268. package/dist/src/yaml/shell-assignments.js +0 -77
  269. package/dist/src/yaml/step-validator-check-failure.test.d.ts +0 -24
  270. package/dist/src/yaml/step-validator-check-failure.test.d.ts.map +0 -1
  271. package/dist/src/yaml/step-validator-check-failure.test.js +0 -130
  272. package/dist/src/yaml/step-validator-self-assigned.test.d.ts +0 -23
  273. package/dist/src/yaml/step-validator-self-assigned.test.d.ts.map +0 -1
  274. package/dist/src/yaml/step-validator-self-assigned.test.js +0 -191
  275. package/dist/src/yaml/step-validator.d.ts +0 -67
  276. package/dist/src/yaml/step-validator.d.ts.map +0 -1
  277. package/dist/src/yaml/step-validator.js +0 -466
  278. package/dist/src/yaml/step-validator.test.d.ts +0 -18
  279. package/dist/src/yaml/step-validator.test.d.ts.map +0 -1
  280. package/dist/src/yaml/step-validator.test.js +0 -140
  281. package/dist/src/yaml/steps/a-missing-pinned-jdk-yields-for-every-gradle-run.test.d.ts +0 -2
  282. package/dist/src/yaml/steps/a-missing-pinned-jdk-yields-for-every-gradle-run.test.d.ts.map +0 -1
  283. package/dist/src/yaml/steps/a-missing-pinned-jdk-yields-for-every-gradle-run.test.js +0 -96
  284. package/dist/src/yaml/steps/android-sign.d.ts +0 -35
  285. package/dist/src/yaml/steps/android-sign.d.ts.map +0 -1
  286. package/dist/src/yaml/steps/android-sign.js +0 -147
  287. package/dist/src/yaml/steps/android-variant-resolution.test.d.ts +0 -2
  288. package/dist/src/yaml/steps/android-variant-resolution.test.d.ts.map +0 -1
  289. package/dist/src/yaml/steps/android-variant-resolution.test.js +0 -260
  290. package/dist/src/yaml/steps/android-version.d.ts +0 -26
  291. package/dist/src/yaml/steps/android-version.d.ts.map +0 -1
  292. package/dist/src/yaml/steps/android-version.js +0 -128
  293. package/dist/src/yaml/steps/android-version.test.d.ts +0 -5
  294. package/dist/src/yaml/steps/android-version.test.d.ts.map +0 -1
  295. package/dist/src/yaml/steps/android-version.test.js +0 -196
  296. package/dist/src/yaml/steps/android.d.ts +0 -156
  297. package/dist/src/yaml/steps/android.d.ts.map +0 -1
  298. package/dist/src/yaml/steps/android.js +0 -1100
  299. package/dist/src/yaml/steps/app-store-deploy.d.ts +0 -48
  300. package/dist/src/yaml/steps/app-store-deploy.d.ts.map +0 -1
  301. package/dist/src/yaml/steps/app-store-deploy.js +0 -167
  302. package/dist/src/yaml/steps/base.d.ts +0 -263
  303. package/dist/src/yaml/steps/base.d.ts.map +0 -1
  304. package/dist/src/yaml/steps/base.js +0 -380
  305. package/dist/src/yaml/steps/bitrise-android-tools.d.ts +0 -26
  306. package/dist/src/yaml/steps/bitrise-android-tools.d.ts.map +0 -1
  307. package/dist/src/yaml/steps/bitrise-android-tools.js +0 -200
  308. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts +0 -5
  309. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts.map +0 -1
  310. package/dist/src/yaml/steps/bitrise-android-tools.test.js +0 -280
  311. package/dist/src/yaml/steps/bitrise-apk-info.d.ts +0 -22
  312. package/dist/src/yaml/steps/bitrise-apk-info.d.ts.map +0 -1
  313. package/dist/src/yaml/steps/bitrise-apk-info.js +0 -144
  314. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts +0 -5
  315. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts.map +0 -1
  316. package/dist/src/yaml/steps/bitrise-apk-info.test.js +0 -331
  317. package/dist/src/yaml/steps/bitrise-slack.d.ts +0 -49
  318. package/dist/src/yaml/steps/bitrise-slack.d.ts.map +0 -1
  319. package/dist/src/yaml/steps/bitrise-slack.js +0 -280
  320. package/dist/src/yaml/steps/bitrise-slack.test.d.ts +0 -5
  321. package/dist/src/yaml/steps/bitrise-slack.test.d.ts.map +0 -1
  322. package/dist/src/yaml/steps/bitrise-slack.test.js +0 -484
  323. package/dist/src/yaml/steps/bitrise-ssh.d.ts +0 -27
  324. package/dist/src/yaml/steps/bitrise-ssh.d.ts.map +0 -1
  325. package/dist/src/yaml/steps/bitrise-ssh.js +0 -134
  326. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts +0 -5
  327. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts.map +0 -1
  328. package/dist/src/yaml/steps/bitrise-ssh.test.js +0 -205
  329. package/dist/src/yaml/steps/cache-pull-daemon.test.d.ts +0 -27
  330. package/dist/src/yaml/steps/cache-pull-daemon.test.d.ts.map +0 -1
  331. package/dist/src/yaml/steps/cache-pull-daemon.test.js +0 -212
  332. package/dist/src/yaml/steps/cache-pull-restore-roots.test.d.ts +0 -42
  333. package/dist/src/yaml/steps/cache-pull-restore-roots.test.d.ts.map +0 -1
  334. package/dist/src/yaml/steps/cache-pull-restore-roots.test.js +0 -209
  335. package/dist/src/yaml/steps/cache-push-daemon.test.d.ts +0 -27
  336. package/dist/src/yaml/steps/cache-push-daemon.test.d.ts.map +0 -1
  337. package/dist/src/yaml/steps/cache-push-daemon.test.js +0 -171
  338. package/dist/src/yaml/steps/cache.d.ts +0 -59
  339. package/dist/src/yaml/steps/cache.d.ts.map +0 -1
  340. package/dist/src/yaml/steps/cache.js +0 -1027
  341. package/dist/src/yaml/steps/capture-injection.d.ts +0 -30
  342. package/dist/src/yaml/steps/capture-injection.d.ts.map +0 -1
  343. package/dist/src/yaml/steps/capture-injection.js +0 -88
  344. package/dist/src/yaml/steps/capture-injection.test.d.ts +0 -2
  345. package/dist/src/yaml/steps/capture-injection.test.d.ts.map +0 -1
  346. package/dist/src/yaml/steps/capture-injection.test.js +0 -163
  347. package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts +0 -42
  348. package/dist/src/yaml/steps/cocoapods-deployment-floor.d.ts.map +0 -1
  349. package/dist/src/yaml/steps/cocoapods-deployment-floor.js +0 -140
  350. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts +0 -11
  351. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.d.ts.map +0 -1
  352. package/dist/src/yaml/steps/cocoapods-deployment-floor.test.js +0 -176
  353. package/dist/src/yaml/steps/cocoapods-install-emits-valid-bash.test.d.ts +0 -22
  354. package/dist/src/yaml/steps/cocoapods-install-emits-valid-bash.test.d.ts.map +0 -1
  355. package/dist/src/yaml/steps/cocoapods-install-emits-valid-bash.test.js +0 -97
  356. package/dist/src/yaml/steps/cocoapods-locked-bundler.test.d.ts +0 -17
  357. package/dist/src/yaml/steps/cocoapods-locked-bundler.test.d.ts.map +0 -1
  358. package/dist/src/yaml/steps/cocoapods-locked-bundler.test.js +0 -282
  359. package/dist/src/yaml/steps/cocoapods-skip-if-absent.test.d.ts +0 -17
  360. package/dist/src/yaml/steps/cocoapods-skip-if-absent.test.d.ts.map +0 -1
  361. package/dist/src/yaml/steps/cocoapods-skip-if-absent.test.js +0 -132
  362. package/dist/src/yaml/steps/envstore-loader.test.d.ts +0 -15
  363. package/dist/src/yaml/steps/envstore-loader.test.d.ts.map +0 -1
  364. package/dist/src/yaml/steps/envstore-loader.test.js +0 -143
  365. package/dist/src/yaml/steps/fastlane.d.ts +0 -27
  366. package/dist/src/yaml/steps/fastlane.d.ts.map +0 -1
  367. package/dist/src/yaml/steps/fastlane.js +0 -79
  368. package/dist/src/yaml/steps/fidelity-aspect-guard.d.ts +0 -53
  369. package/dist/src/yaml/steps/fidelity-aspect-guard.d.ts.map +0 -1
  370. package/dist/src/yaml/steps/fidelity-aspect-guard.js +0 -72
  371. package/dist/src/yaml/steps/fidelity-aspect-guard.test.d.ts +0 -11
  372. package/dist/src/yaml/steps/fidelity-aspect-guard.test.d.ts.map +0 -1
  373. package/dist/src/yaml/steps/fidelity-aspect-guard.test.js +0 -50
  374. package/dist/src/yaml/steps/fidelity-reference-provenance.d.ts +0 -87
  375. package/dist/src/yaml/steps/fidelity-reference-provenance.d.ts.map +0 -1
  376. package/dist/src/yaml/steps/fidelity-reference-provenance.js +0 -111
  377. package/dist/src/yaml/steps/fidelity-reference-provenance.test.d.ts +0 -22
  378. package/dist/src/yaml/steps/fidelity-reference-provenance.test.d.ts.map +0 -1
  379. package/dist/src/yaml/steps/fidelity-reference-provenance.test.js +0 -118
  380. package/dist/src/yaml/steps/file.d.ts +0 -52
  381. package/dist/src/yaml/steps/file.d.ts.map +0 -1
  382. package/dist/src/yaml/steps/file.js +0 -108
  383. package/dist/src/yaml/steps/flutter.d.ts +0 -63
  384. package/dist/src/yaml/steps/flutter.d.ts.map +0 -1
  385. package/dist/src/yaml/steps/flutter.js +0 -215
  386. package/dist/src/yaml/steps/git-clone-names-the-inputs-it-ignores.test.d.ts +0 -16
  387. package/dist/src/yaml/steps/git-clone-names-the-inputs-it-ignores.test.d.ts.map +0 -1
  388. package/dist/src/yaml/steps/git-clone-names-the-inputs-it-ignores.test.js +0 -127
  389. package/dist/src/yaml/steps/git-clone.d.ts +0 -32
  390. package/dist/src/yaml/steps/git-clone.d.ts.map +0 -1
  391. package/dist/src/yaml/steps/git-clone.js +0 -171
  392. package/dist/src/yaml/steps/git-fetch-retry-exec.test.d.ts +0 -10
  393. package/dist/src/yaml/steps/git-fetch-retry-exec.test.d.ts.map +0 -1
  394. package/dist/src/yaml/steps/git-fetch-retry-exec.test.js +0 -162
  395. package/dist/src/yaml/steps/git-fetch-retry.d.ts +0 -62
  396. package/dist/src/yaml/steps/git-fetch-retry.d.ts.map +0 -1
  397. package/dist/src/yaml/steps/git-fetch-retry.js +0 -155
  398. package/dist/src/yaml/steps/git-fetch-retry.test.d.ts +0 -5
  399. package/dist/src/yaml/steps/git-fetch-retry.test.d.ts.map +0 -1
  400. package/dist/src/yaml/steps/git-fetch-retry.test.js +0 -86
  401. package/dist/src/yaml/steps/google-play-deploy.d.ts +0 -37
  402. package/dist/src/yaml/steps/google-play-deploy.d.ts.map +0 -1
  403. package/dist/src/yaml/steps/google-play-deploy.js +0 -193
  404. package/dist/src/yaml/steps/google-play-deploy.test.d.ts +0 -5
  405. package/dist/src/yaml/steps/google-play-deploy.test.d.ts.map +0 -1
  406. package/dist/src/yaml/steps/google-play-deploy.test.js +0 -310
  407. package/dist/src/yaml/steps/gradle-memory.d.ts +0 -91
  408. package/dist/src/yaml/steps/gradle-memory.d.ts.map +0 -1
  409. package/dist/src/yaml/steps/gradle-memory.js +0 -495
  410. package/dist/src/yaml/steps/gradle-memory.test.d.ts +0 -2
  411. package/dist/src/yaml/steps/gradle-memory.test.d.ts.map +0 -1
  412. package/dist/src/yaml/steps/gradle-memory.test.js +0 -344
  413. package/dist/src/yaml/steps/gradle-sdk-cmake.d.ts +0 -28
  414. package/dist/src/yaml/steps/gradle-sdk-cmake.d.ts.map +0 -1
  415. package/dist/src/yaml/steps/gradle-sdk-cmake.js +0 -107
  416. package/dist/src/yaml/steps/gradle-sdk-cmake.test.d.ts +0 -2
  417. package/dist/src/yaml/steps/gradle-sdk-cmake.test.d.ts.map +0 -1
  418. package/dist/src/yaml/steps/gradle-sdk-cmake.test.js +0 -183
  419. package/dist/src/yaml/steps/index.d.ts +0 -10
  420. package/dist/src/yaml/steps/index.d.ts.map +0 -1
  421. package/dist/src/yaml/steps/index.js +0 -1461
  422. package/dist/src/yaml/steps/ios-deps.d.ts +0 -78
  423. package/dist/src/yaml/steps/ios-deps.d.ts.map +0 -1
  424. package/dist/src/yaml/steps/ios-deps.js +0 -279
  425. package/dist/src/yaml/steps/ios-deps.test.d.ts +0 -5
  426. package/dist/src/yaml/steps/ios-deps.test.d.ts.map +0 -1
  427. package/dist/src/yaml/steps/ios-deps.test.js +0 -90
  428. package/dist/src/yaml/steps/ios-signing.d.ts +0 -31
  429. package/dist/src/yaml/steps/ios-signing.d.ts.map +0 -1
  430. package/dist/src/yaml/steps/ios-signing.js +0 -144
  431. package/dist/src/yaml/steps/ios-version.d.ts +0 -47
  432. package/dist/src/yaml/steps/ios-version.d.ts.map +0 -1
  433. package/dist/src/yaml/steps/ios-version.js +0 -151
  434. package/dist/src/yaml/steps/java-home-version-spec.test.d.ts +0 -10
  435. package/dist/src/yaml/steps/java-home-version-spec.test.d.ts.map +0 -1
  436. package/dist/src/yaml/steps/java-home-version-spec.test.js +0 -58
  437. package/dist/src/yaml/steps/kotlin-metadata-compiles-on-a-daemon.test.d.ts +0 -2
  438. package/dist/src/yaml/steps/kotlin-metadata-compiles-on-a-daemon.test.d.ts.map +0 -1
  439. package/dist/src/yaml/steps/kotlin-metadata-compiles-on-a-daemon.test.js +0 -139
  440. package/dist/src/yaml/steps/linting.d.ts +0 -47
  441. package/dist/src/yaml/steps/linting.d.ts.map +0 -1
  442. package/dist/src/yaml/steps/linting.js +0 -148
  443. package/dist/src/yaml/steps/phase2.test.d.ts +0 -6
  444. package/dist/src/yaml/steps/phase2.test.d.ts.map +0 -1
  445. package/dist/src/yaml/steps/phase2.test.js +0 -197
  446. package/dist/src/yaml/steps/phase3.test.d.ts +0 -5
  447. package/dist/src/yaml/steps/phase3.test.d.ts.map +0 -1
  448. package/dist/src/yaml/steps/phase3.test.js +0 -144
  449. package/dist/src/yaml/steps/phase4.test.d.ts +0 -5
  450. package/dist/src/yaml/steps/phase4.test.d.ts.map +0 -1
  451. package/dist/src/yaml/steps/phase4.test.js +0 -166
  452. package/dist/src/yaml/steps/phase5.test.d.ts +0 -6
  453. package/dist/src/yaml/steps/phase5.test.d.ts.map +0 -1
  454. package/dist/src/yaml/steps/phase5.test.js +0 -263
  455. package/dist/src/yaml/steps/registry.d.ts +0 -88
  456. package/dist/src/yaml/steps/registry.d.ts.map +0 -1
  457. package/dist/src/yaml/steps/registry.js +0 -125
  458. package/dist/src/yaml/steps/registry.test.d.ts +0 -5
  459. package/dist/src/yaml/steps/registry.test.d.ts.map +0 -1
  460. package/dist/src/yaml/steps/registry.test.js +0 -235
  461. package/dist/src/yaml/steps/release.d.ts +0 -50
  462. package/dist/src/yaml/steps/release.d.ts.map +0 -1
  463. package/dist/src/yaml/steps/release.js +0 -154
  464. package/dist/src/yaml/steps/render-post-processor.d.ts +0 -100
  465. package/dist/src/yaml/steps/render-post-processor.d.ts.map +0 -1
  466. package/dist/src/yaml/steps/render-post-processor.js +0 -270
  467. package/dist/src/yaml/steps/render-post-processor.test.d.ts +0 -13
  468. package/dist/src/yaml/steps/render-post-processor.test.d.ts.map +0 -1
  469. package/dist/src/yaml/steps/render-post-processor.test.js +0 -220
  470. package/dist/src/yaml/steps/script.d.ts +0 -23
  471. package/dist/src/yaml/steps/script.d.ts.map +0 -1
  472. package/dist/src/yaml/steps/script.js +0 -63
  473. package/dist/src/yaml/steps/spec-validation.test.d.ts +0 -6
  474. package/dist/src/yaml/steps/spec-validation.test.d.ts.map +0 -1
  475. package/dist/src/yaml/steps/spec-validation.test.js +0 -130
  476. package/dist/src/yaml/steps/steps.test.d.ts +0 -6
  477. package/dist/src/yaml/steps/steps.test.d.ts.map +0 -1
  478. package/dist/src/yaml/steps/steps.test.js +0 -881
  479. package/dist/src/yaml/steps/structural-facts.d.ts +0 -992
  480. package/dist/src/yaml/steps/structural-facts.d.ts.map +0 -1
  481. package/dist/src/yaml/steps/structural-facts.js +0 -3276
  482. package/dist/src/yaml/steps/structural-facts.test.d.ts +0 -12
  483. package/dist/src/yaml/steps/structural-facts.test.d.ts.map +0 -1
  484. package/dist/src/yaml/steps/structural-facts.test.js +0 -3039
  485. package/dist/src/yaml/steps/test-config.d.ts +0 -5
  486. package/dist/src/yaml/steps/test-config.d.ts.map +0 -1
  487. package/dist/src/yaml/steps/test-config.js +0 -25
  488. package/dist/src/yaml/steps/trim-align-corpus.test.d.ts +0 -28
  489. package/dist/src/yaml/steps/trim-align-corpus.test.d.ts.map +0 -1
  490. package/dist/src/yaml/steps/trim-align-corpus.test.js +0 -383
  491. package/dist/src/yaml/steps/trim-align.d.ts +0 -87
  492. package/dist/src/yaml/steps/trim-align.d.ts.map +0 -1
  493. package/dist/src/yaml/steps/trim-align.js +0 -367
  494. package/dist/src/yaml/steps/trim-align.test.d.ts +0 -11
  495. package/dist/src/yaml/steps/trim-align.test.d.ts.map +0 -1
  496. package/dist/src/yaml/steps/trim-align.test.js +0 -261
  497. package/dist/src/yaml/steps/ui-fidelity-preview-android.d.ts +0 -66
  498. package/dist/src/yaml/steps/ui-fidelity-preview-android.d.ts.map +0 -1
  499. package/dist/src/yaml/steps/ui-fidelity-preview-android.js +0 -251
  500. package/dist/src/yaml/steps/ui-fidelity-preview-android.test.d.ts +0 -13
  501. package/dist/src/yaml/steps/ui-fidelity-preview-android.test.d.ts.map +0 -1
  502. package/dist/src/yaml/steps/ui-fidelity-preview-android.test.js +0 -302
  503. package/dist/src/yaml/steps/ui-fidelity-preview.d.ts +0 -134
  504. package/dist/src/yaml/steps/ui-fidelity-preview.d.ts.map +0 -1
  505. package/dist/src/yaml/steps/ui-fidelity-preview.js +0 -173
  506. package/dist/src/yaml/steps/ui-fidelity-preview.test.d.ts +0 -11
  507. package/dist/src/yaml/steps/ui-fidelity-preview.test.d.ts.map +0 -1
  508. package/dist/src/yaml/steps/ui-fidelity-preview.test.js +0 -210
  509. package/dist/src/yaml/steps/ui-fidelity-render-android.d.ts +0 -155
  510. package/dist/src/yaml/steps/ui-fidelity-render-android.d.ts.map +0 -1
  511. package/dist/src/yaml/steps/ui-fidelity-render-android.js +0 -1389
  512. package/dist/src/yaml/steps/ui-fidelity-render-android.test.d.ts +0 -2
  513. package/dist/src/yaml/steps/ui-fidelity-render-android.test.d.ts.map +0 -1
  514. package/dist/src/yaml/steps/ui-fidelity-render-android.test.js +0 -1106
  515. package/dist/src/yaml/steps/ui-fidelity-render.d.ts +0 -230
  516. package/dist/src/yaml/steps/ui-fidelity-render.d.ts.map +0 -1
  517. package/dist/src/yaml/steps/ui-fidelity-render.js +0 -1597
  518. package/dist/src/yaml/steps/ui-fidelity-render.test.d.ts +0 -18
  519. package/dist/src/yaml/steps/ui-fidelity-render.test.d.ts.map +0 -1
  520. package/dist/src/yaml/steps/ui-fidelity-render.test.js +0 -1871
  521. package/dist/src/yaml/steps/xcode-app-product.d.ts +0 -90
  522. package/dist/src/yaml/steps/xcode-app-product.d.ts.map +0 -1
  523. package/dist/src/yaml/steps/xcode-app-product.js +0 -247
  524. package/dist/src/yaml/steps/xcode-app-product.test.d.ts +0 -2
  525. package/dist/src/yaml/steps/xcode-app-product.test.d.ts.map +0 -1
  526. package/dist/src/yaml/steps/xcode-app-product.test.js +0 -202
  527. package/dist/src/yaml/steps/xcode-derived-data.test.d.ts +0 -30
  528. package/dist/src/yaml/steps/xcode-derived-data.test.d.ts.map +0 -1
  529. package/dist/src/yaml/steps/xcode-derived-data.test.js +0 -279
  530. package/dist/src/yaml/steps/xcode-destination.d.ts +0 -47
  531. package/dist/src/yaml/steps/xcode-destination.d.ts.map +0 -1
  532. package/dist/src/yaml/steps/xcode-destination.js +0 -202
  533. package/dist/src/yaml/steps/xcode-destination.test.d.ts +0 -9
  534. package/dist/src/yaml/steps/xcode-destination.test.d.ts.map +0 -1
  535. package/dist/src/yaml/steps/xcode-destination.test.js +0 -227
  536. package/dist/src/yaml/steps/xcode-new.test.d.ts +0 -5
  537. package/dist/src/yaml/steps/xcode-new.test.d.ts.map +0 -1
  538. package/dist/src/yaml/steps/xcode-new.test.js +0 -211
  539. package/dist/src/yaml/steps/xcode-resolve-retry.test.d.ts +0 -9
  540. package/dist/src/yaml/steps/xcode-resolve-retry.test.d.ts.map +0 -1
  541. package/dist/src/yaml/steps/xcode-resolve-retry.test.js +0 -146
  542. package/dist/src/yaml/steps/xcode-simulator-archs.d.ts +0 -53
  543. package/dist/src/yaml/steps/xcode-simulator-archs.d.ts.map +0 -1
  544. package/dist/src/yaml/steps/xcode-simulator-archs.js +0 -98
  545. package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts +0 -21
  546. package/dist/src/yaml/steps/xcode-simulator-archs.test.d.ts.map +0 -1
  547. package/dist/src/yaml/steps/xcode-simulator-archs.test.js +0 -155
  548. package/dist/src/yaml/steps/xcode.d.ts +0 -230
  549. package/dist/src/yaml/steps/xcode.d.ts.map +0 -1
  550. package/dist/src/yaml/steps/xcode.js +0 -1350
  551. package/dist/src/yaml/types.d.ts +0 -76
  552. package/dist/src/yaml/types.d.ts.map +0 -1
  553. package/dist/src/yaml/types.js +0 -5
  554. package/dist/src/yaml/validation-types.d.ts +0 -102
  555. package/dist/src/yaml/validation-types.d.ts.map +0 -1
  556. package/dist/src/yaml/validation-types.js +0 -8
  557. package/dist/src/yaml/yaml-updater.d.ts +0 -24
  558. package/dist/src/yaml/yaml-updater.d.ts.map +0 -1
  559. package/dist/src/yaml/yaml-updater.js +0 -128
@@ -1,1350 +0,0 @@
1
- /**
2
- * Xcode step implementations (xcodebuild, xcode-test)
3
- */
4
- import { existsSync } from 'node:fs';
5
- import { BaseStepExecutor } from './base.js';
6
- import { resolveDestinationInput } from './xcode-destination.js';
7
- import { APP_PRODUCT_RESOLVER_SOURCE } from './xcode-app-product.js';
8
- import { pinsSimulatorArm64, simulatorArchsLines, withRuntimeSimulatorArchs } from './xcode-simulator-archs.js';
9
- import { refusedFetchHelpers, retryOnRefusedFetch } from './git-fetch-retry.js';
10
- /**
11
- * Where derived data goes: outside the source tree, keyed by the output dir.
12
- *
13
- * It used to be "$DERIVED_DATA_PATH", and OUTPUT_DIR is inside the
14
- * checkout — so every resolved SPM package sat in the working tree, where an
15
- * app's own lint or format build phase walks it. vinhnx/Clendar's SwiftLint
16
- * phase failed the build on 145 serious violations, all of them in
17
- * third-party packages under build/app/DerivedData/SourcePackages/checkouts.
18
- * A developer's Xcode keeps derived data under ~/Library, so no repository has
19
- * a reason to exclude that directory, and it should not have to.
20
- *
21
- * CIBUILD_SCRATCH is the runner's per-build local root, which holds the
22
- * checkout rather than sitting inside it; outside a sandbox it falls back to
23
- * TMPDIR. The key is a checksum of the absolute output dir, so two steps that
24
- * name the same output_dir still share derived data (the iOS template relies
25
- * on that to avoid compiling the app twice) and two that name different ones
26
- * stay apart, as they did before.
27
- *
28
- * **Never under /tmp** (nightly-baseline 58). analogcode/Swift-Radio-Pro's
29
- * LNPopupController builds its header search paths by deleting
30
- * `Context.packageDirectory` from the paths FileManager lists, and under /tmp
31
- * the two disagree by `/private`: xcodebuild folds `/private/tmp` back to
32
- * `/tmp` however the path is given, and FileManager does not, so every header
33
- * path came out eight characters short ("troller/…"). Resolving the path did
34
- * not help, for that reason. The guest's scratch root is
35
- * `/tmp/cibuild-work-<id>`, so there derived data goes to the build user's
36
- * real home instead. Measured on runner-mac-01 2026-10-03: the same build
37
- * fails under /tmp and succeeds under the home, in a fresh VM each. Not
38
- * /var/folders (TMPDIR): it built correctly there too. SwiftPM caches a
39
- * manifest's evaluation, relative paths and all, so the first evaluation in a
40
- * VM decides — another reason the root must be right from the first build.
41
- */
42
- function derivedDataPathLines() {
43
- return [
44
- '# Derived data outside the source tree, keyed by the output dir, and never under /tmp',
45
- 'cibuild_dd_root="${CIBUILD_SCRATCH:-${TMPDIR:-/tmp}}"',
46
- 'case "$(cd "$cibuild_dd_root" 2>/dev/null && pwd -P)" in /private/tmp|/private/tmp/*) cibuild_dd_root="${CIBUILD_USER_HOME:-$HOME}/Library/Developer/cibuild" ;; esac',
47
- 'DERIVED_DATA_PATH="$cibuild_dd_root/cibuild-derived-data/$(printf \'%s\' "$OUTPUT_DIR" | cksum | cut -d\' \' -f1)"',
48
- 'mkdir -p "$DERIVED_DATA_PATH"',
49
- '# Its real path: /tmp and TMPDIR are symlinks on macOS, and a package that builds paths by text arithmetic breaks on them',
50
- 'DERIVED_DATA_PATH="$(cd "$DERIVED_DATA_PATH" && pwd -P)"',
51
- 'echo "Derived data: $DERIVED_DATA_PATH"',
52
- ];
53
- }
54
- /**
55
- * Xcodebuild step executor
56
- * Builds iOS/macOS projects using xcodebuild
57
- */
58
- export class XcodeBuildStepExecutor extends BaseStepExecutor {
59
- getValidationRequirements(inputs, _env, _config) {
60
- const requirements = [];
61
- // xcodebuild command must exist
62
- requirements.push(this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required for iOS builds', 'Install Xcode from the App Store, then run: xcode-select --install'));
63
- // Required inputs
64
- requirements.push(this.requireInput('project_path', inputs, 'Path to .xcodeproj or .xcworkspace', 'Provide project_path input in YAML'));
65
- requirements.push(this.requireInput('scheme', inputs, 'Xcode scheme name', 'Provide scheme input in YAML'));
66
- // Project file - runtime check only if it doesn't already exist locally
67
- if (inputs.project_path && !existsSync(inputs.project_path)) {
68
- requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'the checkout'));
69
- }
70
- if (inputs.destination === 'auto') {
71
- requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
72
- }
73
- return requirements;
74
- }
75
- async execute(inputs, env, config) {
76
- const stepName = 'xcodebuild';
77
- // Get project path - required
78
- let projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
79
- // Resolve path identifiers
80
- if (projectPath.startsWith('builds:')) {
81
- projectPath = projectPath.replace('builds:', `${config.paths.buildsDir}/`);
82
- }
83
- // Get scheme - required
84
- const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
85
- // Get configuration - defaults to Release
86
- const configuration = this.getInput(inputs, 'configuration', 'Release');
87
- // Get destination - defaults to generic/platform=iOS.
88
- // `auto` triggers runtime resolution via `xcrun simctl`.
89
- const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS'));
90
- // Get output directory - defaults to build
91
- const outputDir = this.getInput(inputs, 'output_dir', 'build');
92
- // Get clean build flag
93
- const isCleanBuild = this.getInput(inputs, 'is_clean_build', false);
94
- // Get xcconfig content - optional
95
- const xcconfigContent = this.getInput(inputs, 'xcconfig_content', '');
96
- const commands = [];
97
- commands.push('# Xcode Build');
98
- commands.push(`echo "Building project: ${this.escapeBash(projectPath)}"`);
99
- commands.push(`echo "Scheme: ${this.escapeBash(scheme)}"`);
100
- commands.push(`echo "Configuration: ${this.escapeBash(configuration)}"`);
101
- // Create output directory and resolve to absolute path. The absolute path
102
- // is the load-bearing part: a relative one let xcodebuild create a `build`
103
- // directory inside each SPM package checkout in DerivedData, which fails
104
- // with "File exists but is not a directory" on repeated runs. That was
105
- // originally fixed by making CONFIGURATION_BUILD_DIR absolute; it is now
106
- // -derivedDataPath that is absolute instead, which fixes the same thing
107
- // without flattening the product tree.
108
- commands.push('');
109
- commands.push('# Create output directory and resolve to absolute path');
110
- commands.push(`mkdir -p '${this.escapeBash(outputDir)}'`);
111
- commands.push(`OUTPUT_DIR="$(cd '${this.escapeBash(outputDir)}' && pwd)"`);
112
- commands.push(...derivedDataPathLines());
113
- // Create xcconfig file if content provided
114
- if (xcconfigContent && xcconfigContent.trim() !== '') {
115
- commands.push('');
116
- commands.push('# Create custom xcconfig file');
117
- commands.push('XCCONFIG_FILE=".ci-custom.xcconfig"');
118
- commands.push('cat > "$XCCONFIG_FILE" << \'EOF\'');
119
- commands.push(xcconfigContent);
120
- commands.push('EOF');
121
- commands.push('echo "Custom xcconfig created"');
122
- }
123
- // Determine if workspace or project
124
- commands.push('');
125
- commands.push('# Determine project type');
126
- const escapedPath = this.escapeBash(projectPath);
127
- commands.push(`if [[ '${escapedPath}' == *.xcworkspace ]]; then`);
128
- commands.push(' PROJECT_TYPE="-workspace"');
129
- commands.push('else');
130
- commands.push(' PROJECT_TYPE="-project"');
131
- commands.push('fi');
132
- // Resolve the package graph before building, and retry that on a refused
133
- // fetch. Resolution is seconds and the build is minutes, so the retry is
134
- // spent on the cheap half. The two -derivedDataPath arguments move
135
- // together: the build below reads the same derived data and finds the
136
- // graph already resolved. Split them and the retry is spent on work the
137
- // build discards.
138
- commands.push('');
139
- commands.push('# Resolve package dependencies first — see git-fetch-retry');
140
- commands.push(...refusedFetchHelpers());
141
- commands.push(...retryOnRefusedFetch({
142
- label: 'Package resolution',
143
- command: 'xcodebuild -resolvePackageDependencies' +
144
- ` "$PROJECT_TYPE" '${escapedPath}'` +
145
- ` -scheme '${this.escapeBash(scheme)}'` +
146
- ' -derivedDataPath "$DERIVED_DATA_PATH"',
147
- }));
148
- // Build xcodebuild command
149
- commands.push('');
150
- commands.push('# Build xcodebuild command');
151
- let xcodebuildCmd = 'xcodebuild';
152
- // Add clean if requested
153
- if (isCleanBuild) {
154
- xcodebuildCmd += ' clean';
155
- }
156
- xcodebuildCmd += ' build';
157
- xcodebuildCmd += ` "$PROJECT_TYPE" '${escapedPath}'`;
158
- xcodebuildCmd += ` -scheme '${this.escapeBash(scheme)}'`;
159
- xcodebuildCmd += ` -configuration '${this.escapeBash(configuration)}'`;
160
- xcodebuildCmd += ` -destination '${this.escapeBash(destination)}'`;
161
- // A derived data path (see derivedDataPathLines), rather than CONFIGURATION_BUILD_DIR.
162
- // Same reasoning as XcodeBuildForSimulatorStepExecutor below, where the
163
- // full mechanism and the control are written up: the flat directory
164
- // collapses xcodebuild's per-configuration/per-platform product separation
165
- // and any graph with two tasks producing the same output name is refused
166
- // with "Multiple commands produce". It also desynchronises CocoaPods, whose
167
- // PODS_CONFIGURATION_BUILD_DIR follows BUILD_DIR and not this setting.
168
- xcodebuildCmd += ` -derivedDataPath "$DERIVED_DATA_PATH"`;
169
- // Add xcconfig if provided
170
- if (xcconfigContent && xcconfigContent.trim() !== '') {
171
- xcodebuildCmd += ' -xcconfig "$XCCONFIG_FILE"';
172
- }
173
- commands.push(xcodebuildCmd);
174
- // Show build results
175
- commands.push('');
176
- commands.push('# Build completed');
177
- commands.push('echo "Build completed successfully"');
178
- // Products live under the per-platform Products directory now, not flat in
179
- // $OUTPUT_DIR, so point the listing at where they actually are — otherwise
180
- // the log says "artifacts in build/" above an empty directory.
181
- commands.push('echo "Build artifacts in: $DERIVED_DATA_PATH/Build/Products"');
182
- commands.push('ls -lhR "$DERIVED_DATA_PATH/Build/Products" 2>/dev/null || true');
183
- const script = this.createBashScriptFromCommands(commands, stepName);
184
- return this.createScriptStep(script, stepName);
185
- }
186
- }
187
- /**
188
- * Xcode test step executor
189
- * Runs tests for iOS/macOS projects using xcodebuild test
190
- */
191
- export class XcodeTestStepExecutor extends BaseStepExecutor {
192
- getValidationRequirements(inputs, _env, _config) {
193
- const requirements = [];
194
- // xcodebuild command must exist
195
- requirements.push(this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required for iOS tests', 'Install Xcode from the App Store, then run: xcode-select --install'));
196
- // Required inputs
197
- requirements.push(this.requireInput('project_path', inputs, 'Path to .xcodeproj or .xcworkspace', 'Provide project_path input in YAML'));
198
- requirements.push(this.requireInput('scheme', inputs, 'Xcode scheme name', 'Provide scheme input in YAML'));
199
- // Project file - runtime check only if it doesn't already exist locally
200
- if (inputs.project_path && !existsSync(inputs.project_path)) {
201
- requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'the checkout'));
202
- }
203
- if (inputs.destination === 'auto') {
204
- requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
205
- }
206
- return requirements;
207
- }
208
- async execute(inputs, env, config) {
209
- const stepName = 'xcode-test';
210
- // Get project path - required
211
- let projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
212
- // Resolve path identifiers
213
- if (projectPath.startsWith('builds:')) {
214
- projectPath = projectPath.replace('builds:', `${config.paths.buildsDir}/`);
215
- }
216
- // Get scheme - required
217
- const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
218
- // Get destination - defaults to platform=iOS Simulator.
219
- // `auto` triggers runtime resolution via `xcrun simctl`.
220
- const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'platform=iOS Simulator,name=iPhone 14,OS=latest'));
221
- // Get test plan - optional
222
- const testPlan = this.getInput(inputs, 'test_plan', '');
223
- // Get code coverage flag
224
- const isCodeCoverageEnabled = this.getInput(inputs, 'is_code_coverage_enabled', false);
225
- const commands = [];
226
- commands.push('# Xcode Test');
227
- commands.push(`echo "Testing project: ${this.escapeBash(projectPath)}"`);
228
- commands.push(`echo "Scheme: ${this.escapeBash(scheme)}"`);
229
- // Determine if workspace or project
230
- commands.push('');
231
- commands.push('# Determine project type');
232
- const escapedPath = this.escapeBash(projectPath);
233
- commands.push(`if [[ '${escapedPath}' == *.xcworkspace ]]; then`);
234
- commands.push(' PROJECT_TYPE="-workspace"');
235
- commands.push('else');
236
- commands.push(' PROJECT_TYPE="-project"');
237
- commands.push('fi');
238
- // Build xcodebuild test command
239
- commands.push('');
240
- commands.push('# Run tests');
241
- let xcodebuildCmd = 'xcodebuild test';
242
- xcodebuildCmd += ` "$PROJECT_TYPE" '${escapedPath}'`;
243
- xcodebuildCmd += ` -scheme '${this.escapeBash(scheme)}'`;
244
- xcodebuildCmd += ` -destination '${this.escapeBash(destination)}'`;
245
- // Add test plan if specified
246
- if (testPlan && testPlan.trim() !== '') {
247
- xcodebuildCmd += ` -testPlan '${this.escapeBash(testPlan)}'`;
248
- }
249
- // Add code coverage if enabled
250
- if (isCodeCoverageEnabled) {
251
- xcodebuildCmd += ' -enableCodeCoverage YES';
252
- }
253
- commands.push(xcodebuildCmd);
254
- // Show test results
255
- commands.push('');
256
- commands.push('# Tests completed');
257
- commands.push('echo "Tests completed successfully"');
258
- const script = this.createBashScriptFromCommands(commands, stepName);
259
- return this.createScriptStep(script, stepName);
260
- }
261
- }
262
- /**
263
- * xcode-archive step executor
264
- * Archives and exports an iOS app to IPA, mirroring bitrise xcode-archive@5.
265
- */
266
- export class XcodeArchiveStepExecutor extends BaseStepExecutor {
267
- getValidationRequirements(inputs, _env, _config) {
268
- const requirements = [];
269
- requirements.push(this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required for iOS builds', 'Install Xcode from the App Store, then run: xcode-select --install'));
270
- requirements.push(this.requireInput('project_path', inputs, 'Path to .xcodeproj or .xcworkspace', 'Provide project_path input in YAML'));
271
- requirements.push(this.requireInput('scheme', inputs, 'Xcode scheme name', 'Provide scheme input in YAML'));
272
- // Project file - runtime check only if it doesn't already exist locally
273
- if (inputs.project_path && !existsSync(inputs.project_path)) {
274
- requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'the checkout'));
275
- }
276
- return requirements;
277
- }
278
- getOutputs() {
279
- return [
280
- { name: 'CIBUILD_IPA_PATH', type: 'environment', description: 'Path to the exported IPA file' },
281
- { name: 'CIBUILD_XCARCHIVE_PATH', type: 'environment', description: 'Path to the generated .xcarchive' },
282
- { name: 'CIBUILD_DSYM_PATH', type: 'environment', description: 'Path to the zipped dSYM files' },
283
- { name: 'CIBUILD_APP_PATH', type: 'environment', description: 'Path to the .app inside the xcarchive (when code signing is off)' },
284
- ];
285
- }
286
- async execute(inputs, env, config) {
287
- const stepName = 'xcode-archive';
288
- let projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
289
- if (projectPath.startsWith('builds:')) {
290
- projectPath = projectPath.replace('builds:', `${config.paths.buildsDir}/`);
291
- }
292
- const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
293
- const configuration = this.getInput(inputs, 'configuration', 'Release');
294
- const platform = this.getInput(inputs, 'platform', 'iOS');
295
- const distributionMethod = this.getInput(inputs, 'distribution_method', 'development');
296
- const performClean = this.getInput(inputs, 'perform_clean_action', 'no');
297
- const compileBitcode = this.getInput(inputs, 'compile_bitcode', 'yes');
298
- const uploadBitcode = this.getInput(inputs, 'upload_bitcode', 'yes');
299
- const automaticCodeSigning = this.getInput(inputs, 'automatic_code_signing', 'off');
300
- const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
301
- const xcconfigContent = this.getInput(inputs, 'xcconfig_content', 'COMPILER_INDEX_STORE_ENABLE = NO');
302
- const exportOptionsPlistContent = this.getInput(inputs, 'export_options_plist_content', '');
303
- const signingStyleInput = this.getInput(inputs, 'signing_style', 'automatic');
304
- const provisioningProfilesInput = this.getInput(inputs, 'provisioning_profiles', '');
305
- const outputDir = this.getInput(inputs, 'output_dir', 'build/ipa');
306
- const artifactName = this.getInput(inputs, 'artifact_name', '');
307
- const escapedPath = this.escapeBash(projectPath);
308
- const escapedScheme = this.escapeBash(scheme);
309
- const escapedConfig = this.escapeBash(configuration);
310
- const commands = [];
311
- commands.push('# xcode-archive — archive and export iOS app to IPA');
312
- commands.push(`echo "Project: ${escapedPath}"`);
313
- commands.push(`echo "Scheme: ${escapedScheme}"`);
314
- commands.push(`echo "Configuration: ${escapedConfig}"`);
315
- commands.push(`echo "Distribution method: ${this.escapeBash(distributionMethod)}"`);
316
- commands.push('');
317
- // Determine project type
318
- commands.push('# Determine project type (-workspace vs -project)');
319
- commands.push(`if [[ '${escapedPath}' == *.xcworkspace ]]; then`);
320
- commands.push(' PROJECT_TYPE="-workspace"');
321
- commands.push('else');
322
- commands.push(' PROJECT_TYPE="-project"');
323
- commands.push('fi');
324
- commands.push('');
325
- // Derive artifact name
326
- if (artifactName) {
327
- commands.push(`ARTIFACT_NAME="${this.escapeBash(artifactName)}"`);
328
- }
329
- else {
330
- commands.push(`ARTIFACT_NAME="${escapedScheme}"`);
331
- }
332
- // Paths
333
- commands.push(`OUTPUT_DIR="${this.escapeBash(outputDir)}"`);
334
- commands.push('ARCHIVE_PATH="$OUTPUT_DIR/archive/${ARTIFACT_NAME}.xcarchive"');
335
- commands.push('mkdir -p "$(dirname "$ARCHIVE_PATH")"');
336
- commands.push('mkdir -p "$OUTPUT_DIR"');
337
- commands.push('');
338
- // Write xcconfig override
339
- commands.push('# Write xcconfig overrides');
340
- commands.push('XCCONFIG_PATH="$(mktemp -t cibuild-xcconfig).xcconfig"');
341
- // When automatic_code_signing is off (default), disable code signing so
342
- // archives succeed on CI without a development team / provisioning profile.
343
- let effectiveXcconfig = xcconfigContent.trim() || 'COMPILER_INDEX_STORE_ENABLE = NO';
344
- if (automaticCodeSigning === 'off') {
345
- effectiveXcconfig += '\nCODE_SIGNING_ALLOWED = NO';
346
- effectiveXcconfig += '\nCODE_SIGN_IDENTITY = -';
347
- }
348
- commands.push(`cat > "$XCCONFIG_PATH" << 'XCCONFIG_EOF'`);
349
- commands.push(effectiveXcconfig);
350
- commands.push('XCCONFIG_EOF');
351
- commands.push('');
352
- // Detect Apple API key for cloud-managed signing (xcodebuild
353
- // -allowProvisioningUpdates). When APPLE_API_KEY_ID/ISSUER_ID/KEY_PATH
354
- // are resolved by the env-resolver (from .cibuild-secrets.json or
355
- // CIBUILD_SW__* env vars), embed the .p8 into the generated script via
356
- // heredoc and bake the IDs as literals. Reading from $APPLE_API_KEY_ID
357
- // at script runtime would not work because cibuild's runner only
358
- // forwards process.env to spawned scripts, and EnvResolver-decoded
359
- // secrets live in its in-memory map, not process.env.
360
- let xcodeAuthFlags = '';
361
- if (automaticCodeSigning !== 'off') {
362
- const apiKeyId = (env['APPLE_API_KEY_ID'] || '').trim();
363
- const apiIssuerId = (env['APPLE_API_ISSUER_ID'] || '').trim();
364
- const apiKeySecret = env['APPLE_API_KEY_PATH'] || '';
365
- // Secret may be raw PEM (`-----BEGIN PRIVATE KEY-----…`) or base64-encoded.
366
- let p8Pem = '';
367
- if (apiKeySecret) {
368
- if (apiKeySecret.trimStart().startsWith('-----BEGIN')) {
369
- p8Pem = apiKeySecret;
370
- }
371
- else {
372
- try {
373
- p8Pem = Buffer.from(apiKeySecret, 'base64').toString('utf-8');
374
- }
375
- catch {
376
- p8Pem = '';
377
- }
378
- }
379
- }
380
- const p8LooksValid = p8Pem.includes('-----BEGIN') && p8Pem.includes('PRIVATE KEY');
381
- if (apiKeyId && apiIssuerId && p8LooksValid) {
382
- commands.push('# Apple API key resolved — embedding for cloud-managed signing');
383
- // BSD/macOS mktemp requires X's at the end of the template; any chars
384
- // after them are literal and not substituted. Don't add a .p8 suffix.
385
- commands.push('API_KEY_TEMP_FILE="$(mktemp /tmp/cibuild-api-key.XXXXXX)"');
386
- commands.push(`trap 'rm -f "$API_KEY_TEMP_FILE"' EXIT`);
387
- // Quoted heredoc so the PEM body isn't subject to shell expansion.
388
- commands.push(`cat > "$API_KEY_TEMP_FILE" << 'CIBUILD_API_KEY_EOF'`);
389
- commands.push(p8Pem.replace(/\r\n/g, '\n').replace(/\n+$/, ''));
390
- commands.push('CIBUILD_API_KEY_EOF');
391
- commands.push('echo "✓ Cloud-managed signing enabled (API key: '
392
- + this.escapeBash(apiKeyId) + ')"');
393
- commands.push('');
394
- // Build a bash-syntax fragment that gets concatenated directly into
395
- // the archive/export command lines. Single quotes here are real shell
396
- // quotes (consumed by bash) — unlike the previous approach that put
397
- // them inside a doubly-quoted variable assignment, where they would
398
- // become literal characters in the value.
399
- xcodeAuthFlags =
400
- ` -allowProvisioningUpdates` +
401
- ` -authenticationKeyPath "$API_KEY_TEMP_FILE"` +
402
- ` -authenticationKeyID '${this.escapeBash(apiKeyId)}'` +
403
- ` -authenticationKeyIssuerID '${this.escapeBash(apiIssuerId)}'`;
404
- }
405
- }
406
- // Build xcodebuild archive command
407
- commands.push('# Run xcodebuild archive');
408
- let archiveCmd = 'xcodebuild';
409
- if (performClean === 'yes')
410
- archiveCmd += ' clean';
411
- archiveCmd += ' archive';
412
- archiveCmd += ` "$PROJECT_TYPE" '${escapedPath}'`;
413
- archiveCmd += ` -scheme '${escapedScheme}'`;
414
- archiveCmd += ` -configuration '${escapedConfig}'`;
415
- archiveCmd += ` -destination 'generic/platform=${this.escapeBash(platform)}'`;
416
- archiveCmd += ' -archivePath "$ARCHIVE_PATH"';
417
- archiveCmd += ' -xcconfig "$XCCONFIG_PATH"';
418
- // When code signing is off, also pass settings as command-line build
419
- // settings so they take highest priority and override any target-level
420
- // signing configuration in the Xcode project.
421
- if (automaticCodeSigning === 'off') {
422
- archiveCmd += ' CODE_SIGNING_ALLOWED=NO CODE_SIGN_IDENTITY=- CODE_SIGNING_REQUIRED=NO';
423
- }
424
- else {
425
- archiveCmd += xcodeAuthFlags;
426
- // Don't override CODE_SIGN_IDENTITY here. Xcode 26.3+ rejects an explicit
427
- // identity when the project is configured for automatic signing
428
- // ("conflicting provisioning settings" at GatherProvisioningInputs).
429
- // Archive with the project's automatic identity (Development); the
430
- // exportArchive step re-signs with Distribution via exportOptionsPlist
431
- // (method=app-store + signingStyle=automatic), mirroring Xcode IDE's
432
- // Archive → Distribute flow. DEVELOPMENT_TEAM is still injected so SPM
433
- // frameworks without an explicit team in Package.swift can sign.
434
- const teamId = (env['APPLE_TEAM_ID'] || '').trim();
435
- if (teamId) {
436
- archiveCmd += ` DEVELOPMENT_TEAM='${this.escapeBash(teamId)}'`;
437
- }
438
- }
439
- if (xcodebuildOptions) {
440
- archiveCmd += ` ${xcodebuildOptions}`;
441
- }
442
- commands.push(archiveCmd);
443
- commands.push('');
444
- commands.push('echo "✓ Archive created: $ARCHIVE_PATH"');
445
- commands.push('');
446
- // Write output env var helper (used in both signing and non-signing paths)
447
- commands.push('# Export output environment variables');
448
- commands.push('ENVSTORE_FILE="${ENVMAN_ENVSTORE_PATH:-.ci/.envstore.json}"');
449
- commands.push('export_env() {');
450
- commands.push(' local key="$1" val="$2"');
451
- commands.push(' if [ -f "$ENVSTORE_FILE" ]; then');
452
- commands.push(' node -e "');
453
- commands.push(' const fs=require(\'fs\');');
454
- commands.push(' const s=JSON.parse(fs.readFileSync(process.argv[1],\'utf-8\'));');
455
- commands.push(' s.envs=s.envs||[];');
456
- commands.push(' s.envs=s.envs.filter(e=>e.key!==process.argv[2]);');
457
- commands.push(' s.envs.push({key:process.argv[2],value:process.argv[3]});');
458
- commands.push(' fs.writeFileSync(process.argv[1],JSON.stringify(s));');
459
- commands.push(' " "$ENVSTORE_FILE" "$key" "$val" 2>/dev/null || true');
460
- commands.push(' fi');
461
- commands.push(' export "$key=$val"');
462
- commands.push(' echo " $key=$val"');
463
- commands.push('}');
464
- commands.push('');
465
- if (automaticCodeSigning === 'off') {
466
- // Signing is disabled — skip IPA export (unsigned archives cannot be exported).
467
- // Output the xcarchive path and the .app inside it instead.
468
- commands.push('# Code signing disabled — export xcarchive path only');
469
- commands.push('export_env CIBUILD_XCARCHIVE_PATH "$(pwd)/$ARCHIVE_PATH"');
470
- commands.push('');
471
- commands.push('# Locate .app inside the xcarchive for downstream use');
472
- commands.push('APP_PATH=$(find "$ARCHIVE_PATH/Products" -name "*.app" -maxdepth 3 2>/dev/null | head -1 || true)');
473
- commands.push('[ -n "$APP_PATH" ] && export_env CIBUILD_APP_PATH "$(pwd)/$APP_PATH" || true');
474
- commands.push('');
475
- commands.push('echo "✓ xcode-archive complete (unsigned — code signing disabled)"');
476
- }
477
- else {
478
- // Signing enabled — generate ExportOptions.plist and export to IPA
479
- commands.push('# Generate ExportOptions.plist');
480
- commands.push('EXPORT_PLIST="$(mktemp -t ExportOptions).plist"');
481
- if (exportOptionsPlistContent.trim()) {
482
- commands.push(`cat > "$EXPORT_PLIST" << 'PLIST_EOF'`);
483
- commands.push(exportOptionsPlistContent);
484
- commands.push('PLIST_EOF');
485
- }
486
- else {
487
- // Map deprecated "development" method name to "debugging" (Apple renamed it in Xcode 15)
488
- const exportMethod = distributionMethod === 'development' ? 'debugging' : distributionMethod;
489
- const compileBitcodeVal = compileBitcode === 'yes' ? 'true' : 'false';
490
- const uploadBitcodeVal = uploadBitcode === 'yes' ? 'true' : 'false';
491
- const signingStyle = signingStyleInput === 'manual' ? 'manual' : 'automatic';
492
- // Parse provisioning_profiles input: each non-empty line is `bundleId=ProfileName`.
493
- // Lines starting with # are treated as comments. Whitespace is trimmed.
494
- const profileEntries = [];
495
- if (signingStyle === 'manual' && provisioningProfilesInput.trim()) {
496
- for (const rawLine of provisioningProfilesInput.split('\n')) {
497
- const line = rawLine.trim();
498
- if (!line || line.startsWith('#'))
499
- continue;
500
- const eq = line.indexOf('=');
501
- if (eq === -1)
502
- continue;
503
- const bundleId = line.slice(0, eq).trim();
504
- const profile = line.slice(eq + 1).trim();
505
- if (bundleId && profile)
506
- profileEntries.push({ bundleId, profile });
507
- }
508
- }
509
- if (signingStyle === 'manual') {
510
- if (profileEntries.length === 0) {
511
- throw new Error(`xcode-archive: signing_style=manual requires provisioning_profiles input ` +
512
- `(newline-separated 'bundleId=ProfileName' pairs).`);
513
- }
514
- // Manual export needs APPLE_TEAM_ID at runtime — fail fast with a clear message.
515
- commands.push('# signing_style=manual — verify APPLE_TEAM_ID is available');
516
- commands.push('if [ -z "${APPLE_TEAM_ID:-}" ]; then');
517
- commands.push(' echo "❌ Error: signing_style=manual requires APPLE_TEAM_ID env var." >&2');
518
- commands.push(' echo " Set via: ci secrets add APPLE_TEAM_ID -w <workflow>" >&2');
519
- commands.push(' exit 1');
520
- commands.push('fi');
521
- commands.push('');
522
- }
523
- // Manual mode references ${APPLE_TEAM_ID}, which requires an *unquoted* heredoc
524
- // delimiter so bash performs variable expansion. Automatic mode uses single-quoted
525
- // delimiter so the plist content is preserved literally.
526
- const heredocOpen = signingStyle === 'manual'
527
- ? `cat > "$EXPORT_PLIST" << PLIST_EOF`
528
- : `cat > "$EXPORT_PLIST" << 'PLIST_EOF'`;
529
- commands.push(heredocOpen);
530
- commands.push('<?xml version="1.0" encoding="UTF-8"?>');
531
- commands.push('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">');
532
- commands.push('<plist version="1.0">');
533
- commands.push('<dict>');
534
- commands.push(' <key>method</key>');
535
- commands.push(` <string>${exportMethod}</string>`);
536
- commands.push(' <key>signingStyle</key>');
537
- commands.push(` <string>${signingStyle}</string>`);
538
- if (signingStyle === 'manual') {
539
- commands.push(' <key>teamID</key>');
540
- commands.push(' <string>${APPLE_TEAM_ID}</string>');
541
- commands.push(' <key>provisioningProfiles</key>');
542
- commands.push(' <dict>');
543
- for (const { bundleId, profile } of profileEntries) {
544
- commands.push(` <key>${bundleId}</key>`);
545
- commands.push(` <string>${profile}</string>`);
546
- }
547
- commands.push(' </dict>');
548
- }
549
- if (exportMethod !== 'app-store') {
550
- commands.push(' <key>compileBitcode</key>');
551
- commands.push(` <${compileBitcodeVal}/>`);
552
- }
553
- if (exportMethod === 'app-store') {
554
- commands.push(' <key>uploadBitcode</key>');
555
- commands.push(` <${uploadBitcodeVal}/>`);
556
- }
557
- commands.push('</dict>');
558
- commands.push('</plist>');
559
- commands.push('PLIST_EOF');
560
- }
561
- commands.push('');
562
- // Export archive to IPA
563
- commands.push('# Export archive to IPA');
564
- let exportCmd = 'xcodebuild -exportArchive';
565
- exportCmd += ' -archivePath "$ARCHIVE_PATH"';
566
- exportCmd += ' -exportOptionsPlist "$EXPORT_PLIST"';
567
- exportCmd += ' -exportPath "$OUTPUT_DIR"';
568
- exportCmd += xcodeAuthFlags;
569
- commands.push(exportCmd);
570
- commands.push('');
571
- // Locate generated IPA
572
- commands.push('# Locate generated IPA and export paths');
573
- commands.push('IPA_PATH=$(find "$OUTPUT_DIR" -name "*.ipa" | head -1)');
574
- commands.push('DSYM_PATH=$(find "$OUTPUT_DIR" -name "*.dSYM.zip" 2>/dev/null | head -1 || true)');
575
- commands.push('');
576
- commands.push('if [ -z "$IPA_PATH" ]; then');
577
- commands.push(' echo "Error: IPA not found in $OUTPUT_DIR" >&2');
578
- commands.push(' exit 1');
579
- commands.push('fi');
580
- commands.push('');
581
- commands.push('echo "✓ IPA created: $IPA_PATH"');
582
- commands.push('ls -lh "$IPA_PATH"');
583
- commands.push('');
584
- commands.push('export_env CIBUILD_IPA_PATH "$IPA_PATH"');
585
- commands.push('export_env CIBUILD_XCARCHIVE_PATH "$(pwd)/$ARCHIVE_PATH"');
586
- commands.push('[ -n "$DSYM_PATH" ] && export_env CIBUILD_DSYM_PATH "$DSYM_PATH" || true');
587
- commands.push('');
588
- commands.push('echo "✓ xcode-archive complete"');
589
- commands.push('rm -f "$EXPORT_PLIST"');
590
- }
591
- commands.push('rm -f "$XCCONFIG_PATH"');
592
- const script = this.createBashScriptFromCommands(commands, stepName);
593
- return this.createScriptStep(script, stepName);
594
- }
595
- }
596
- /**
597
- * iOS Archive step executor
598
- * Creates an IPA file from a .app bundle
599
- */
600
- export class IosArchiveStepExecutor extends BaseStepExecutor {
601
- getValidationRequirements(inputs, _env, _config) {
602
- const requirements = [];
603
- // Required input
604
- requirements.push(this.requireInput('app_path', inputs, 'Path to .app bundle', 'Provide app_path input pointing to your built .app file'));
605
- // zip command for creating IPA
606
- requirements.push(this.requireCommand('zip', 'zip utility for creating IPA files', 'zip should be pre-installed on macOS'));
607
- // .app file - runtime check (created by xcodebuild)
608
- if (inputs.app_path) {
609
- requirements.push(this.runtimeRequirement(inputs.app_path, '.app bundle file', 'directory', 'xcodebuild'));
610
- }
611
- return requirements;
612
- }
613
- async execute(inputs, env, config) {
614
- const stepName = 'ios-archive';
615
- // Get app path - required
616
- let appPath = this.getRequiredInput(inputs, 'app_path', stepName);
617
- // Resolve path identifiers
618
- if (appPath.startsWith('builds:')) {
619
- appPath = appPath.replace('builds:', `${config.paths.buildsDir}/`);
620
- }
621
- // Get output path - defaults to artifacts/
622
- const outputPath = this.getInput(inputs, 'output_path', 'artifacts');
623
- // Get output name - optional, will derive from .app name if not provided
624
- const outputName = this.getInput(inputs, 'output_name', '');
625
- const commands = [];
626
- commands.push('# iOS Archive - Create IPA');
627
- commands.push(`echo "Creating IPA from: ${this.escapeBash(appPath)}"`);
628
- // Check if .app exists
629
- commands.push('');
630
- commands.push('# Verify .app bundle exists');
631
- commands.push(`if [ ! -d '${this.escapeBash(appPath)}' ]; then`);
632
- commands.push(` echo "Error: .app bundle not found at ${this.escapeBash(appPath)}"`);
633
- commands.push(' exit 1');
634
- commands.push('fi');
635
- // Determine output IPA name
636
- commands.push('');
637
- commands.push('# Determine IPA name');
638
- if (outputName && outputName.trim() !== '') {
639
- // Use provided name
640
- const cleanName = outputName.replace(/\.ipa$/, '');
641
- commands.push(`IPA_NAME="${this.escapeBash(cleanName)}"`);
642
- }
643
- else {
644
- // Derive from .app bundle name
645
- commands.push(`APP_BUNDLE='${this.escapeBash(appPath)}'`);
646
- commands.push('IPA_NAME=$(basename "$APP_BUNDLE" .app)');
647
- }
648
- commands.push('echo "IPA name: $IPA_NAME.ipa"');
649
- // Create IPA
650
- commands.push('');
651
- commands.push('# Create IPA structure');
652
- commands.push('TEMP_DIR=$(mktemp -d)');
653
- commands.push('mkdir -p "$TEMP_DIR/Payload"');
654
- commands.push('');
655
- commands.push('# Copy .app to Payload directory');
656
- commands.push(`cp -r '${this.escapeBash(appPath)}' "$TEMP_DIR/Payload/"`);
657
- commands.push('');
658
- commands.push('# Create IPA (zip with .ipa extension)');
659
- commands.push('cd "$TEMP_DIR"');
660
- commands.push(`zip -r "$IPA_NAME.ipa" Payload -q`);
661
- commands.push('cd - > /dev/null');
662
- commands.push('');
663
- commands.push('# Create output directory and move IPA');
664
- commands.push(`mkdir -p '${this.escapeBash(outputPath)}'`);
665
- commands.push(`mv "$TEMP_DIR/$IPA_NAME.ipa" '${this.escapeBash(outputPath)}/'`);
666
- commands.push('');
667
- commands.push('# Cleanup temp directory');
668
- commands.push('rm -rf "$TEMP_DIR"');
669
- commands.push('');
670
- commands.push('# Show result');
671
- commands.push('echo "✓ IPA created successfully"');
672
- commands.push(`ls -lh '${this.escapeBash(outputPath)}'/"$IPA_NAME.ipa"`);
673
- const script = this.createBashScriptFromCommands(commands, stepName);
674
- return this.createScriptStep(script, stepName);
675
- }
676
- }
677
- /**
678
- * OTA install step executor.
679
- * Generates manifest.plist and a QR code for itms-services:// OTA installation.
680
- * The IPA and manifest must be hosted at user-provided HTTPS URLs.
681
- */
682
- export class OtaInstallStepExecutor extends BaseStepExecutor {
683
- getValidationRequirements(inputs, _env, _config) {
684
- return [
685
- this.requireInput('ipa_url', inputs, 'HTTPS URL where the IPA file will be hosted', 'Provide the full HTTPS URL to where the IPA will be uploaded'),
686
- this.requireInput('bundle_id', inputs, 'iOS bundle identifier (e.g. com.example.app)'),
687
- this.requireInput('bundle_version', inputs, 'App version string (e.g. 1.2.3)'),
688
- this.requireInput('title', inputs, 'App display name shown during install'),
689
- ];
690
- }
691
- getOutputs() {
692
- return [
693
- {
694
- name: 'CIBUILD_PUBLIC_INSTALL_PAGE_QR_CODE_IMAGE_URL',
695
- type: 'environment',
696
- description: 'QR code image URL for the OTA install page (api.qrserver.com link)',
697
- },
698
- ];
699
- }
700
- async execute(inputs, _env, _config) {
701
- const stepName = 'ota-install';
702
- const ipaUrl = this.getRequiredInput(inputs, 'ipa_url', stepName);
703
- const bundleId = this.getRequiredInput(inputs, 'bundle_id', stepName);
704
- const bundleVersion = this.getRequiredInput(inputs, 'bundle_version', stepName);
705
- const title = this.getRequiredInput(inputs, 'title', stepName);
706
- const outputDir = this.getInput(inputs, 'output_dir', '.ci/artifacts');
707
- const manifestUrlInput = this.getInput(inputs, 'manifest_url', '');
708
- const escapedIpaUrl = this.escapeBash(ipaUrl);
709
- const escapedBundleId = this.escapeBash(bundleId);
710
- const escapedBundleVersion = this.escapeBash(bundleVersion);
711
- const escapedTitle = this.escapeBash(title);
712
- const escapedOutputDir = this.escapeBash(outputDir);
713
- const commands = [];
714
- commands.push('# ota-install — generate OTA manifest + QR code');
715
- commands.push(`IPA_URL='${escapedIpaUrl}'`);
716
- commands.push(`BUNDLE_ID='${escapedBundleId}'`);
717
- commands.push(`BUNDLE_VERSION='${escapedBundleVersion}'`);
718
- commands.push(`TITLE='${escapedTitle}'`);
719
- commands.push(`OUTPUT_DIR='${escapedOutputDir}'`);
720
- commands.push('');
721
- // Derive manifest URL if not provided
722
- if (manifestUrlInput.trim()) {
723
- commands.push(`MANIFEST_URL='${this.escapeBash(manifestUrlInput)}'`);
724
- }
725
- else {
726
- commands.push('# Derive manifest URL from IPA URL (same directory, manifest.plist filename)');
727
- commands.push('MANIFEST_URL="$(dirname "$IPA_URL")/manifest.plist"');
728
- }
729
- commands.push('');
730
- // Build OTA link
731
- commands.push('OTA_URL="itms-services://?action=download-manifest&url=${MANIFEST_URL}"');
732
- commands.push('');
733
- // Create output dir and write manifest.plist
734
- commands.push('mkdir -p "$OUTPUT_DIR"');
735
- commands.push('');
736
- commands.push('# Write manifest.plist');
737
- commands.push('cat > "$OUTPUT_DIR/manifest.plist" << PLIST_EOF');
738
- commands.push('<?xml version="1.0" encoding="UTF-8"?>');
739
- commands.push('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">');
740
- commands.push('<plist version="1.0">');
741
- commands.push('<dict>');
742
- commands.push(' <key>items</key>');
743
- commands.push(' <array>');
744
- commands.push(' <dict>');
745
- commands.push(' <key>assets</key>');
746
- commands.push(' <array>');
747
- commands.push(' <dict>');
748
- commands.push(' <key>kind</key><string>software-package</string>');
749
- commands.push(' <key>url</key><string>${IPA_URL}</string>');
750
- commands.push(' </dict>');
751
- commands.push(' </array>');
752
- commands.push(' <key>metadata</key>');
753
- commands.push(' <dict>');
754
- commands.push(' <key>bundle-identifier</key><string>${BUNDLE_ID}</string>');
755
- commands.push(' <key>bundle-version</key><string>${BUNDLE_VERSION}</string>');
756
- commands.push(' <key>kind</key><string>software</string>');
757
- commands.push(' <key>title</key><string>${TITLE}</string>');
758
- commands.push(' </dict>');
759
- commands.push(' </dict>');
760
- commands.push(' </array>');
761
- commands.push('</dict>');
762
- commands.push('</plist>');
763
- commands.push('PLIST_EOF');
764
- commands.push('');
765
- commands.push('echo "✓ manifest.plist written to $OUTPUT_DIR/manifest.plist"');
766
- commands.push('');
767
- // Generate QR code (qrencode preferred; graceful fallback)
768
- commands.push('# Generate QR code');
769
- commands.push('if command -v qrencode &>/dev/null; then');
770
- commands.push(' echo ""');
771
- commands.push(' echo "Scan to install:"');
772
- commands.push(' qrencode -t ansiutf8 "$OTA_URL"');
773
- commands.push('else');
774
- commands.push(' echo "ℹ Install qrencode for terminal QR: brew install qrencode"');
775
- commands.push('fi');
776
- commands.push('');
777
- // Print summary
778
- commands.push('echo ""');
779
- commands.push('echo "─────────────────────────────────────────"');
780
- commands.push('echo "OTA Install Summary"');
781
- commands.push('echo "─────────────────────────────────────────"');
782
- commands.push('echo "IPA URL: $IPA_URL"');
783
- commands.push('echo "Manifest URL: $MANIFEST_URL"');
784
- commands.push('echo "OTA Link: $OTA_URL"');
785
- commands.push('echo ""');
786
- commands.push('echo "Host the IPA and manifest.plist at the URLs above, then share the OTA link."');
787
- commands.push('echo "─────────────────────────────────────────"');
788
- commands.push('');
789
- // Export QR image URL to envstore (api.qrserver.com image link, usable in notifications)
790
- commands.push('# Export QR image URL to envstore for downstream steps (e.g. Slack notifications)');
791
- commands.push('ENCODED_OTA="$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$OTA_URL" 2>/dev/null || printf "%s" "$OTA_URL" | sed \'s/ /%20/g; s/:/%3A/g; s|/|%2F|g; s/?/%3F/g; s/=/%3D/g; s/&/%26/g\')"');
792
- commands.push('QR_IMAGE_URL="https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${ENCODED_OTA}"');
793
- commands.push('');
794
- commands.push('ENVSTORE_FILE="${ENVMAN_ENVSTORE_PATH:-.ci/.envstore.json}"');
795
- commands.push('if [ -f "$ENVSTORE_FILE" ]; then');
796
- commands.push(' node -e "');
797
- commands.push(' const fs=require(\'fs\');');
798
- commands.push(' const s=JSON.parse(fs.readFileSync(process.argv[1],\'utf-8\'));');
799
- commands.push(' s.envs=s.envs||[];');
800
- commands.push(' s.envs=s.envs.filter(e=>e.key!==\'CIBUILD_PUBLIC_INSTALL_PAGE_QR_CODE_IMAGE_URL\');');
801
- commands.push(' s.envs.push({key:\'CIBUILD_PUBLIC_INSTALL_PAGE_QR_CODE_IMAGE_URL\',value:process.argv[2]});');
802
- commands.push(' fs.writeFileSync(process.argv[1],JSON.stringify(s));');
803
- commands.push(' " "$ENVSTORE_FILE" "$QR_IMAGE_URL" 2>/dev/null || true');
804
- commands.push('fi');
805
- commands.push('export CIBUILD_PUBLIC_INSTALL_PAGE_QR_CODE_IMAGE_URL="$QR_IMAGE_URL"');
806
- const script = this.createBashScriptFromCommands(commands, stepName);
807
- return this.createScriptStep(script, stepName);
808
- }
809
- }
810
- /**
811
- * Builds the app and tests without executing them.
812
- * Produces an .xctestrun file for use with xcode-test-without-building.
813
- */
814
- export class XcodeBuildForTestStepExecutor extends BaseStepExecutor {
815
- getValidationRequirements(inputs, _env, _config) {
816
- const requirements = [];
817
- requirements.push(this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required', 'Install Xcode, then run: xcode-select --install'));
818
- requirements.push(this.requireInput('project_path', inputs, 'Path to .xcodeproj or .xcworkspace'));
819
- requirements.push(this.requireInput('scheme', inputs, 'Xcode scheme name'));
820
- if (inputs.project_path && !existsSync(inputs.project_path)) {
821
- requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'the checkout'));
822
- }
823
- if (inputs.destination === 'auto') {
824
- requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
825
- }
826
- return requirements;
827
- }
828
- getOutputs() {
829
- return [
830
- { name: 'CIBUILD_TEST_BUNDLE_PATH', type: 'environment', description: 'Directory containing the built test bundle' },
831
- { name: 'CIBUILD_XCTESTRUN_FILE_PATH', type: 'environment', description: 'Path to the generated .xctestrun file' },
832
- ];
833
- }
834
- async execute(inputs, _env, _config) {
835
- const stepName = 'xcode-build-for-test';
836
- const projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
837
- const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
838
- const configuration = this.getInput(inputs, 'configuration', 'Debug');
839
- // `auto` triggers runtime resolution via `xcrun simctl`.
840
- const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS Simulator'));
841
- const testPlan = this.getInput(inputs, 'test_plan', '');
842
- const xcconfigContent = this.getInput(inputs, 'xcconfig_content', '');
843
- const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
844
- const outputDir = this.getInput(inputs, 'output_dir', 'build');
845
- const escapedPath = this.escapeBash(projectPath);
846
- const escapedScheme = this.escapeBash(scheme);
847
- const commands = [];
848
- commands.push('# xcode-build-for-test — build-for-testing');
849
- commands.push(`echo "Building for testing: ${escapedPath}"`);
850
- commands.push(`echo "Scheme: ${escapedScheme}"`);
851
- commands.push('');
852
- // Output directory
853
- commands.push(`mkdir -p '${this.escapeBash(outputDir)}'`);
854
- commands.push(`OUTPUT_DIR="$(cd '${this.escapeBash(outputDir)}' && pwd)"`);
855
- commands.push(...derivedDataPathLines());
856
- commands.push('');
857
- // xcconfig
858
- if (xcconfigContent.trim()) {
859
- commands.push('XCCONFIG_FILE="$(mktemp -t cibuild-xcconfig).xcconfig"');
860
- commands.push(`cat > "$XCCONFIG_FILE" << 'XCCONFIG_EOF'`);
861
- commands.push(xcconfigContent);
862
- commands.push('XCCONFIG_EOF');
863
- commands.push('');
864
- }
865
- // Determine project type
866
- commands.push(`if [[ '${escapedPath}' == *.xcworkspace ]]; then`);
867
- commands.push(' PROJECT_TYPE="-workspace"');
868
- commands.push('else');
869
- commands.push(' PROJECT_TYPE="-project"');
870
- commands.push('fi');
871
- commands.push('');
872
- // Resolve the package graph on its own, ahead of the build, so a refused
873
- // fetch costs a retry of something that takes seconds rather than a re-run
874
- // of build-for-testing, which takes minutes. The build that follows reads
875
- // the same derived data and finds the graph already resolved.
876
- commands.push('# Resolve package dependencies first — see git-fetch-retry');
877
- commands.push(...refusedFetchHelpers());
878
- commands.push(...retryOnRefusedFetch({
879
- label: 'Package resolution',
880
- command: 'xcodebuild -resolvePackageDependencies' +
881
- ` "$PROJECT_TYPE" '${escapedPath}'` +
882
- ` -scheme '${escapedScheme}'` +
883
- ' -derivedDataPath "$DERIVED_DATA_PATH"',
884
- }));
885
- const pinsArm64 = pinsSimulatorArm64(xcodebuildOptions);
886
- if (pinsArm64) {
887
- commands.push(...simulatorArchsLines({
888
- projectPath: escapedPath,
889
- scheme: escapedScheme,
890
- configuration: this.escapeBash(configuration),
891
- destination: this.escapeBash(destination),
892
- xcconfig: Boolean(xcconfigContent.trim()),
893
- }));
894
- }
895
- // Build command
896
- let cmd = 'xcodebuild build-for-testing';
897
- cmd += ` "$PROJECT_TYPE" '${escapedPath}'`;
898
- cmd += ` -scheme '${escapedScheme}'`;
899
- cmd += ` -configuration '${this.escapeBash(configuration)}'`;
900
- cmd += ` -destination '${this.escapeBash(destination)}'`;
901
- cmd += ` -derivedDataPath "$DERIVED_DATA_PATH"`;
902
- if (testPlan) {
903
- cmd += ` -testPlan '${this.escapeBash(testPlan)}'`;
904
- }
905
- if (xcconfigContent.trim()) {
906
- cmd += ' -xcconfig "$XCCONFIG_FILE"';
907
- }
908
- if (xcodebuildOptions) {
909
- cmd += ` ${pinsArm64 ? withRuntimeSimulatorArchs(xcodebuildOptions) : xcodebuildOptions}`;
910
- }
911
- commands.push(cmd);
912
- commands.push('');
913
- // Locate .xctestrun file
914
- commands.push('# Locate generated .xctestrun file');
915
- commands.push('XCTESTRUN_PATH=$(find "$DERIVED_DATA_PATH/Build/Products" -name "*.xctestrun" | head -1)');
916
- commands.push('if [ -z "$XCTESTRUN_PATH" ]; then');
917
- commands.push(' echo "❌ Error: .xctestrun file not found"');
918
- commands.push(' exit 1');
919
- commands.push('fi');
920
- commands.push('');
921
- commands.push('TEST_BUNDLE_DIR="$(dirname "$XCTESTRUN_PATH")"');
922
- commands.push('echo "✅ Build for testing complete"');
923
- commands.push('echo "xctestrun: $XCTESTRUN_PATH"');
924
- commands.push('');
925
- // Export env vars
926
- commands.push('envman add --key CIBUILD_TEST_BUNDLE_PATH --value "$TEST_BUNDLE_DIR"');
927
- commands.push('envman add --key CIBUILD_XCTESTRUN_FILE_PATH --value "$XCTESTRUN_PATH"');
928
- if (xcconfigContent.trim()) {
929
- commands.push('rm -f "$XCCONFIG_FILE"');
930
- }
931
- const script = this.createBashScriptFromCommands(commands, stepName);
932
- return this.createScriptStep(script, stepName);
933
- }
934
- }
935
- /**
936
- * Runs pre-compiled tests from an .xctestrun file.
937
- */
938
- export class XcodeTestWithoutBuildingStepExecutor extends BaseStepExecutor {
939
- getValidationRequirements(inputs, _env, _config) {
940
- const requirements = [
941
- this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required', 'Install Xcode, then run: xcode-select --install'),
942
- ];
943
- if (inputs.destination === 'auto') {
944
- requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
945
- }
946
- return requirements;
947
- }
948
- getOutputs() {
949
- return [
950
- { name: 'CIBUILD_XCRESULT_PATH', type: 'environment', description: 'Path to the .xcresult test result bundle' },
951
- ];
952
- }
953
- async execute(inputs, _env, _config) {
954
- const stepName = 'xcode-test-without-building';
955
- const xctestrun = this.getInput(inputs, 'xctestrun', '$CIBUILD_XCTESTRUN_FILE_PATH');
956
- // `auto` triggers runtime resolution via `xcrun simctl`.
957
- const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'platform=iOS Simulator,name=iPhone 15,OS=latest'));
958
- const onlyTesting = this.getInput(inputs, 'only_testing', '');
959
- const skipTesting = this.getInput(inputs, 'skip_testing', '');
960
- const repetitionMode = this.getInput(inputs, 'test_repetition_mode', 'none');
961
- const maxRepetitions = this.getInput(inputs, 'maximum_test_repetitions', '3');
962
- const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
963
- const commands = [];
964
- commands.push('# xcode-test-without-building');
965
- commands.push('echo "Running pre-built tests..."');
966
- commands.push('');
967
- // Resolve xctestrun path
968
- commands.push(`XCTESTRUN_FILE="${xctestrun}"`);
969
- commands.push('if [ -z "$XCTESTRUN_FILE" ]; then');
970
- commands.push(' echo "❌ Error: xctestrun file path is empty. Run xcode-build-for-test first."');
971
- commands.push(' exit 1');
972
- commands.push('fi');
973
- commands.push('if [ ! -f "$XCTESTRUN_FILE" ]; then');
974
- commands.push(' echo "❌ Error: xctestrun file not found: $XCTESTRUN_FILE"');
975
- commands.push(' exit 1');
976
- commands.push('fi');
977
- commands.push('echo "xctestrun: $XCTESTRUN_FILE"');
978
- commands.push('');
979
- // Result bundle path
980
- commands.push('RESULT_BUNDLE_PATH="build/test-results/$(date +%Y%m%d_%H%M%S).xcresult"');
981
- commands.push('mkdir -p "$(dirname "$RESULT_BUNDLE_PATH")"');
982
- commands.push('');
983
- // Build command
984
- let cmd = 'xcodebuild test-without-building';
985
- cmd += ' -xctestrun "$XCTESTRUN_FILE"';
986
- cmd += ` -destination '${this.escapeBash(destination)}'`;
987
- cmd += ' -resultBundlePath "$RESULT_BUNDLE_PATH"';
988
- // Test filtering
989
- if (onlyTesting) {
990
- for (const test of onlyTesting.split('\n').filter(Boolean)) {
991
- cmd += ` -only-testing:'${this.escapeBash(test.trim())}'`;
992
- }
993
- }
994
- if (skipTesting) {
995
- for (const test of skipTesting.split('\n').filter(Boolean)) {
996
- cmd += ` -skip-testing:'${this.escapeBash(test.trim())}'`;
997
- }
998
- }
999
- // Repetition
1000
- if (repetitionMode && repetitionMode !== 'none') {
1001
- if (repetitionMode === 'until_failure') {
1002
- cmd += ' -run-tests-until-failure';
1003
- }
1004
- else if (repetitionMode === 'retry_on_failure') {
1005
- cmd += ' -retry-tests-on-failure';
1006
- }
1007
- cmd += ` -test-iterations ${maxRepetitions}`;
1008
- }
1009
- if (xcodebuildOptions) {
1010
- cmd += ` ${xcodebuildOptions}`;
1011
- }
1012
- commands.push(cmd);
1013
- commands.push('');
1014
- commands.push('echo "✅ Tests completed"');
1015
- commands.push('echo "Result bundle: $RESULT_BUNDLE_PATH"');
1016
- commands.push('');
1017
- // Export
1018
- commands.push('envman add --key CIBUILD_XCRESULT_PATH --value "$RESULT_BUNDLE_PATH"');
1019
- const script = this.createBashScriptFromCommands(commands, stepName);
1020
- return this.createScriptStep(script, stepName);
1021
- }
1022
- }
1023
- /**
1024
- * Builds an iOS/tvOS/watchOS app for the simulator.
1025
- * Produces a .app bundle with code signing disabled by default.
1026
- */
1027
- export class XcodeBuildForSimulatorStepExecutor extends BaseStepExecutor {
1028
- getValidationRequirements(inputs, _env, _config) {
1029
- const requirements = [];
1030
- requirements.push(this.requireCommand('xcodebuild', 'Xcode Command Line Tools are required', 'Install Xcode, then run: xcode-select --install'));
1031
- requirements.push(this.requireInput('project_path', inputs, 'Path to .xcodeproj or .xcworkspace'));
1032
- requirements.push(this.requireInput('scheme', inputs, 'Xcode scheme name'));
1033
- if (inputs.project_path && !existsSync(inputs.project_path)) {
1034
- requirements.push(this.runtimeRequirement(inputs.project_path, 'Xcode project/workspace file', 'file', 'the checkout'));
1035
- }
1036
- if (inputs.destination === 'auto') {
1037
- requirements.push(this.requireCommand('xcrun', 'xcrun is required to resolve destination: auto via xcrun simctl', 'Install Xcode and run: xcode-select --install'));
1038
- }
1039
- return requirements;
1040
- }
1041
- getOutputs() {
1042
- return [
1043
- { name: 'CIBUILD_APP_DIR_PATH', type: 'environment', description: 'Path to the generated .app directory' },
1044
- ];
1045
- }
1046
- async execute(inputs, _env, _config) {
1047
- const stepName = 'xcode-build-for-simulator';
1048
- const projectPath = this.getRequiredInput(inputs, 'project_path', stepName);
1049
- const scheme = this.getRequiredInput(inputs, 'scheme', stepName);
1050
- const configuration = this.getInput(inputs, 'configuration', '');
1051
- // `auto` triggers runtime resolution via `xcrun simctl`.
1052
- const destination = resolveDestinationInput(this.getInput(inputs, 'destination', 'generic/platform=iOS Simulator'));
1053
- const performClean = this.getInput(inputs, 'perform_clean_action', 'no');
1054
- const xcconfigContent = this.getInput(inputs, 'xcconfig_content', 'CODE_SIGNING_ALLOWED=NO');
1055
- const xcodebuildOptions = this.getInput(inputs, 'xcodebuild_options', '');
1056
- const outputDir = this.getInput(inputs, 'output_dir', 'build');
1057
- const escapedPath = this.escapeBash(projectPath);
1058
- const escapedScheme = this.escapeBash(scheme);
1059
- const commands = [];
1060
- commands.push('# xcode-build-for-simulator');
1061
- commands.push(`echo "Building for simulator: ${escapedPath}"`);
1062
- commands.push(`echo "Scheme: ${escapedScheme}"`);
1063
- commands.push('');
1064
- // Output dir
1065
- commands.push(`mkdir -p '${this.escapeBash(outputDir)}'`);
1066
- commands.push(`OUTPUT_DIR="$(cd '${this.escapeBash(outputDir)}' && pwd)"`);
1067
- commands.push(...derivedDataPathLines());
1068
- commands.push('');
1069
- // xcconfig
1070
- commands.push('XCCONFIG_FILE="$(mktemp -t cibuild-xcconfig).xcconfig"');
1071
- if (xcconfigContent.trim()) {
1072
- commands.push(`cat > "$XCCONFIG_FILE" << 'XCCONFIG_EOF'`);
1073
- commands.push(xcconfigContent);
1074
- commands.push('XCCONFIG_EOF');
1075
- }
1076
- else {
1077
- commands.push('echo "CODE_SIGNING_ALLOWED=NO" > "$XCCONFIG_FILE"');
1078
- }
1079
- commands.push('');
1080
- // Project type
1081
- commands.push(`if [[ '${escapedPath}' == *.xcworkspace ]]; then`);
1082
- commands.push(' PROJECT_TYPE="-workspace"');
1083
- commands.push('else');
1084
- commands.push(' PROJECT_TYPE="-project"');
1085
- commands.push('fi');
1086
- commands.push('');
1087
- // Resolve the package graph before building, under the refused-fetch
1088
- // retry. This is the step an iOS app is normally built with, so it is the
1089
- // one a refused dependency fetch lands on first. The build below reads the
1090
- // same derived data and finds the graph already resolved — the two
1091
- // -derivedDataPath arguments have to move together, or the resolve
1092
- // populates one location and the build re-resolves into another, which
1093
- // silently spends the retry on work the build then throws away.
1094
- commands.push('# Resolve package dependencies first — see git-fetch-retry');
1095
- commands.push(...refusedFetchHelpers());
1096
- commands.push(...retryOnRefusedFetch({
1097
- label: 'Package resolution',
1098
- command: 'xcodebuild -resolvePackageDependencies' +
1099
- ` "$PROJECT_TYPE" '${escapedPath}'` +
1100
- ` -scheme '${escapedScheme}'` +
1101
- ' -derivedDataPath "$DERIVED_DATA_PATH"',
1102
- }));
1103
- const pinsArm64 = pinsSimulatorArm64(xcodebuildOptions);
1104
- if (pinsArm64) {
1105
- commands.push(...simulatorArchsLines({
1106
- projectPath: escapedPath,
1107
- scheme: escapedScheme,
1108
- configuration: configuration ? this.escapeBash(configuration) : '',
1109
- destination: this.escapeBash(destination),
1110
- xcconfig: true,
1111
- }));
1112
- }
1113
- // Build command
1114
- let cmd = 'xcodebuild';
1115
- if (performClean === 'yes') {
1116
- cmd += ' clean';
1117
- }
1118
- cmd += ' build';
1119
- cmd += ` "$PROJECT_TYPE" '${escapedPath}'`;
1120
- cmd += ` -scheme '${escapedScheme}'`;
1121
- if (configuration) {
1122
- cmd += ` -configuration '${this.escapeBash(configuration)}'`;
1123
- }
1124
- cmd += ` -destination '${this.escapeBash(destination)}'`;
1125
- // -derivedDataPath rather than CONFIGURATION_BUILD_DIR. The latter was set
1126
- // to keep xcodebuild from writing a `build` directory inside each SPM
1127
- // package checkout in DerivedData ("File exists but is not a directory" on
1128
- // repeated runs) — but note what that fix actually was: making the path
1129
- // ABSOLUTE. Pointing derived data somewhere writable achieves the same
1130
- // thing without the cost below, and matches xcode-build-for-test.
1131
- //
1132
- // The cost, measured 2026-09-09 on four of the six iOS corpus rows:
1133
- // CONFIGURATION_BUILD_DIR overrides the per-configuration/per-platform
1134
- // product separation xcodebuild normally provides under
1135
- // DerivedData/Build/Products/<config>-<platform>/, flattening every target
1136
- // in the graph into ONE directory. Two build tasks for the same target then
1137
- // declare the same absolute output path and xcodebuild refuses the whole
1138
- // build with "Multiple commands produce". Read the notes it prints: they
1139
- // name the SAME target twice. It is not two packages colliding on a name,
1140
- // it is one target built twice into one directory. 16 collisions on
1141
- // jellyfin/Swiftfin, 266 on Automattic/pocket-casts-ios, 425 on
1142
- // home-assistant/iOS.
1143
- //
1144
- // It also breaks CocoaPods, which is the same defect wearing a disguise.
1145
- // CocoaPods derives PODS_CONFIGURATION_BUILD_DIR from BUILD_DIR, and
1146
- // BUILD_DIR is NOT what CONFIGURATION_BUILD_DIR overrides — so pod products
1147
- // are written to the flat directory while every generated copy-resources
1148
- // script and linker search path still points into DerivedData. On
1149
- // shenruisi/Stay that surfaced as "Resource SDWebImage.bundle not found.
1150
- // Run pod install", for a bundle that had in fact been built, two
1151
- // directories away.
1152
- //
1153
- // Proved by control, same repo and image and flags, only this line
1154
- // differing: CONFIGURATION_BUILD_DIR reproduced the collision and exit 65
1155
- // with no .app; -derivedDataPath reached BUILD SUCCEEDED in 2m06s and left
1156
- // both Debug and Debug-iphonesimulator under Products — the separation the
1157
- // flat directory destroys.
1158
- cmd += ` -derivedDataPath "$DERIVED_DATA_PATH"`;
1159
- cmd += ' -xcconfig "$XCCONFIG_FILE"';
1160
- if (xcodebuildOptions) {
1161
- cmd += ` ${pinsArm64 ? withRuntimeSimulatorArchs(xcodebuildOptions) : xcodebuildOptions}`;
1162
- }
1163
- commands.push(cmd);
1164
- commands.push('');
1165
- // Locate .app. It now lands under the per-platform Products directory
1166
- // rather than flat in $OUTPUT_DIR, so the guard has to follow it — at
1167
- // maxdepth 1 this found nothing and the step would fail every build with
1168
- // ".app not found" while the app had compiled perfectly.
1169
- //
1170
- // Following the products is not enough on its own, though, because a scheme
1171
- // that builds a watchOS or tvOS companion produces more than one bundle and
1172
- // a scan has no way to tell them apart. Ask the scheme, which knows: see
1173
- // xcode-app-product.ts. The scan below is what runs when the scheme cannot
1174
- // answer — a project with no shared scheme is ordinary and builds fine, so
1175
- // this resolves the same bundle it always did there.
1176
- commands.push('# Locate generated .app — the one this scheme builds');
1177
- commands.push('PRODUCTS_DIR="$DERIVED_DATA_PATH/Build/Products"');
1178
- commands.push('APP_RESOLVER="$(mktemp -t cibuild-app-product).cjs"');
1179
- commands.push(`cat > "$APP_RESOLVER" << 'CIBUILD_APP_PRODUCT_EOF'`);
1180
- commands.push(APP_PRODUCT_RESOLVER_SOURCE.trim());
1181
- commands.push('CIBUILD_APP_PRODUCT_EOF');
1182
- commands.push('APP_PATH=$(node "$APP_RESOLVER" "$PRODUCTS_DIR"' +
1183
- ` '${escapedPath}' '${escapedScheme}' '${this.escapeBash(destination)}' 2>/dev/null || true)`);
1184
- commands.push('rm -f "$APP_RESOLVER"');
1185
- commands.push('if [ -z "$APP_PATH" ]; then');
1186
- commands.push(' APP_PATH=$(find "$PRODUCTS_DIR" -maxdepth 2 -name "*.app" -type d 2>/dev/null | head -1)');
1187
- commands.push('fi');
1188
- commands.push('if [ -z "$APP_PATH" ]; then');
1189
- commands.push(' echo "❌ Error: .app not found under $PRODUCTS_DIR"');
1190
- commands.push(' exit 1');
1191
- commands.push('fi');
1192
- commands.push('');
1193
- commands.push('echo "✅ Simulator build complete"');
1194
- commands.push('echo "App: $APP_PATH"');
1195
- commands.push('');
1196
- // Export
1197
- commands.push('envman add --key CIBUILD_APP_DIR_PATH --value "$APP_PATH"');
1198
- commands.push('');
1199
- // Deliver it, the way gradle-build delivers its .apk.
1200
- //
1201
- // gradle-build copies its own output into the artifacts directory; this
1202
- // step located the bundle, exported the path and left it in DerivedData —
1203
- // which the runner excludes from artifact discovery. So the app was
1204
- // findable and deliberately not found, and an iOS proof could go green
1205
- // handing the user nothing to install. Pipelines that added a collecting
1206
- // step of their own delivered; every other one did not, which made
1207
- // delivery a property of the pipeline rather than of the build.
1208
- //
1209
- // It zips rather than copying the bundle in, and that is not cosmetic. A
1210
- // .app is a directory: staged as a directory it becomes one artifact per
1211
- // file inside it — every asset, nib and framework separately — and an
1212
- // internal symlink pointing outside the workspace fails the stage
1213
- // outright. A .zip is a plain file, stages as exactly one artifact, and is
1214
- // what someone downloading it wants anyway. ditto is the macOS-native
1215
- // archiver and preserves the bundle's permissions and symlinks, which a
1216
- // plain recursive zip does not do faithfully.
1217
- commands.push('# Deliver the app as one artifact');
1218
- commands.push('ARTIFACTS_DIR="${CIBUILD_ARTIFACTS_DIR:-.ci/artifacts}"');
1219
- commands.push('mkdir -p "$ARTIFACTS_DIR"');
1220
- commands.push('APP_NAME="$(basename "$APP_PATH")"');
1221
- commands.push('rm -f "$ARTIFACTS_DIR/$APP_NAME.zip"');
1222
- commands.push('ditto -c -k --keepParent "$APP_PATH" "$ARTIFACTS_DIR/$APP_NAME.zip"');
1223
- commands.push('echo " → Collected: $APP_NAME.zip"');
1224
- commands.push('echo "✅ Artifacts copied to: $ARTIFACTS_DIR"');
1225
- commands.push('ls -lh "$ARTIFACTS_DIR"');
1226
- commands.push('');
1227
- commands.push('rm -f "$XCCONFIG_FILE"');
1228
- const script = this.createBashScriptFromCommands(commands, stepName);
1229
- return this.createScriptStep(script, stepName);
1230
- }
1231
- }
1232
- /**
1233
- * Exports an IPA from an existing .xcarchive using xcodebuild -exportArchive.
1234
- */
1235
- export class ExportXcarchiveStepExecutor extends BaseStepExecutor {
1236
- getValidationRequirements(_inputs, _env, _config) {
1237
- return [
1238
- this.requireCommand('xcodebuild', 'Xcode is required for archive export'),
1239
- ];
1240
- }
1241
- getOutputs() {
1242
- return [
1243
- { name: 'CIBUILD_IPA_PATH', type: 'environment', description: 'Path to the exported IPA file' },
1244
- { name: 'CIBUILD_DSYM_PATH', type: 'environment', description: 'Path to the zipped dSYM files' },
1245
- ];
1246
- }
1247
- async execute(inputs, _env, _config) {
1248
- const stepName = 'export-xcarchive';
1249
- const archivePath = this.getRequiredInput(inputs, 'archive_path', stepName);
1250
- const product = this.getInput(inputs, 'product', 'app');
1251
- const distributionMethod = this.getInput(inputs, 'distribution_method', 'development');
1252
- const compileBitcode = this.getInput(inputs, 'compile_bitcode', 'yes') === 'yes';
1253
- const uploadBitcode = this.getInput(inputs, 'upload_bitcode', 'yes') === 'yes';
1254
- const exportOptionsPlistContent = this.getInput(inputs, 'export_options_plist_content', '');
1255
- const verbose = this.getInput(inputs, 'verbose_log', 'no') === 'yes';
1256
- const commands = [];
1257
- commands.push('# export-xcarchive — export IPA from .xcarchive');
1258
- commands.push('echo "📦 Exporting IPA from xcarchive..."');
1259
- commands.push('');
1260
- commands.push(`ARCHIVE_PATH='${this.escapeBash(archivePath)}'`);
1261
- commands.push('');
1262
- // Validate archive exists
1263
- commands.push('if [ ! -d "$ARCHIVE_PATH" ]; then');
1264
- commands.push(' echo "❌ Error: Archive not found: $ARCHIVE_PATH"');
1265
- commands.push(' exit 1');
1266
- commands.push('fi');
1267
- commands.push('');
1268
- // Set up export directory
1269
- commands.push('EXPORT_DIR="${CIBUILD_DEPLOY_DIR:-./artifacts}/export"');
1270
- commands.push('mkdir -p "$EXPORT_DIR"');
1271
- commands.push('');
1272
- // Generate or use provided ExportOptions.plist
1273
- commands.push('EXPORT_OPTIONS="$EXPORT_DIR/ExportOptions.plist"');
1274
- if (exportOptionsPlistContent) {
1275
- commands.push('cat > "$EXPORT_OPTIONS" << \'PLIST_EOF\'');
1276
- commands.push(exportOptionsPlistContent);
1277
- commands.push('PLIST_EOF');
1278
- }
1279
- else {
1280
- // Map distribution method for Xcode 15.3+
1281
- commands.push('# Determine distribution method');
1282
- commands.push(`METHOD='${this.escapeBash(distributionMethod)}'`);
1283
- commands.push('XCODE_VERSION=$(xcodebuild -version | head -1 | grep -oE "[0-9]+\\.[0-9]+" || echo "0.0")');
1284
- commands.push('XCODE_MAJOR=$(echo "$XCODE_VERSION" | cut -d. -f1)');
1285
- commands.push('XCODE_MINOR=$(echo "$XCODE_VERSION" | cut -d. -f2)');
1286
- commands.push('if [ "$XCODE_MAJOR" -ge 16 ] || ([ "$XCODE_MAJOR" -eq 15 ] && [ "$XCODE_MINOR" -ge 3 ]); then');
1287
- commands.push(' case "$METHOD" in');
1288
- commands.push(' development) METHOD="debugging" ;;');
1289
- commands.push(' app-store) METHOD="app-store-connect" ;;');
1290
- commands.push(' ad-hoc) METHOD="release-testing" ;;');
1291
- commands.push(' esac');
1292
- commands.push('fi');
1293
- commands.push('');
1294
- commands.push('cat > "$EXPORT_OPTIONS" << PLIST_EOF');
1295
- commands.push('<?xml version="1.0" encoding="UTF-8"?>');
1296
- commands.push('<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">');
1297
- commands.push('<plist version="1.0">');
1298
- commands.push('<dict>');
1299
- commands.push(' <key>method</key>');
1300
- commands.push(' <string>$METHOD</string>');
1301
- commands.push(` <key>compileBitcode</key>`);
1302
- commands.push(` <${compileBitcode}/>`);
1303
- commands.push(` <key>uploadBitcode</key>`);
1304
- commands.push(` <${uploadBitcode}/>`);
1305
- if (product === 'app-clip') {
1306
- commands.push(' <key>exportForThinning</key>');
1307
- commands.push(' <string>app-clip</string>');
1308
- }
1309
- commands.push('</dict>');
1310
- commands.push('</plist>');
1311
- commands.push('PLIST_EOF');
1312
- }
1313
- commands.push('');
1314
- // Run xcodebuild -exportArchive
1315
- const verboseFlag = verbose ? '' : ' -quiet';
1316
- commands.push('echo "Exporting with method: $METHOD"');
1317
- commands.push(`xcodebuild -exportArchive \\`);
1318
- commands.push(` -archivePath "$ARCHIVE_PATH" \\`);
1319
- commands.push(` -exportPath "$EXPORT_DIR" \\`);
1320
- commands.push(` -exportOptionsPlist "$EXPORT_OPTIONS"${verboseFlag}`);
1321
- commands.push('');
1322
- // Find IPA
1323
- commands.push('# Find exported IPA');
1324
- commands.push('IPA_PATH=$(find "$EXPORT_DIR" -name "*.ipa" | head -1)');
1325
- commands.push('if [ -z "$IPA_PATH" ]; then');
1326
- commands.push(' echo "❌ Error: No IPA found in export directory"');
1327
- commands.push(' exit 1');
1328
- commands.push('fi');
1329
- commands.push('echo "✅ Exported IPA: $IPA_PATH"');
1330
- commands.push('');
1331
- // Collect dSYMs
1332
- commands.push('# Collect dSYMs');
1333
- commands.push('DSYM_DIR="$ARCHIVE_PATH/dSYMs"');
1334
- commands.push('DSYM_ZIP=""');
1335
- commands.push('if [ -d "$DSYM_DIR" ] && [ "$(ls -A "$DSYM_DIR" 2>/dev/null)" ]; then');
1336
- commands.push(' DSYM_ZIP="$EXPORT_DIR/dSYMs.zip"');
1337
- commands.push(' cd "$DSYM_DIR" && zip -r "$DSYM_ZIP" . && cd -');
1338
- commands.push(' echo "dSYMs: $DSYM_ZIP"');
1339
- commands.push('fi');
1340
- commands.push('');
1341
- // Export env vars
1342
- commands.push('envman add --key CIBUILD_IPA_PATH --value "$IPA_PATH"');
1343
- commands.push('if [ -n "$DSYM_ZIP" ]; then');
1344
- commands.push(' envman add --key CIBUILD_DSYM_PATH --value "$DSYM_ZIP"');
1345
- commands.push('fi');
1346
- const script = this.createBashScriptFromCommands(commands, stepName);
1347
- return this.createScriptStep(script, stepName);
1348
- }
1349
- }
1350
- //# sourceMappingURL=xcode.js.map