@invarn/cibuild 1.3.16 → 1.3.17

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 (242) hide show
  1. package/dist/cli.cjs +1 -1
  2. package/dist/src/cli.d.ts +3 -0
  3. package/dist/src/cli.d.ts.map +1 -0
  4. package/dist/src/cli.js +987 -0
  5. package/dist/src/commands/android-scanner.d.ts +32 -0
  6. package/dist/src/commands/android-scanner.d.ts.map +1 -0
  7. package/dist/src/commands/android-scanner.js +667 -0
  8. package/dist/src/commands/build.d.ts +5 -0
  9. package/dist/src/commands/build.d.ts.map +1 -0
  10. package/dist/src/commands/build.js +1096 -0
  11. package/dist/src/commands/edit.d.ts +3 -0
  12. package/dist/src/commands/edit.d.ts.map +1 -0
  13. package/dist/src/commands/edit.js +651 -0
  14. package/dist/src/commands/file-secret-collector.d.ts +37 -0
  15. package/dist/src/commands/file-secret-collector.d.ts.map +1 -0
  16. package/dist/src/commands/file-secret-collector.js +199 -0
  17. package/dist/src/commands/github-workflow.d.ts +5 -0
  18. package/dist/src/commands/github-workflow.d.ts.map +1 -0
  19. package/dist/src/commands/github-workflow.js +45 -0
  20. package/dist/src/commands/ios-scanner.d.ts +27 -0
  21. package/dist/src/commands/ios-scanner.d.ts.map +1 -0
  22. package/dist/src/commands/ios-scanner.js +337 -0
  23. package/dist/src/commands/reset.d.ts +7 -0
  24. package/dist/src/commands/reset.d.ts.map +1 -0
  25. package/dist/src/commands/reset.js +81 -0
  26. package/dist/src/commands/secrets-sync-workflow.d.ts +15 -0
  27. package/dist/src/commands/secrets-sync-workflow.d.ts.map +1 -0
  28. package/dist/src/commands/secrets-sync-workflow.js +255 -0
  29. package/dist/src/commands/secrets-upload.d.ts +21 -0
  30. package/dist/src/commands/secrets-upload.d.ts.map +1 -0
  31. package/dist/src/commands/secrets-upload.js +177 -0
  32. package/dist/src/commands/secrets-upload.test.d.ts +5 -0
  33. package/dist/src/commands/secrets-upload.test.d.ts.map +1 -0
  34. package/dist/src/commands/secrets-upload.test.js +60 -0
  35. package/dist/src/config.d.ts +3 -0
  36. package/dist/src/config.d.ts.map +1 -0
  37. package/dist/src/config.js +46 -0
  38. package/dist/src/envman/cli.d.ts +21 -0
  39. package/dist/src/envman/cli.d.ts.map +1 -0
  40. package/dist/src/envman/cli.js +240 -0
  41. package/dist/src/envman/envman.d.ts +83 -0
  42. package/dist/src/envman/envman.d.ts.map +1 -0
  43. package/dist/src/envman/envman.js +361 -0
  44. package/dist/src/envman/envman.test.d.ts +5 -0
  45. package/dist/src/envman/envman.test.d.ts.map +1 -0
  46. package/dist/src/envman/envman.test.js +236 -0
  47. package/dist/src/envman/index.d.ts +23 -0
  48. package/dist/src/envman/index.d.ts.map +1 -0
  49. package/dist/src/envman/index.js +23 -0
  50. package/dist/src/envman/types.d.ts +55 -0
  51. package/dist/src/envman/types.d.ts.map +1 -0
  52. package/dist/src/envman/types.js +12 -0
  53. package/dist/src/lib.d.ts +27 -0
  54. package/dist/src/lib.d.ts.map +1 -0
  55. package/dist/src/lib.js +32 -0
  56. package/dist/src/pipeline.d.ts +3 -0
  57. package/dist/src/pipeline.d.ts.map +1 -0
  58. package/dist/src/pipeline.js +57 -0
  59. package/dist/src/runner.d.ts +17 -0
  60. package/dist/src/runner.d.ts.map +1 -0
  61. package/dist/src/runner.js +234 -0
  62. package/dist/src/types.d.ts +57 -0
  63. package/dist/src/types.d.ts.map +1 -0
  64. package/dist/src/types.js +2 -0
  65. package/dist/src/yaml/bitrise-compat.d.ts +65 -0
  66. package/dist/src/yaml/bitrise-compat.d.ts.map +1 -0
  67. package/dist/src/yaml/bitrise-compat.js +206 -0
  68. package/dist/src/yaml/bitrise-compat.test.d.ts +5 -0
  69. package/dist/src/yaml/bitrise-compat.test.d.ts.map +1 -0
  70. package/dist/src/yaml/bitrise-compat.test.js +347 -0
  71. package/dist/src/yaml/converter.d.ts +33 -0
  72. package/dist/src/yaml/converter.d.ts.map +1 -0
  73. package/dist/src/yaml/converter.js +222 -0
  74. package/dist/src/yaml/converter.test.d.ts +5 -0
  75. package/dist/src/yaml/converter.test.d.ts.map +1 -0
  76. package/dist/src/yaml/converter.test.js +348 -0
  77. package/dist/src/yaml/e2e.test.d.ts +6 -0
  78. package/dist/src/yaml/e2e.test.d.ts.map +1 -0
  79. package/dist/src/yaml/e2e.test.js +446 -0
  80. package/dist/src/yaml/env-resolver.d.ts +120 -0
  81. package/dist/src/yaml/env-resolver.d.ts.map +1 -0
  82. package/dist/src/yaml/env-resolver.js +405 -0
  83. package/dist/src/yaml/env-resolver.test.d.ts +5 -0
  84. package/dist/src/yaml/env-resolver.test.d.ts.map +1 -0
  85. package/dist/src/yaml/env-resolver.test.js +502 -0
  86. package/dist/src/yaml/interactive-prompts.d.ts +71 -0
  87. package/dist/src/yaml/interactive-prompts.d.ts.map +1 -0
  88. package/dist/src/yaml/interactive-prompts.js +258 -0
  89. package/dist/src/yaml/missing-env-handler.d.ts +45 -0
  90. package/dist/src/yaml/missing-env-handler.d.ts.map +1 -0
  91. package/dist/src/yaml/missing-env-handler.js +64 -0
  92. package/dist/src/yaml/parser.d.ts +33 -0
  93. package/dist/src/yaml/parser.d.ts.map +1 -0
  94. package/dist/src/yaml/parser.js +145 -0
  95. package/dist/src/yaml/pipeline-with-secrets.d.ts +25 -0
  96. package/dist/src/yaml/pipeline-with-secrets.d.ts.map +1 -0
  97. package/dist/src/yaml/pipeline-with-secrets.js +76 -0
  98. package/dist/src/yaml/platform-detector.d.ts +83 -0
  99. package/dist/src/yaml/platform-detector.d.ts.map +1 -0
  100. package/dist/src/yaml/platform-detector.js +188 -0
  101. package/dist/src/yaml/platform-detector.test.d.ts +5 -0
  102. package/dist/src/yaml/platform-detector.test.d.ts.map +1 -0
  103. package/dist/src/yaml/platform-detector.test.js +414 -0
  104. package/dist/src/yaml/preflight-validation.d.ts +40 -0
  105. package/dist/src/yaml/preflight-validation.d.ts.map +1 -0
  106. package/dist/src/yaml/preflight-validation.js +152 -0
  107. package/dist/src/yaml/secrets-manager.d.ts +77 -0
  108. package/dist/src/yaml/secrets-manager.d.ts.map +1 -0
  109. package/dist/src/yaml/secrets-manager.js +219 -0
  110. package/dist/src/yaml/step-validator.d.ts +54 -0
  111. package/dist/src/yaml/step-validator.d.ts.map +1 -0
  112. package/dist/src/yaml/step-validator.js +403 -0
  113. package/dist/src/yaml/steps/android-sign.d.ts +35 -0
  114. package/dist/src/yaml/steps/android-sign.d.ts.map +1 -0
  115. package/dist/src/yaml/steps/android-sign.js +147 -0
  116. package/dist/src/yaml/steps/android-version.d.ts +26 -0
  117. package/dist/src/yaml/steps/android-version.d.ts.map +1 -0
  118. package/dist/src/yaml/steps/android-version.js +128 -0
  119. package/dist/src/yaml/steps/android-version.test.d.ts +5 -0
  120. package/dist/src/yaml/steps/android-version.test.d.ts.map +1 -0
  121. package/dist/src/yaml/steps/android-version.test.js +196 -0
  122. package/dist/src/yaml/steps/android.d.ts +95 -0
  123. package/dist/src/yaml/steps/android.d.ts.map +1 -0
  124. package/dist/src/yaml/steps/android.js +916 -0
  125. package/dist/src/yaml/steps/app-store-deploy.d.ts +48 -0
  126. package/dist/src/yaml/steps/app-store-deploy.d.ts.map +1 -0
  127. package/dist/src/yaml/steps/app-store-deploy.js +162 -0
  128. package/dist/src/yaml/steps/base.d.ts +238 -0
  129. package/dist/src/yaml/steps/base.d.ts.map +1 -0
  130. package/dist/src/yaml/steps/base.js +345 -0
  131. package/dist/src/yaml/steps/bitrise-android-tools.d.ts +26 -0
  132. package/dist/src/yaml/steps/bitrise-android-tools.d.ts.map +1 -0
  133. package/dist/src/yaml/steps/bitrise-android-tools.js +198 -0
  134. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts +5 -0
  135. package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts.map +1 -0
  136. package/dist/src/yaml/steps/bitrise-android-tools.test.js +280 -0
  137. package/dist/src/yaml/steps/bitrise-apk-info.d.ts +22 -0
  138. package/dist/src/yaml/steps/bitrise-apk-info.d.ts.map +1 -0
  139. package/dist/src/yaml/steps/bitrise-apk-info.js +144 -0
  140. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts +5 -0
  141. package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts.map +1 -0
  142. package/dist/src/yaml/steps/bitrise-apk-info.test.js +331 -0
  143. package/dist/src/yaml/steps/bitrise-slack.d.ts +49 -0
  144. package/dist/src/yaml/steps/bitrise-slack.d.ts.map +1 -0
  145. package/dist/src/yaml/steps/bitrise-slack.js +280 -0
  146. package/dist/src/yaml/steps/bitrise-slack.test.d.ts +5 -0
  147. package/dist/src/yaml/steps/bitrise-slack.test.d.ts.map +1 -0
  148. package/dist/src/yaml/steps/bitrise-slack.test.js +484 -0
  149. package/dist/src/yaml/steps/bitrise-ssh.d.ts +27 -0
  150. package/dist/src/yaml/steps/bitrise-ssh.d.ts.map +1 -0
  151. package/dist/src/yaml/steps/bitrise-ssh.js +134 -0
  152. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts +5 -0
  153. package/dist/src/yaml/steps/bitrise-ssh.test.d.ts.map +1 -0
  154. package/dist/src/yaml/steps/bitrise-ssh.test.js +205 -0
  155. package/dist/src/yaml/steps/cache.d.ts +52 -0
  156. package/dist/src/yaml/steps/cache.d.ts.map +1 -0
  157. package/dist/src/yaml/steps/cache.js +351 -0
  158. package/dist/src/yaml/steps/fastlane.d.ts +27 -0
  159. package/dist/src/yaml/steps/fastlane.d.ts.map +1 -0
  160. package/dist/src/yaml/steps/fastlane.js +79 -0
  161. package/dist/src/yaml/steps/file.d.ts +27 -0
  162. package/dist/src/yaml/steps/file.d.ts.map +1 -0
  163. package/dist/src/yaml/steps/file.js +35 -0
  164. package/dist/src/yaml/steps/flutter.d.ts +63 -0
  165. package/dist/src/yaml/steps/flutter.d.ts.map +1 -0
  166. package/dist/src/yaml/steps/flutter.js +215 -0
  167. package/dist/src/yaml/steps/git-clone.d.ts +26 -0
  168. package/dist/src/yaml/steps/git-clone.d.ts.map +1 -0
  169. package/dist/src/yaml/steps/git-clone.js +111 -0
  170. package/dist/src/yaml/steps/google-play-deploy.d.ts +37 -0
  171. package/dist/src/yaml/steps/google-play-deploy.d.ts.map +1 -0
  172. package/dist/src/yaml/steps/google-play-deploy.js +193 -0
  173. package/dist/src/yaml/steps/google-play-deploy.test.d.ts +5 -0
  174. package/dist/src/yaml/steps/google-play-deploy.test.d.ts.map +1 -0
  175. package/dist/src/yaml/steps/google-play-deploy.test.js +310 -0
  176. package/dist/src/yaml/steps/index.d.ts +10 -0
  177. package/dist/src/yaml/steps/index.d.ts.map +1 -0
  178. package/dist/src/yaml/steps/index.js +1361 -0
  179. package/dist/src/yaml/steps/ios-deps.d.ts +43 -0
  180. package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -0
  181. package/dist/src/yaml/steps/ios-deps.js +141 -0
  182. package/dist/src/yaml/steps/ios-deps.test.d.ts +5 -0
  183. package/dist/src/yaml/steps/ios-deps.test.d.ts.map +1 -0
  184. package/dist/src/yaml/steps/ios-deps.test.js +90 -0
  185. package/dist/src/yaml/steps/ios-signing.d.ts +31 -0
  186. package/dist/src/yaml/steps/ios-signing.d.ts.map +1 -0
  187. package/dist/src/yaml/steps/ios-signing.js +144 -0
  188. package/dist/src/yaml/steps/ios-version.d.ts +47 -0
  189. package/dist/src/yaml/steps/ios-version.d.ts.map +1 -0
  190. package/dist/src/yaml/steps/ios-version.js +151 -0
  191. package/dist/src/yaml/steps/linting.d.ts +47 -0
  192. package/dist/src/yaml/steps/linting.d.ts.map +1 -0
  193. package/dist/src/yaml/steps/linting.js +148 -0
  194. package/dist/src/yaml/steps/phase2.test.d.ts +6 -0
  195. package/dist/src/yaml/steps/phase2.test.d.ts.map +1 -0
  196. package/dist/src/yaml/steps/phase2.test.js +197 -0
  197. package/dist/src/yaml/steps/phase3.test.d.ts +5 -0
  198. package/dist/src/yaml/steps/phase3.test.d.ts.map +1 -0
  199. package/dist/src/yaml/steps/phase3.test.js +144 -0
  200. package/dist/src/yaml/steps/phase4.test.d.ts +5 -0
  201. package/dist/src/yaml/steps/phase4.test.d.ts.map +1 -0
  202. package/dist/src/yaml/steps/phase4.test.js +166 -0
  203. package/dist/src/yaml/steps/phase5.test.d.ts +6 -0
  204. package/dist/src/yaml/steps/phase5.test.d.ts.map +1 -0
  205. package/dist/src/yaml/steps/phase5.test.js +263 -0
  206. package/dist/src/yaml/steps/registry.d.ts +88 -0
  207. package/dist/src/yaml/steps/registry.d.ts.map +1 -0
  208. package/dist/src/yaml/steps/registry.js +125 -0
  209. package/dist/src/yaml/steps/registry.test.d.ts +5 -0
  210. package/dist/src/yaml/steps/registry.test.d.ts.map +1 -0
  211. package/dist/src/yaml/steps/registry.test.js +235 -0
  212. package/dist/src/yaml/steps/release.d.ts +50 -0
  213. package/dist/src/yaml/steps/release.d.ts.map +1 -0
  214. package/dist/src/yaml/steps/release.js +154 -0
  215. package/dist/src/yaml/steps/script.d.ts +23 -0
  216. package/dist/src/yaml/steps/script.d.ts.map +1 -0
  217. package/dist/src/yaml/steps/script.js +63 -0
  218. package/dist/src/yaml/steps/spec-validation.test.d.ts +6 -0
  219. package/dist/src/yaml/steps/spec-validation.test.d.ts.map +1 -0
  220. package/dist/src/yaml/steps/spec-validation.test.js +130 -0
  221. package/dist/src/yaml/steps/steps.test.d.ts +6 -0
  222. package/dist/src/yaml/steps/steps.test.d.ts.map +1 -0
  223. package/dist/src/yaml/steps/steps.test.js +474 -0
  224. package/dist/src/yaml/steps/test-config.d.ts +3 -0
  225. package/dist/src/yaml/steps/test-config.d.ts.map +1 -0
  226. package/dist/src/yaml/steps/test-config.js +16 -0
  227. package/dist/src/yaml/steps/xcode-new.test.d.ts +5 -0
  228. package/dist/src/yaml/steps/xcode-new.test.d.ts.map +1 -0
  229. package/dist/src/yaml/steps/xcode-new.test.js +211 -0
  230. package/dist/src/yaml/steps/xcode.d.ts +222 -0
  231. package/dist/src/yaml/steps/xcode.d.ts.map +1 -0
  232. package/dist/src/yaml/steps/xcode.js +999 -0
  233. package/dist/src/yaml/types.d.ts +68 -0
  234. package/dist/src/yaml/types.d.ts.map +1 -0
  235. package/dist/src/yaml/types.js +5 -0
  236. package/dist/src/yaml/validation-types.d.ts +96 -0
  237. package/dist/src/yaml/validation-types.d.ts.map +1 -0
  238. package/dist/src/yaml/validation-types.js +8 -0
  239. package/dist/src/yaml/yaml-updater.d.ts +24 -0
  240. package/dist/src/yaml/yaml-updater.d.ts.map +1 -0
  241. package/dist/src/yaml/yaml-updater.js +128 -0
  242. package/package.json +16 -4
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Converts YAML pipeline workflows to PipelineDef format
3
+ * This bridges the YAML configuration with the existing runner engine
4
+ */
5
+ import { detectPlatformInfo } from './platform-detector.js';
6
+ import { EnvResolver } from './env-resolver.js';
7
+ import { getStepExecutor, UnrecognizedStepError } from './steps/registry.js';
8
+ export class YAMLConversionError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = 'YAMLConversionError';
12
+ }
13
+ }
14
+ /**
15
+ * Mapping of common unsupported steps to CI Build alternatives
16
+ */
17
+ const STEP_SUGGESTIONS = {
18
+ 'create-install-page-qr-code': 'Use script step with qrencode to generate QR codes',
19
+ 'deploy-to-itunesconnect-deliver': 'Use script step with fastlane deliver or xcrun altool',
20
+ 'deploy-to-itunesconnect-application-loader': 'Use script step with xcrun altool',
21
+ 'amazon-s3-deploy': 'Use built-in S3 upload via upload-artifacts.sh script',
22
+ 'deploy-to-bitrise-io': 'Use app-store-deploy (iOS) or google-play-deploy (Android) for store deployment, or a script step for generic S3 upload',
23
+ 'generic-file-storage': 'Use a script step with upload-artifacts.sh for S3 upload',
24
+ 'bitrise-step-install-from-source': 'Not supported - use native CI Build steps',
25
+ 'npm': 'Use script step with npm commands',
26
+ 'yarn': 'Use script step with yarn commands',
27
+ 'danger': 'Use script step with danger commands',
28
+ 'firebase-app-distribution': 'Use script step with Firebase CLI',
29
+ 'firebase-test-lab': 'Use script step with gcloud firebase test',
30
+ 'find-jira-issue': 'Use script step with JIRA REST API',
31
+ 'comment-on-github-pull-request': 'Use script step with GitHub API or gh CLI',
32
+ };
33
+ /**
34
+ * Bitrise step names that differ from their cibuild equivalents.
35
+ * Most Bitrise steps keep the same name — only remaps are listed here.
36
+ * See steps/bitrise-map.yml for the full version-tracking map.
37
+ */
38
+ const BITRISE_TO_CIBUILD = {
39
+ 'gradle-runner': 'gradle-build',
40
+ 'certificate-and-profile-installer': 'certificate-installer',
41
+ 'android-detekt': 'detekt',
42
+ 'bitrise-step-flutter-installer': 'flutter-installer',
43
+ };
44
+ /**
45
+ * Converts a YAML pipeline workflow to PipelineDef format
46
+ * @param pipeline Parsed YAML pipeline
47
+ * @param config CI configuration with path mappings
48
+ * @param workflowName Name of the workflow to convert (if not specified, uses first workflow)
49
+ * @param yamlFilePath Optional path to the YAML file (used for naming SSH keys, etc.)
50
+ * @returns ConversionResult with PipelineDef and warnings about unsupported steps
51
+ */
52
+ export async function convertYAMLToPipelineDef(pipeline, config, workflowName, yamlFilePath) {
53
+ // Initialize warnings collection
54
+ const warnings = [];
55
+ let skippedSteps = 0;
56
+ // Step 1: Workflow selection (FR-22, sub-task 3.7)
57
+ const selectedWorkflow = selectWorkflow(pipeline, workflowName);
58
+ const selectedWorkflowName = workflowName || Object.keys(pipeline.workflows)[0];
59
+ // Step 2: Platform detection
60
+ const platformInfo = detectPlatformInfo(pipeline, selectedWorkflowName);
61
+ // Step 3: Environment variable resolution
62
+ const envResolver = new EnvResolver(pipeline, selectedWorkflow, selectedWorkflowName, platformInfo.platform, platformInfo.stack, yamlFilePath);
63
+ // Step 4: Parse and convert steps
64
+ const steps = [];
65
+ const stepsOrder = [];
66
+ let stepCounter = 0;
67
+ for (const yamlStep of selectedWorkflow.steps) {
68
+ // Parse step (sub-task 3.8)
69
+ const parsedStep = parseStep(yamlStep, stepCounter);
70
+ stepCounter++;
71
+ // Handle conditional execution (sub-task 3.9)
72
+ // Note: run_if, is_always_run, is_skippable will be implemented
73
+ // when we have the step registry
74
+ // Remap Bitrise step names that differ from cibuild names
75
+ const resolvedStepName = BITRISE_TO_CIBUILD[parsedStep.name] ?? parsedStep.name;
76
+ // Get step executor from registry - catch unrecognized steps
77
+ let stepExecutor;
78
+ try {
79
+ stepExecutor = getStepExecutor(resolvedStepName);
80
+ }
81
+ catch (error) {
82
+ if (error instanceof UnrecognizedStepError) {
83
+ // Add warning and skip this step
84
+ const stepIdentifier = parsedStep.version
85
+ ? `${parsedStep.name}@${parsedStep.version}`
86
+ : parsedStep.name;
87
+ // Check if there's a suggested alternative
88
+ const suggestion = STEP_SUGGESTIONS[parsedStep.name];
89
+ let warningMessage = `⚠️ Unsupported step: ${stepIdentifier} (skipping)`;
90
+ if (suggestion) {
91
+ warningMessage += `\n 💡 Suggestion: ${suggestion}`;
92
+ }
93
+ warnings.push(warningMessage);
94
+ skippedSteps++;
95
+ continue; // Skip to next step
96
+ }
97
+ // Re-throw other errors
98
+ throw error;
99
+ }
100
+ // Interpolate step inputs
101
+ const interpolatedInputs = envResolver.interpolateObject(parsedStep.inputs, parsedStep.title || parsedStep.name);
102
+ // Execute step to get script
103
+ const stepDef = await stepExecutor.execute(interpolatedInputs, envResolver.getAll(), config);
104
+ // Generate unique step ID
105
+ const stepId = `step_${stepCounter}`;
106
+ stepDef.id = stepId;
107
+ stepDef.name = parsedStep.title || parsedStep.name;
108
+ // Cache steps are always skippable — they degrade gracefully and should
109
+ // never abort a pipeline.
110
+ const alwaysSkippableSteps = ['cache-pull', 'cache-push'];
111
+ stepDef.isSkippable = parsedStep.is_skippable || alwaysSkippableSteps.includes(resolvedStepName);
112
+ steps.push(stepDef);
113
+ stepsOrder.push(stepId);
114
+ // Register this step's outputs as passthrough shell references so that
115
+ // later steps can reference them without triggering a missing-var error.
116
+ if (stepExecutor.getOutputs) {
117
+ for (const output of stepExecutor.getOutputs()) {
118
+ envResolver.registerStepOutput(output.name);
119
+ }
120
+ }
121
+ }
122
+ // Step 5: Create PipelineDef
123
+ const pipelineDef = {
124
+ name: `${selectedWorkflowName} (YAML)`,
125
+ artifacts: [], // YAML pipelines don't define artifacts in the same way
126
+ steps,
127
+ stepsOrder,
128
+ };
129
+ return {
130
+ pipeline: pipelineDef,
131
+ warnings,
132
+ skippedSteps,
133
+ };
134
+ }
135
+ /**
136
+ * Selects a workflow from the pipeline
137
+ * If workflowName is not specified, returns the first workflow
138
+ * @param pipeline Parsed YAML pipeline
139
+ * @param workflowName Optional workflow name
140
+ * @returns Selected workflow
141
+ * @throws YAMLConversionError if workflow not found
142
+ */
143
+ function selectWorkflow(pipeline, workflowName) {
144
+ // If no workflow specified, use the first one (FR-4)
145
+ if (!workflowName) {
146
+ const firstWorkflowName = Object.keys(pipeline.workflows)[0];
147
+ return pipeline.workflows[firstWorkflowName];
148
+ }
149
+ // Check if specified workflow exists
150
+ const workflow = pipeline.workflows[workflowName];
151
+ if (!workflow) {
152
+ const availableWorkflows = Object.keys(pipeline.workflows).join(', ');
153
+ throw new YAMLConversionError(`Workflow '${workflowName}' not found in pipeline.\n` +
154
+ `Available workflows: ${availableWorkflows}`);
155
+ }
156
+ return workflow;
157
+ }
158
+ /**
159
+ * Parses a YAML step object into a ParsedStep
160
+ * Handles the step-name@version format
161
+ * @param yamlStep YAML step object
162
+ * @param index Step index for error messages
163
+ * @returns ParsedStep with name, version, and inputs
164
+ */
165
+ function parseStep(yamlStep, index) {
166
+ // Each YAML step is an object with one key: "step-name@version"
167
+ const stepKeys = Object.keys(yamlStep);
168
+ if (stepKeys.length === 0) {
169
+ throw new YAMLConversionError(`Step at index ${index} has no step name defined`);
170
+ }
171
+ const stepNameWithVersion = stepKeys[0];
172
+ const stepConfig = yamlStep[stepNameWithVersion];
173
+ // Parse step name and version (FR-8)
174
+ const { name, version } = parseStepNameAndVersion(stepNameWithVersion);
175
+ // Convert Bitrise array-style inputs to object format
176
+ let inputs = stepConfig.inputs || {};
177
+ if (Array.isArray(inputs)) {
178
+ // Bitrise format: inputs are an array of objects with single key-value pairs
179
+ const inputsObj = {};
180
+ for (const input of inputs) {
181
+ if (typeof input === 'object' && input !== null) {
182
+ Object.assign(inputsObj, input);
183
+ }
184
+ }
185
+ inputs = inputsObj;
186
+ }
187
+ // Extract step configuration
188
+ const parsedStep = {
189
+ name,
190
+ version,
191
+ title: stepConfig.title,
192
+ inputs,
193
+ run_if: stepConfig.run_if,
194
+ is_always_run: stepConfig.is_always_run,
195
+ is_skippable: stepConfig.is_skippable,
196
+ };
197
+ return parsedStep;
198
+ }
199
+ /**
200
+ * Parses step name and version from "step-name@version" format
201
+ * @param stepNameWithVersion Full step identifier
202
+ * @returns Object with name and optional version
203
+ */
204
+ function parseStepNameAndVersion(stepNameWithVersion) {
205
+ const atIndex = stepNameWithVersion.indexOf('@');
206
+ if (atIndex === -1) {
207
+ // No version specified
208
+ return { name: stepNameWithVersion };
209
+ }
210
+ const name = stepNameWithVersion.substring(0, atIndex);
211
+ const version = stepNameWithVersion.substring(atIndex + 1);
212
+ return { name, version };
213
+ }
214
+ /**
215
+ * Helper function to get available workflow names from a pipeline
216
+ * @param pipeline Parsed YAML pipeline
217
+ * @returns Array of workflow names
218
+ */
219
+ export function getAvailableWorkflows(pipeline) {
220
+ return Object.keys(pipeline.workflows);
221
+ }
222
+ //# sourceMappingURL=converter.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Unit tests for YAML to PipelineDef conversion with warning system
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=converter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converter.test.d.ts","sourceRoot":"","sources":["../../../src/yaml/converter.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Unit tests for YAML to PipelineDef conversion with warning system
3
+ */
4
+ import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
5
+ import { convertYAMLToPipelineDef, YAMLConversionError } from './converter.js';
6
+ import { clearRegistry, registerStep } from './steps/registry.js';
7
+ import { ScriptStepExecutor } from './steps/script.js';
8
+ import { CocoapodsInstallStepExecutor } from './steps/ios-deps.js';
9
+ describe('convertYAMLToPipelineDef - Warning System', () => {
10
+ let mockConfig;
11
+ beforeEach(() => {
12
+ // Clear registry before each test
13
+ clearRegistry();
14
+ // Register steps used in tests
15
+ registerStep('script', new ScriptStepExecutor());
16
+ registerStep('cocoapods-install', new CocoapodsInstallStepExecutor());
17
+ // Mock config
18
+ mockConfig = {
19
+ artifactsDir: '/test/artifacts',
20
+ maxConcurrentJobs: 1,
21
+ paths: {
22
+ buildsDir: '/test/builds',
23
+ cacheDir: '/test/cache',
24
+ derivedDataDir: '/test/derived-data',
25
+ },
26
+ interpreters: {
27
+ bash: '/bin/bash',
28
+ python: 'python3',
29
+ ruby: 'ruby',
30
+ node: 'node',
31
+ },
32
+ };
33
+ });
34
+ afterEach(() => {
35
+ // Clean up registry
36
+ clearRegistry();
37
+ });
38
+ describe('Unsupported step handling', () => {
39
+ test('should collect warnings for unsupported steps', async () => {
40
+ const pipeline = {
41
+ format_version: '4',
42
+ workflows: {
43
+ primary: {
44
+ steps: [
45
+ {
46
+ 'script@1.0.0': {
47
+ title: 'Valid step',
48
+ inputs: { content: 'echo "test"' },
49
+ },
50
+ },
51
+ {
52
+ 'unsupported-step@1.0.0': {
53
+ title: 'This step does not exist',
54
+ inputs: {},
55
+ },
56
+ },
57
+ {
58
+ 'another-unsupported@2.0.0': {
59
+ inputs: {},
60
+ },
61
+ },
62
+ ],
63
+ },
64
+ },
65
+ };
66
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
67
+ // Should have warnings
68
+ expect(result.warnings).toBeDefined();
69
+ expect(result.warnings.length).toBe(2);
70
+ // Should include step names with versions
71
+ expect(result.warnings[0]).toContain('unsupported-step@1.0.0');
72
+ expect(result.warnings[1]).toContain('another-unsupported@2.0.0');
73
+ // Should have warning symbol
74
+ expect(result.warnings[0]).toContain('⚠️');
75
+ expect(result.warnings[1]).toContain('⚠️');
76
+ // Should indicate skipping
77
+ expect(result.warnings[0]).toContain('skipping');
78
+ expect(result.warnings[1]).toContain('skipping');
79
+ // Should track skipped steps count
80
+ expect(result.skippedSteps).toBe(2);
81
+ // Pipeline should only contain the valid step
82
+ expect(result.pipeline.steps.length).toBe(1);
83
+ expect(result.pipeline.steps[0].name).toBe('Valid step');
84
+ });
85
+ test('should handle unsupported step without version', async () => {
86
+ const pipeline = {
87
+ format_version: '4',
88
+ workflows: {
89
+ primary: {
90
+ steps: [
91
+ {
92
+ 'unknown-step': {
93
+ title: 'No version specified',
94
+ inputs: {},
95
+ },
96
+ },
97
+ ],
98
+ },
99
+ },
100
+ };
101
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
102
+ expect(result.warnings.length).toBe(1);
103
+ expect(result.warnings[0]).toContain('unknown-step');
104
+ expect(result.warnings[0]).not.toContain('@');
105
+ expect(result.skippedSteps).toBe(1);
106
+ expect(result.pipeline.steps.length).toBe(0);
107
+ });
108
+ test('should return empty warnings for fully supported pipeline', async () => {
109
+ const pipeline = {
110
+ format_version: '4',
111
+ workflows: {
112
+ primary: {
113
+ steps: [
114
+ {
115
+ 'script@1.0.0': {
116
+ title: 'Step 1',
117
+ inputs: { content: 'echo "1"' },
118
+ },
119
+ },
120
+ {
121
+ 'script@1.0.0': {
122
+ title: 'Step 2',
123
+ inputs: { content: 'echo "2"' },
124
+ },
125
+ },
126
+ ],
127
+ },
128
+ },
129
+ };
130
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
131
+ expect(result.warnings).toBeDefined();
132
+ expect(result.warnings.length).toBe(0);
133
+ expect(result.skippedSteps).toBe(0);
134
+ expect(result.pipeline.steps.length).toBe(2);
135
+ });
136
+ });
137
+ describe('Step suggestions', () => {
138
+ test('should include suggestions for known unsupported steps', async () => {
139
+ const pipeline = {
140
+ format_version: '4',
141
+ workflows: {
142
+ primary: {
143
+ steps: [
144
+ {
145
+ 'npm@1.0.0': {
146
+ title: 'NPM step',
147
+ inputs: { command: 'install' },
148
+ },
149
+ },
150
+ ],
151
+ },
152
+ },
153
+ };
154
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
155
+ expect(result.warnings.length).toBe(1);
156
+ expect(result.warnings[0]).toContain('npm@1.0.0');
157
+ expect(result.warnings[0]).toContain('💡 Suggestion');
158
+ expect(result.warnings[0]).toContain('script step with npm commands');
159
+ });
160
+ test('should convert cocoapods-install as a supported step', async () => {
161
+ const pipeline = {
162
+ format_version: '4',
163
+ workflows: {
164
+ primary: {
165
+ steps: [
166
+ {
167
+ 'cocoapods-install@2.0.0': {
168
+ inputs: {},
169
+ },
170
+ },
171
+ ],
172
+ },
173
+ },
174
+ };
175
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
176
+ expect(result.warnings.length).toBe(0);
177
+ expect(result.skippedSteps).toBe(0);
178
+ expect(result.pipeline.steps.length).toBe(1);
179
+ });
180
+ test('should not include suggestions for unknown steps', async () => {
181
+ const pipeline = {
182
+ format_version: '4',
183
+ workflows: {
184
+ primary: {
185
+ steps: [
186
+ {
187
+ 'completely-unknown-step@1.0.0': {
188
+ inputs: {},
189
+ },
190
+ },
191
+ ],
192
+ },
193
+ },
194
+ };
195
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
196
+ expect(result.warnings.length).toBe(1);
197
+ expect(result.warnings[0]).toContain('completely-unknown-step@1.0.0');
198
+ expect(result.warnings[0]).not.toContain('💡 Suggestion');
199
+ });
200
+ });
201
+ describe('Mixed supported and unsupported steps', () => {
202
+ test('should process supported steps and warn about unsupported ones', async () => {
203
+ const pipeline = {
204
+ format_version: '4',
205
+ workflows: {
206
+ primary: {
207
+ steps: [
208
+ {
209
+ 'script@1.0.0': {
210
+ title: 'Step 1',
211
+ inputs: { content: 'echo "1"' },
212
+ },
213
+ },
214
+ {
215
+ 'unsupported-1@1.0.0': {
216
+ title: 'Unsupported 1',
217
+ inputs: {},
218
+ },
219
+ },
220
+ {
221
+ 'script@1.0.0': {
222
+ title: 'Step 2',
223
+ inputs: { content: 'echo "2"' },
224
+ },
225
+ },
226
+ {
227
+ 'unsupported-2@2.0.0': {
228
+ title: 'Unsupported 2',
229
+ inputs: {},
230
+ },
231
+ },
232
+ {
233
+ 'script@1.0.0': {
234
+ title: 'Step 3',
235
+ inputs: { content: 'echo "3"' },
236
+ },
237
+ },
238
+ ],
239
+ },
240
+ },
241
+ };
242
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
243
+ // Should have 2 warnings
244
+ expect(result.warnings.length).toBe(2);
245
+ expect(result.skippedSteps).toBe(2);
246
+ // Should have 3 valid steps
247
+ expect(result.pipeline.steps.length).toBe(3);
248
+ expect(result.pipeline.steps[0].name).toBe('Step 1');
249
+ expect(result.pipeline.steps[1].name).toBe('Step 2');
250
+ expect(result.pipeline.steps[2].name).toBe('Step 3');
251
+ // Step order should be preserved
252
+ expect(result.pipeline.stepsOrder.length).toBe(3);
253
+ });
254
+ test('should handle all unsupported steps', async () => {
255
+ const pipeline = {
256
+ format_version: '4',
257
+ workflows: {
258
+ primary: {
259
+ steps: [
260
+ {
261
+ 'unsupported-1@1.0.0': {
262
+ inputs: {},
263
+ },
264
+ },
265
+ {
266
+ 'unsupported-2@1.0.0': {
267
+ inputs: {},
268
+ },
269
+ },
270
+ {
271
+ 'unsupported-3@1.0.0': {
272
+ inputs: {},
273
+ },
274
+ },
275
+ ],
276
+ },
277
+ },
278
+ };
279
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
280
+ expect(result.warnings.length).toBe(3);
281
+ expect(result.skippedSteps).toBe(3);
282
+ expect(result.pipeline.steps.length).toBe(0);
283
+ });
284
+ });
285
+ describe('ConversionResult structure', () => {
286
+ test('should return valid ConversionResult structure', async () => {
287
+ const pipeline = {
288
+ format_version: '4',
289
+ workflows: {
290
+ primary: {
291
+ steps: [
292
+ {
293
+ 'script@1.0.0': {
294
+ inputs: { content: 'echo "test"' },
295
+ },
296
+ },
297
+ ],
298
+ },
299
+ },
300
+ };
301
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
302
+ // Should have all required properties
303
+ expect(result).toHaveProperty('pipeline');
304
+ expect(result).toHaveProperty('warnings');
305
+ expect(result).toHaveProperty('skippedSteps');
306
+ // Types should be correct
307
+ expect(Array.isArray(result.warnings)).toBe(true);
308
+ expect(typeof result.skippedSteps).toBe('number');
309
+ expect(result.pipeline).toHaveProperty('name');
310
+ expect(result.pipeline).toHaveProperty('steps');
311
+ expect(result.pipeline).toHaveProperty('stepsOrder');
312
+ });
313
+ });
314
+ describe('Error handling', () => {
315
+ test('should throw YAMLConversionError for invalid workflow name', async () => {
316
+ const pipeline = {
317
+ format_version: '4',
318
+ workflows: {
319
+ primary: {
320
+ steps: [],
321
+ },
322
+ },
323
+ };
324
+ await expect(convertYAMLToPipelineDef(pipeline, mockConfig, 'nonexistent')).rejects.toThrow(YAMLConversionError);
325
+ });
326
+ test('should not throw for unsupported steps (should warn instead)', async () => {
327
+ const pipeline = {
328
+ format_version: '4',
329
+ workflows: {
330
+ primary: {
331
+ steps: [
332
+ {
333
+ 'unsupported-step@1.0.0': {
334
+ inputs: {},
335
+ },
336
+ },
337
+ ],
338
+ },
339
+ },
340
+ };
341
+ // Should not throw, should return warnings instead
342
+ const result = await convertYAMLToPipelineDef(pipeline, mockConfig, 'primary');
343
+ expect(result.warnings.length).toBeGreaterThan(0);
344
+ expect(result.skippedSteps).toBeGreaterThan(0);
345
+ });
346
+ });
347
+ });
348
+ //# sourceMappingURL=converter.test.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * End-to-end integration tests for YAML pipelines
3
+ * Tests complete YAML pipeline loading and execution through CLI components
4
+ */
5
+ import './steps/index.js';
6
+ //# sourceMappingURL=e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e.test.d.ts","sourceRoot":"","sources":["../../../src/yaml/e2e.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,kBAAkB,CAAC"}