@invarn/cibuild 1.3.16 → 1.3.18
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.
- package/dist/cli.cjs +1 -1
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +987 -0
- package/dist/src/commands/android-scanner.d.ts +32 -0
- package/dist/src/commands/android-scanner.d.ts.map +1 -0
- package/dist/src/commands/android-scanner.js +667 -0
- package/dist/src/commands/build.d.ts +5 -0
- package/dist/src/commands/build.d.ts.map +1 -0
- package/dist/src/commands/build.js +1096 -0
- package/dist/src/commands/edit.d.ts +3 -0
- package/dist/src/commands/edit.d.ts.map +1 -0
- package/dist/src/commands/edit.js +651 -0
- package/dist/src/commands/file-secret-collector.d.ts +37 -0
- package/dist/src/commands/file-secret-collector.d.ts.map +1 -0
- package/dist/src/commands/file-secret-collector.js +199 -0
- package/dist/src/commands/github-workflow.d.ts +5 -0
- package/dist/src/commands/github-workflow.d.ts.map +1 -0
- package/dist/src/commands/github-workflow.js +45 -0
- package/dist/src/commands/ios-scanner.d.ts +27 -0
- package/dist/src/commands/ios-scanner.d.ts.map +1 -0
- package/dist/src/commands/ios-scanner.js +337 -0
- package/dist/src/commands/reset.d.ts +7 -0
- package/dist/src/commands/reset.d.ts.map +1 -0
- package/dist/src/commands/reset.js +81 -0
- package/dist/src/commands/secrets-sync-workflow.d.ts +15 -0
- package/dist/src/commands/secrets-sync-workflow.d.ts.map +1 -0
- package/dist/src/commands/secrets-sync-workflow.js +255 -0
- package/dist/src/commands/secrets-upload.d.ts +21 -0
- package/dist/src/commands/secrets-upload.d.ts.map +1 -0
- package/dist/src/commands/secrets-upload.js +177 -0
- package/dist/src/commands/secrets-upload.test.d.ts +5 -0
- package/dist/src/commands/secrets-upload.test.d.ts.map +1 -0
- package/dist/src/commands/secrets-upload.test.js +60 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +47 -0
- package/dist/src/envman/cli.d.ts +21 -0
- package/dist/src/envman/cli.d.ts.map +1 -0
- package/dist/src/envman/cli.js +240 -0
- package/dist/src/envman/envman.d.ts +83 -0
- package/dist/src/envman/envman.d.ts.map +1 -0
- package/dist/src/envman/envman.js +361 -0
- package/dist/src/envman/envman.test.d.ts +5 -0
- package/dist/src/envman/envman.test.d.ts.map +1 -0
- package/dist/src/envman/envman.test.js +236 -0
- package/dist/src/envman/index.d.ts +23 -0
- package/dist/src/envman/index.d.ts.map +1 -0
- package/dist/src/envman/index.js +23 -0
- package/dist/src/envman/types.d.ts +55 -0
- package/dist/src/envman/types.d.ts.map +1 -0
- package/dist/src/envman/types.js +12 -0
- package/dist/src/lib.d.ts +27 -0
- package/dist/src/lib.d.ts.map +1 -0
- package/dist/src/lib.js +32 -0
- package/dist/src/pipeline.d.ts +3 -0
- package/dist/src/pipeline.d.ts.map +1 -0
- package/dist/src/pipeline.js +57 -0
- package/dist/src/runner.d.ts +17 -0
- package/dist/src/runner.d.ts.map +1 -0
- package/dist/src/runner.js +234 -0
- package/dist/src/types.d.ts +58 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/yaml/bitrise-compat.d.ts +65 -0
- package/dist/src/yaml/bitrise-compat.d.ts.map +1 -0
- package/dist/src/yaml/bitrise-compat.js +206 -0
- package/dist/src/yaml/bitrise-compat.test.d.ts +5 -0
- package/dist/src/yaml/bitrise-compat.test.d.ts.map +1 -0
- package/dist/src/yaml/bitrise-compat.test.js +347 -0
- package/dist/src/yaml/converter.d.ts +33 -0
- package/dist/src/yaml/converter.d.ts.map +1 -0
- package/dist/src/yaml/converter.js +222 -0
- package/dist/src/yaml/converter.test.d.ts +5 -0
- package/dist/src/yaml/converter.test.d.ts.map +1 -0
- package/dist/src/yaml/converter.test.js +348 -0
- package/dist/src/yaml/e2e.test.d.ts +6 -0
- package/dist/src/yaml/e2e.test.d.ts.map +1 -0
- package/dist/src/yaml/e2e.test.js +446 -0
- package/dist/src/yaml/env-resolver.d.ts +120 -0
- package/dist/src/yaml/env-resolver.d.ts.map +1 -0
- package/dist/src/yaml/env-resolver.js +405 -0
- package/dist/src/yaml/env-resolver.test.d.ts +5 -0
- package/dist/src/yaml/env-resolver.test.d.ts.map +1 -0
- package/dist/src/yaml/env-resolver.test.js +502 -0
- package/dist/src/yaml/interactive-prompts.d.ts +71 -0
- package/dist/src/yaml/interactive-prompts.d.ts.map +1 -0
- package/dist/src/yaml/interactive-prompts.js +258 -0
- package/dist/src/yaml/missing-env-handler.d.ts +45 -0
- package/dist/src/yaml/missing-env-handler.d.ts.map +1 -0
- package/dist/src/yaml/missing-env-handler.js +64 -0
- package/dist/src/yaml/parser.d.ts +33 -0
- package/dist/src/yaml/parser.d.ts.map +1 -0
- package/dist/src/yaml/parser.js +145 -0
- package/dist/src/yaml/pipeline-with-secrets.d.ts +25 -0
- package/dist/src/yaml/pipeline-with-secrets.d.ts.map +1 -0
- package/dist/src/yaml/pipeline-with-secrets.js +76 -0
- package/dist/src/yaml/platform-detector.d.ts +83 -0
- package/dist/src/yaml/platform-detector.d.ts.map +1 -0
- package/dist/src/yaml/platform-detector.js +188 -0
- package/dist/src/yaml/platform-detector.test.d.ts +5 -0
- package/dist/src/yaml/platform-detector.test.d.ts.map +1 -0
- package/dist/src/yaml/platform-detector.test.js +414 -0
- package/dist/src/yaml/preflight-validation.d.ts +40 -0
- package/dist/src/yaml/preflight-validation.d.ts.map +1 -0
- package/dist/src/yaml/preflight-validation.js +152 -0
- package/dist/src/yaml/secrets-manager.d.ts +77 -0
- package/dist/src/yaml/secrets-manager.d.ts.map +1 -0
- package/dist/src/yaml/secrets-manager.js +219 -0
- package/dist/src/yaml/step-validator.d.ts +54 -0
- package/dist/src/yaml/step-validator.d.ts.map +1 -0
- package/dist/src/yaml/step-validator.js +403 -0
- package/dist/src/yaml/steps/android-sign.d.ts +35 -0
- package/dist/src/yaml/steps/android-sign.d.ts.map +1 -0
- package/dist/src/yaml/steps/android-sign.js +147 -0
- package/dist/src/yaml/steps/android-version.d.ts +26 -0
- package/dist/src/yaml/steps/android-version.d.ts.map +1 -0
- package/dist/src/yaml/steps/android-version.js +128 -0
- package/dist/src/yaml/steps/android-version.test.d.ts +5 -0
- package/dist/src/yaml/steps/android-version.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/android-version.test.js +196 -0
- package/dist/src/yaml/steps/android.d.ts +95 -0
- package/dist/src/yaml/steps/android.d.ts.map +1 -0
- package/dist/src/yaml/steps/android.js +916 -0
- package/dist/src/yaml/steps/app-store-deploy.d.ts +48 -0
- package/dist/src/yaml/steps/app-store-deploy.d.ts.map +1 -0
- package/dist/src/yaml/steps/app-store-deploy.js +162 -0
- package/dist/src/yaml/steps/base.d.ts +238 -0
- package/dist/src/yaml/steps/base.d.ts.map +1 -0
- package/dist/src/yaml/steps/base.js +345 -0
- package/dist/src/yaml/steps/bitrise-android-tools.d.ts +26 -0
- package/dist/src/yaml/steps/bitrise-android-tools.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-android-tools.js +198 -0
- package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts +5 -0
- package/dist/src/yaml/steps/bitrise-android-tools.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-android-tools.test.js +280 -0
- package/dist/src/yaml/steps/bitrise-apk-info.d.ts +22 -0
- package/dist/src/yaml/steps/bitrise-apk-info.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-apk-info.js +144 -0
- package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts +5 -0
- package/dist/src/yaml/steps/bitrise-apk-info.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-apk-info.test.js +331 -0
- package/dist/src/yaml/steps/bitrise-slack.d.ts +49 -0
- package/dist/src/yaml/steps/bitrise-slack.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-slack.js +280 -0
- package/dist/src/yaml/steps/bitrise-slack.test.d.ts +5 -0
- package/dist/src/yaml/steps/bitrise-slack.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-slack.test.js +484 -0
- package/dist/src/yaml/steps/bitrise-ssh.d.ts +27 -0
- package/dist/src/yaml/steps/bitrise-ssh.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-ssh.js +134 -0
- package/dist/src/yaml/steps/bitrise-ssh.test.d.ts +5 -0
- package/dist/src/yaml/steps/bitrise-ssh.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/bitrise-ssh.test.js +205 -0
- package/dist/src/yaml/steps/cache.d.ts +52 -0
- package/dist/src/yaml/steps/cache.d.ts.map +1 -0
- package/dist/src/yaml/steps/cache.js +352 -0
- package/dist/src/yaml/steps/fastlane.d.ts +27 -0
- package/dist/src/yaml/steps/fastlane.d.ts.map +1 -0
- package/dist/src/yaml/steps/fastlane.js +79 -0
- package/dist/src/yaml/steps/file.d.ts +27 -0
- package/dist/src/yaml/steps/file.d.ts.map +1 -0
- package/dist/src/yaml/steps/file.js +35 -0
- package/dist/src/yaml/steps/flutter.d.ts +63 -0
- package/dist/src/yaml/steps/flutter.d.ts.map +1 -0
- package/dist/src/yaml/steps/flutter.js +215 -0
- package/dist/src/yaml/steps/git-clone.d.ts +26 -0
- package/dist/src/yaml/steps/git-clone.d.ts.map +1 -0
- package/dist/src/yaml/steps/git-clone.js +111 -0
- package/dist/src/yaml/steps/google-play-deploy.d.ts +37 -0
- package/dist/src/yaml/steps/google-play-deploy.d.ts.map +1 -0
- package/dist/src/yaml/steps/google-play-deploy.js +193 -0
- package/dist/src/yaml/steps/google-play-deploy.test.d.ts +5 -0
- package/dist/src/yaml/steps/google-play-deploy.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/google-play-deploy.test.js +310 -0
- package/dist/src/yaml/steps/index.d.ts +10 -0
- package/dist/src/yaml/steps/index.d.ts.map +1 -0
- package/dist/src/yaml/steps/index.js +1361 -0
- package/dist/src/yaml/steps/ios-deps.d.ts +43 -0
- package/dist/src/yaml/steps/ios-deps.d.ts.map +1 -0
- package/dist/src/yaml/steps/ios-deps.js +141 -0
- package/dist/src/yaml/steps/ios-deps.test.d.ts +5 -0
- package/dist/src/yaml/steps/ios-deps.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/ios-deps.test.js +90 -0
- package/dist/src/yaml/steps/ios-signing.d.ts +31 -0
- package/dist/src/yaml/steps/ios-signing.d.ts.map +1 -0
- package/dist/src/yaml/steps/ios-signing.js +144 -0
- package/dist/src/yaml/steps/ios-version.d.ts +47 -0
- package/dist/src/yaml/steps/ios-version.d.ts.map +1 -0
- package/dist/src/yaml/steps/ios-version.js +151 -0
- package/dist/src/yaml/steps/linting.d.ts +47 -0
- package/dist/src/yaml/steps/linting.d.ts.map +1 -0
- package/dist/src/yaml/steps/linting.js +148 -0
- package/dist/src/yaml/steps/phase2.test.d.ts +6 -0
- package/dist/src/yaml/steps/phase2.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/phase2.test.js +197 -0
- package/dist/src/yaml/steps/phase3.test.d.ts +5 -0
- package/dist/src/yaml/steps/phase3.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/phase3.test.js +144 -0
- package/dist/src/yaml/steps/phase4.test.d.ts +5 -0
- package/dist/src/yaml/steps/phase4.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/phase4.test.js +166 -0
- package/dist/src/yaml/steps/phase5.test.d.ts +6 -0
- package/dist/src/yaml/steps/phase5.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/phase5.test.js +263 -0
- package/dist/src/yaml/steps/registry.d.ts +88 -0
- package/dist/src/yaml/steps/registry.d.ts.map +1 -0
- package/dist/src/yaml/steps/registry.js +125 -0
- package/dist/src/yaml/steps/registry.test.d.ts +5 -0
- package/dist/src/yaml/steps/registry.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/registry.test.js +235 -0
- package/dist/src/yaml/steps/release.d.ts +50 -0
- package/dist/src/yaml/steps/release.d.ts.map +1 -0
- package/dist/src/yaml/steps/release.js +154 -0
- package/dist/src/yaml/steps/script.d.ts +23 -0
- package/dist/src/yaml/steps/script.d.ts.map +1 -0
- package/dist/src/yaml/steps/script.js +63 -0
- package/dist/src/yaml/steps/spec-validation.test.d.ts +6 -0
- package/dist/src/yaml/steps/spec-validation.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/spec-validation.test.js +130 -0
- package/dist/src/yaml/steps/steps.test.d.ts +6 -0
- package/dist/src/yaml/steps/steps.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/steps.test.js +505 -0
- package/dist/src/yaml/steps/test-config.d.ts +3 -0
- package/dist/src/yaml/steps/test-config.d.ts.map +1 -0
- package/dist/src/yaml/steps/test-config.js +17 -0
- package/dist/src/yaml/steps/xcode-new.test.d.ts +5 -0
- package/dist/src/yaml/steps/xcode-new.test.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode-new.test.js +211 -0
- package/dist/src/yaml/steps/xcode.d.ts +222 -0
- package/dist/src/yaml/steps/xcode.d.ts.map +1 -0
- package/dist/src/yaml/steps/xcode.js +999 -0
- package/dist/src/yaml/types.d.ts +68 -0
- package/dist/src/yaml/types.d.ts.map +1 -0
- package/dist/src/yaml/types.js +5 -0
- package/dist/src/yaml/validation-types.d.ts +96 -0
- package/dist/src/yaml/validation-types.d.ts.map +1 -0
- package/dist/src/yaml/validation-types.js +8 -0
- package/dist/src/yaml/yaml-updater.d.ts +24 -0
- package/dist/src/yaml/yaml-updater.d.ts.map +1 -0
- package/dist/src/yaml/yaml-updater.js +128 -0
- 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 @@
|
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"e2e.test.d.ts","sourceRoot":"","sources":["../../../src/yaml/e2e.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,kBAAkB,CAAC"}
|