@aifabrix/builder 2.22.2 → 2.31.0
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/jest.config.coverage.js +37 -0
- package/lib/api/pipeline.api.js +10 -9
- package/lib/app-deploy.js +36 -14
- package/lib/app-list.js +191 -71
- package/lib/app-prompts.js +77 -26
- package/lib/app-readme.js +123 -5
- package/lib/app-rotate-secret.js +101 -57
- package/lib/app-run-helpers.js +200 -172
- package/lib/app-run.js +137 -68
- package/lib/audit-logger.js +8 -7
- package/lib/build.js +161 -250
- package/lib/cli.js +73 -65
- package/lib/commands/login.js +45 -31
- package/lib/commands/logout.js +181 -0
- package/lib/commands/secure.js +59 -24
- package/lib/config.js +79 -45
- package/lib/datasource-deploy.js +89 -29
- package/lib/deployer.js +164 -129
- package/lib/diff.js +63 -21
- package/lib/environment-deploy.js +36 -19
- package/lib/external-system-deploy.js +134 -66
- package/lib/external-system-download.js +244 -171
- package/lib/external-system-test.js +199 -164
- package/lib/generator-external.js +145 -72
- package/lib/generator-helpers.js +49 -17
- package/lib/generator-split.js +105 -58
- package/lib/infra.js +101 -131
- package/lib/schema/application-schema.json +895 -896
- package/lib/schema/env-config.yaml +11 -4
- package/lib/template-validator.js +13 -4
- package/lib/utils/api.js +8 -8
- package/lib/utils/app-register-auth.js +36 -18
- package/lib/utils/app-run-containers.js +140 -0
- package/lib/utils/auth-headers.js +6 -6
- package/lib/utils/build-copy.js +60 -2
- package/lib/utils/build-helpers.js +94 -0
- package/lib/utils/cli-utils.js +177 -76
- package/lib/utils/compose-generator.js +12 -2
- package/lib/utils/config-tokens.js +151 -9
- package/lib/utils/deployment-errors.js +137 -69
- package/lib/utils/deployment-validation-helpers.js +103 -0
- package/lib/utils/docker-build.js +57 -0
- package/lib/utils/dockerfile-utils.js +13 -3
- package/lib/utils/env-copy.js +163 -94
- package/lib/utils/env-map.js +226 -86
- package/lib/utils/error-formatters/network-errors.js +0 -1
- package/lib/utils/external-system-display.js +14 -19
- package/lib/utils/external-system-env-helpers.js +107 -0
- package/lib/utils/external-system-test-helpers.js +144 -0
- package/lib/utils/health-check.js +10 -8
- package/lib/utils/infra-status.js +123 -0
- package/lib/utils/paths.js +228 -49
- package/lib/utils/schema-loader.js +125 -57
- package/lib/utils/token-manager.js +3 -3
- package/lib/utils/yaml-preserve.js +55 -16
- package/lib/validate.js +87 -89
- package/package.json +4 -4
- package/scripts/ci-fix.sh +19 -0
- package/scripts/ci-simulate.sh +19 -0
- package/templates/applications/miso-controller/test.yaml +1 -0
- package/templates/python/Dockerfile.hbs +8 -45
- package/templates/typescript/Dockerfile.hbs +8 -42
|
@@ -81,38 +81,15 @@ async function generateExternalSystemDeployJson(appName, appPath) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
85
|
-
* Combines system and datasource JSONs into application-level deployment format
|
|
84
|
+
* Load system file and merge RBAC
|
|
86
85
|
* @async
|
|
87
|
-
* @
|
|
88
|
-
* @param {string}
|
|
89
|
-
* @
|
|
90
|
-
* @
|
|
86
|
+
* @param {string} appPath - Application path
|
|
87
|
+
* @param {string} schemaBasePath - Schema base path
|
|
88
|
+
* @param {string} systemFileName - System file name
|
|
89
|
+
* @returns {Promise<Object>} System JSON object
|
|
90
|
+
* @throws {Error} If file cannot be loaded
|
|
91
91
|
*/
|
|
92
|
-
async function
|
|
93
|
-
if (!appName || typeof appName !== 'string') {
|
|
94
|
-
throw new Error('App name is required and must be a string');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const { appPath } = await detectAppType(appName);
|
|
98
|
-
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
99
|
-
|
|
100
|
-
// Load variables.yaml
|
|
101
|
-
const { parsed: variables } = loadVariables(variablesPath);
|
|
102
|
-
|
|
103
|
-
if (!variables.externalIntegration) {
|
|
104
|
-
throw new Error('externalIntegration block not found in variables.yaml');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Load system file
|
|
108
|
-
const schemaBasePath = variables.externalIntegration.schemaBasePath || './';
|
|
109
|
-
const systemFiles = variables.externalIntegration.systems || [];
|
|
110
|
-
|
|
111
|
-
if (systemFiles.length === 0) {
|
|
112
|
-
throw new Error('No system files specified in externalIntegration.systems');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const systemFileName = systemFiles[0];
|
|
92
|
+
async function loadSystemFile(appPath, schemaBasePath, systemFileName) {
|
|
116
93
|
const systemFilePath = path.isAbsolute(schemaBasePath)
|
|
117
94
|
? path.join(schemaBasePath, systemFileName)
|
|
118
95
|
: path.join(appPath, schemaBasePath, systemFileName);
|
|
@@ -125,7 +102,6 @@ async function generateExternalSystemApplicationSchema(appName) {
|
|
|
125
102
|
const systemJson = JSON.parse(systemContent);
|
|
126
103
|
|
|
127
104
|
// Load rbac.yaml from app directory and merge if present
|
|
128
|
-
// Priority: roles/permissions in system JSON > rbac.yaml (if both exist, prefer JSON)
|
|
129
105
|
const rbacPath = path.join(appPath, 'rbac.yaml');
|
|
130
106
|
const rbac = loadRbac(rbacPath);
|
|
131
107
|
if (rbac) {
|
|
@@ -137,8 +113,19 @@ async function generateExternalSystemApplicationSchema(appName) {
|
|
|
137
113
|
}
|
|
138
114
|
}
|
|
139
115
|
|
|
140
|
-
|
|
141
|
-
|
|
116
|
+
return systemJson;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Load datasource files
|
|
121
|
+
* @async
|
|
122
|
+
* @param {string} appPath - Application path
|
|
123
|
+
* @param {string} schemaBasePath - Schema base path
|
|
124
|
+
* @param {Array<string>} datasourceFiles - Array of datasource file names
|
|
125
|
+
* @returns {Promise<Array<Object>>} Array of datasource JSON objects
|
|
126
|
+
* @throws {Error} If files cannot be loaded
|
|
127
|
+
*/
|
|
128
|
+
async function loadDatasourceFiles(appPath, schemaBasePath, datasourceFiles) {
|
|
142
129
|
const datasourceJsons = [];
|
|
143
130
|
|
|
144
131
|
for (const datasourceFile of datasourceFiles) {
|
|
@@ -155,69 +142,155 @@ async function generateExternalSystemApplicationSchema(appName) {
|
|
|
155
142
|
datasourceJsons.push(datasourceJson);
|
|
156
143
|
}
|
|
157
144
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
145
|
+
return datasourceJsons;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build base application schema structure
|
|
150
|
+
* @param {Object} systemJson - System JSON object
|
|
151
|
+
* @param {Array<Object>} datasourceJsons - Array of datasource JSON objects
|
|
152
|
+
* @param {string} version - Schema version
|
|
153
|
+
* @returns {Object} Application schema object
|
|
154
|
+
*/
|
|
155
|
+
function buildBaseSchema(systemJson, datasourceJsons, version) {
|
|
156
|
+
return {
|
|
157
|
+
version: version || '1.0.0',
|
|
161
158
|
application: systemJson,
|
|
162
159
|
dataSources: datasourceJsons
|
|
163
160
|
};
|
|
161
|
+
}
|
|
164
162
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Filter validation errors to handle schema inconsistencies
|
|
165
|
+
* @param {Array} errors - Validation errors
|
|
166
|
+
* @param {Object} schema - Schema object
|
|
167
|
+
* @returns {Array} Filtered errors
|
|
168
|
+
*/
|
|
169
|
+
function filterValidationErrors(errors, schema) {
|
|
170
|
+
return errors.filter(err => {
|
|
171
|
+
if (err.keyword === 'additionalProperties' && err.params?.additionalProperty === 'authentication') {
|
|
172
|
+
const required = schema.required || [];
|
|
173
|
+
if (required.includes('authentication')) {
|
|
174
|
+
return false; // Ignore this error since authentication is required but not defined
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
174
180
|
|
|
175
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Format validation errors for display
|
|
183
|
+
* @param {Array} errors - Validation errors
|
|
184
|
+
* @returns {string} Formatted error message
|
|
185
|
+
*/
|
|
186
|
+
function formatValidationErrors(errors) {
|
|
187
|
+
return errors.map(err => {
|
|
188
|
+
const path = err.instancePath || err.schemaPath;
|
|
189
|
+
return `${path} ${err.message}`;
|
|
190
|
+
}).join(', ');
|
|
191
|
+
}
|
|
176
192
|
|
|
177
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Validate system against external-system schema
|
|
195
|
+
* @param {Object} systemJson - System JSON object
|
|
196
|
+
* @param {Object} externalSystemSchema - External system schema
|
|
197
|
+
* @param {Object} ajv - AJV instance
|
|
198
|
+
* @throws {Error} If validation fails
|
|
199
|
+
*/
|
|
200
|
+
function validateSystemSchema(systemJson, externalSystemSchema, ajv) {
|
|
178
201
|
const externalSystemSchemaId = externalSystemSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-system.schema.json';
|
|
179
202
|
ajv.addSchema(externalSystemSchema, externalSystemSchemaId);
|
|
180
203
|
const validateSystem = ajv.compile(externalSystemSchema);
|
|
181
204
|
const systemValid = validateSystem(systemJson);
|
|
182
205
|
|
|
183
206
|
if (!systemValid) {
|
|
184
|
-
|
|
185
|
-
// This handles schema inconsistencies where authentication is required but not defined in properties
|
|
186
|
-
const filteredErrors = validateSystem.errors.filter(err => {
|
|
187
|
-
if (err.keyword === 'additionalProperties' && err.params?.additionalProperty === 'authentication') {
|
|
188
|
-
// Check if authentication is in required array
|
|
189
|
-
const required = externalSystemSchema.required || [];
|
|
190
|
-
if (required.includes('authentication')) {
|
|
191
|
-
return false; // Ignore this error since authentication is required but not defined
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return true;
|
|
195
|
-
});
|
|
196
|
-
|
|
207
|
+
const filteredErrors = filterValidationErrors(validateSystem.errors, externalSystemSchema);
|
|
197
208
|
if (filteredErrors.length > 0) {
|
|
198
|
-
const errors = filteredErrors
|
|
199
|
-
const path = err.instancePath || err.schemaPath;
|
|
200
|
-
return `${path} ${err.message}`;
|
|
201
|
-
}).join(', ');
|
|
209
|
+
const errors = formatValidationErrors(filteredErrors);
|
|
202
210
|
throw new Error(`System JSON does not match external-system schema: ${errors}`);
|
|
203
211
|
}
|
|
204
212
|
}
|
|
213
|
+
}
|
|
205
214
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Validate datasources against external-datasource schema
|
|
217
|
+
* @param {Array<Object>} datasourceJsons - Array of datasource JSON objects
|
|
218
|
+
* @param {Object} externalDatasourceSchema - External datasource schema
|
|
219
|
+
* @param {Object} ajv - AJV instance
|
|
220
|
+
* @throws {Error} If validation fails
|
|
221
|
+
*/
|
|
222
|
+
function validateDatasourceSchemas(datasourceJsons, externalDatasourceSchema, ajv) {
|
|
223
|
+
const externalDatasourceSchemaId = externalDatasourceSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-datasource.schema.json';
|
|
224
|
+
ajv.addSchema(externalDatasourceSchema, externalDatasourceSchemaId);
|
|
225
|
+
const validateDatasource = ajv.compile(externalDatasourceSchema);
|
|
210
226
|
|
|
211
227
|
for (let i = 0; i < datasourceJsons.length; i++) {
|
|
212
228
|
const datasourceValid = validateDatasource(datasourceJsons[i]);
|
|
213
229
|
if (!datasourceValid) {
|
|
214
|
-
const errors = validateDatasource.errors
|
|
215
|
-
const path = err.instancePath || err.schemaPath;
|
|
216
|
-
return `${path} ${err.message}`;
|
|
217
|
-
}).join(', ');
|
|
230
|
+
const errors = formatValidationErrors(validateDatasource.errors);
|
|
218
231
|
throw new Error(`Datasource ${i + 1} (${datasourceJsons[i].key || 'unknown'}) does not match external-datasource schema: ${errors}`);
|
|
219
232
|
}
|
|
220
233
|
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Generates application-schema.json structure for external systems
|
|
238
|
+
* Combines system and datasource JSONs into application-level deployment format
|
|
239
|
+
* @async
|
|
240
|
+
* @function generateExternalSystemApplicationSchema
|
|
241
|
+
* @param {string} appName - Application name
|
|
242
|
+
* @returns {Promise<Object>} Application schema object
|
|
243
|
+
* @throws {Error} If generation fails
|
|
244
|
+
*/
|
|
245
|
+
async function generateExternalSystemApplicationSchema(appName) {
|
|
246
|
+
if (!appName || typeof appName !== 'string') {
|
|
247
|
+
throw new Error('App name is required and must be a string');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const { appPath } = await detectAppType(appName);
|
|
251
|
+
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
252
|
+
|
|
253
|
+
// Load variables.yaml
|
|
254
|
+
const { parsed: variables } = loadVariables(variablesPath);
|
|
255
|
+
|
|
256
|
+
if (!variables.externalIntegration) {
|
|
257
|
+
throw new Error('externalIntegration block not found in variables.yaml');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Load system file and merge RBAC
|
|
261
|
+
const schemaBasePath = variables.externalIntegration.schemaBasePath || './';
|
|
262
|
+
const systemFiles = variables.externalIntegration.systems || [];
|
|
263
|
+
|
|
264
|
+
if (systemFiles.length === 0) {
|
|
265
|
+
throw new Error('No system files specified in externalIntegration.systems');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const systemJson = await loadSystemFile(appPath, schemaBasePath, systemFiles[0]);
|
|
269
|
+
|
|
270
|
+
// Load datasource files
|
|
271
|
+
const datasourceFiles = variables.externalIntegration.dataSources || [];
|
|
272
|
+
const datasourceJsons = await loadDatasourceFiles(appPath, schemaBasePath, datasourceFiles);
|
|
273
|
+
|
|
274
|
+
// Build application-schema.json structure
|
|
275
|
+
const applicationSchema = buildBaseSchema(systemJson, datasourceJsons, variables.externalIntegration.version);
|
|
276
|
+
|
|
277
|
+
// Validate individual components against their schemas
|
|
278
|
+
const externalSystemSchema = require('./schema/external-system.schema.json');
|
|
279
|
+
const externalDatasourceSchema = require('./schema/external-datasource.schema.json');
|
|
280
|
+
|
|
281
|
+
// For draft-2020-12 schemas, remove $schema to avoid AJV issues
|
|
282
|
+
const datasourceSchemaToAdd = { ...externalDatasourceSchema };
|
|
283
|
+
if (datasourceSchemaToAdd.$schema && datasourceSchemaToAdd.$schema.includes('2020-12')) {
|
|
284
|
+
delete datasourceSchemaToAdd.$schema;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const ajv = new Ajv({ allErrors: true, strict: false, removeAdditional: false });
|
|
288
|
+
|
|
289
|
+
// Validate system against external-system schema
|
|
290
|
+
validateSystemSchema(systemJson, externalSystemSchema, ajv);
|
|
291
|
+
|
|
292
|
+
// Validate datasources against external-datasource schema
|
|
293
|
+
validateDatasourceSchemas(datasourceJsons, datasourceSchemaToAdd, ajv);
|
|
221
294
|
|
|
222
295
|
return applicationSchema;
|
|
223
296
|
}
|
package/lib/generator-helpers.js
CHANGED
|
@@ -63,17 +63,12 @@ function loadRbac(rbacPath) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
* @param {Object} portalInput - Portal input configuration
|
|
66
|
+
* Validate required fields in portalInput
|
|
67
|
+
* @param {Object} portalInput - Portal input configuration
|
|
68
68
|
* @param {string} variableName - Variable name for error messages
|
|
69
|
-
* @throws {Error} If
|
|
69
|
+
* @throws {Error} If required fields are missing
|
|
70
70
|
*/
|
|
71
|
-
function
|
|
72
|
-
if (!portalInput || typeof portalInput !== 'object') {
|
|
73
|
-
throw new Error(`Invalid portalInput for variable '${variableName}': must be an object`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Check required fields
|
|
71
|
+
function validateRequiredFields(portalInput, variableName) {
|
|
77
72
|
if (!portalInput.field || typeof portalInput.field !== 'string') {
|
|
78
73
|
throw new Error(`Invalid portalInput for variable '${variableName}': field is required and must be a string`);
|
|
79
74
|
}
|
|
@@ -81,21 +76,48 @@ function validatePortalInput(portalInput, variableName) {
|
|
|
81
76
|
if (!portalInput.label || typeof portalInput.label !== 'string') {
|
|
82
77
|
throw new Error(`Invalid portalInput for variable '${variableName}': label is required and must be a string`);
|
|
83
78
|
}
|
|
79
|
+
}
|
|
84
80
|
|
|
85
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Validate field type in portalInput
|
|
83
|
+
* @param {Object} portalInput - Portal input configuration
|
|
84
|
+
* @param {string} variableName - Variable name for error messages
|
|
85
|
+
* @throws {Error} If field type is invalid
|
|
86
|
+
*/
|
|
87
|
+
function validateFieldType(portalInput, variableName) {
|
|
86
88
|
const validFieldTypes = ['password', 'text', 'textarea', 'select'];
|
|
87
89
|
if (!validFieldTypes.includes(portalInput.field)) {
|
|
88
90
|
throw new Error(`Invalid portalInput for variable '${variableName}': field must be one of: ${validFieldTypes.join(', ')}`);
|
|
89
91
|
}
|
|
92
|
+
}
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Validate select field options
|
|
96
|
+
* @param {Object} portalInput - Portal input configuration
|
|
97
|
+
* @param {string} variableName - Variable name for error messages
|
|
98
|
+
* @throws {Error} If select field options are invalid
|
|
99
|
+
*/
|
|
100
|
+
function validateSelectFieldOptions(portalInput, variableName) {
|
|
92
101
|
if (portalInput.field === 'select') {
|
|
93
102
|
if (!portalInput.options || !Array.isArray(portalInput.options) || portalInput.options.length === 0) {
|
|
94
103
|
throw new Error(`Invalid portalInput for variable '${variableName}': select field requires a non-empty options array`);
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
|
|
107
|
+
if (portalInput.options !== undefined && portalInput.field !== 'select') {
|
|
108
|
+
if (Array.isArray(portalInput.options) && portalInput.options.length > 0) {
|
|
109
|
+
throw new Error(`Invalid portalInput for variable '${variableName}': options can only be used with select field type`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validate optional fields in portalInput
|
|
116
|
+
* @param {Object} portalInput - Portal input configuration
|
|
117
|
+
* @param {string} variableName - Variable name for error messages
|
|
118
|
+
* @throws {Error} If optional fields are invalid
|
|
119
|
+
*/
|
|
120
|
+
function validateOptionalFields(portalInput, variableName) {
|
|
99
121
|
if (portalInput.placeholder !== undefined && typeof portalInput.placeholder !== 'string') {
|
|
100
122
|
throw new Error(`Invalid portalInput for variable '${variableName}': placeholder must be a string`);
|
|
101
123
|
}
|
|
@@ -109,13 +131,23 @@ function validatePortalInput(portalInput, variableName) {
|
|
|
109
131
|
throw new Error(`Invalid portalInput for variable '${variableName}': validation must be an object`);
|
|
110
132
|
}
|
|
111
133
|
}
|
|
134
|
+
}
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Validates portalInput structure against schema requirements
|
|
138
|
+
* @param {Object} portalInput - Portal input configuration to validate
|
|
139
|
+
* @param {string} variableName - Variable name for error messages
|
|
140
|
+
* @throws {Error} If portalInput structure is invalid
|
|
141
|
+
*/
|
|
142
|
+
function validatePortalInput(portalInput, variableName) {
|
|
143
|
+
if (!portalInput || typeof portalInput !== 'object') {
|
|
144
|
+
throw new Error(`Invalid portalInput for variable '${variableName}': must be an object`);
|
|
118
145
|
}
|
|
146
|
+
|
|
147
|
+
validateRequiredFields(portalInput, variableName);
|
|
148
|
+
validateFieldType(portalInput, variableName);
|
|
149
|
+
validateSelectFieldOptions(portalInput, variableName);
|
|
150
|
+
validateOptionalFields(portalInput, variableName);
|
|
119
151
|
}
|
|
120
152
|
|
|
121
153
|
/**
|
package/lib/generator-split.js
CHANGED
|
@@ -84,98 +84,145 @@ function parseImageReference(imageString) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
88
|
-
* @function extractVariablesYaml
|
|
87
|
+
* Extract app section from deployment
|
|
89
88
|
* @param {Object} deployment - Deployment JSON object
|
|
90
|
-
* @returns {Object}
|
|
89
|
+
* @returns {Object|undefined} App section or undefined
|
|
91
90
|
*/
|
|
92
|
-
function
|
|
93
|
-
if (!deployment
|
|
94
|
-
|
|
91
|
+
function extractAppSection(deployment) {
|
|
92
|
+
if (!deployment.key && !deployment.displayName && !deployment.description && !deployment.type) {
|
|
93
|
+
return undefined;
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
const
|
|
96
|
+
const app = {};
|
|
97
|
+
if (deployment.key) app.key = deployment.key;
|
|
98
|
+
if (deployment.displayName) app.displayName = deployment.displayName;
|
|
99
|
+
if (deployment.description) app.description = deployment.description;
|
|
100
|
+
if (deployment.type) app.type = deployment.type;
|
|
101
|
+
return app;
|
|
102
|
+
}
|
|
98
103
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Extract image section from deployment
|
|
106
|
+
* @param {Object} deployment - Deployment JSON object
|
|
107
|
+
* @returns {Object|undefined} Image section or undefined
|
|
108
|
+
*/
|
|
109
|
+
function extractImageSection(deployment) {
|
|
110
|
+
if (!deployment.image) {
|
|
111
|
+
return undefined;
|
|
106
112
|
}
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
114
|
+
const imageParts = parseImageReference(deployment.image);
|
|
115
|
+
const image = {};
|
|
116
|
+
if (imageParts.name) image.name = imageParts.name;
|
|
117
|
+
if (imageParts.registry) image.registry = imageParts.registry;
|
|
118
|
+
if (imageParts.tag) image.tag = imageParts.tag;
|
|
119
|
+
if (deployment.registryMode) image.registryMode = deployment.registryMode;
|
|
120
|
+
return image;
|
|
121
|
+
}
|
|
117
122
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Extract requirements section from deployment
|
|
125
|
+
* @param {Object} deployment - Deployment JSON object
|
|
126
|
+
* @returns {Object|undefined} Requirements section or undefined
|
|
127
|
+
*/
|
|
128
|
+
function extractRequirementsSection(deployment) {
|
|
129
|
+
if (!deployment.requiresDatabase && !deployment.requiresRedis && !deployment.requiresStorage && !deployment.databases) {
|
|
130
|
+
return undefined;
|
|
121
131
|
}
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
if (deployment.requiresDatabase
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
const requires = {};
|
|
134
|
+
if (deployment.requiresDatabase !== undefined) requires.database = deployment.requiresDatabase;
|
|
135
|
+
if (deployment.requiresRedis !== undefined) requires.redis = deployment.requiresRedis;
|
|
136
|
+
if (deployment.requiresStorage !== undefined) requires.storage = deployment.requiresStorage;
|
|
137
|
+
if (deployment.databases) requires.databases = deployment.databases;
|
|
138
|
+
return requires;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Extract optional sections from deployment
|
|
143
|
+
* @param {Object} deployment - Deployment JSON object
|
|
144
|
+
* @returns {Object} Object with optional sections
|
|
145
|
+
*/
|
|
146
|
+
function extractOptionalSections(deployment) {
|
|
147
|
+
const optional = {};
|
|
131
148
|
|
|
132
|
-
// Extract healthCheck
|
|
133
149
|
if (deployment.healthCheck) {
|
|
134
|
-
|
|
150
|
+
optional.healthCheck = deployment.healthCheck;
|
|
135
151
|
}
|
|
136
|
-
|
|
137
|
-
// Extract authentication
|
|
138
152
|
if (deployment.authentication) {
|
|
139
|
-
|
|
153
|
+
optional.authentication = { ...deployment.authentication };
|
|
140
154
|
}
|
|
141
|
-
|
|
142
|
-
// Extract build
|
|
143
155
|
if (deployment.build) {
|
|
144
|
-
|
|
156
|
+
optional.build = deployment.build;
|
|
145
157
|
}
|
|
146
|
-
|
|
147
|
-
// Extract repository
|
|
148
158
|
if (deployment.repository) {
|
|
149
|
-
|
|
159
|
+
optional.repository = deployment.repository;
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
// Extract deployment config
|
|
153
161
|
if (deployment.deployment) {
|
|
154
|
-
|
|
162
|
+
optional.deployment = deployment.deployment;
|
|
155
163
|
}
|
|
156
|
-
|
|
157
|
-
// Extract other optional fields
|
|
158
164
|
if (deployment.startupCommand) {
|
|
159
|
-
|
|
165
|
+
optional.startupCommand = deployment.startupCommand;
|
|
160
166
|
}
|
|
161
167
|
if (deployment.runtimeVersion) {
|
|
162
|
-
|
|
168
|
+
optional.runtimeVersion = deployment.runtimeVersion;
|
|
163
169
|
}
|
|
164
170
|
if (deployment.scaling) {
|
|
165
|
-
|
|
171
|
+
optional.scaling = deployment.scaling;
|
|
166
172
|
}
|
|
167
173
|
if (deployment.frontDoorRouting) {
|
|
168
|
-
|
|
174
|
+
optional.frontDoorRouting = deployment.frontDoorRouting;
|
|
169
175
|
}
|
|
170
|
-
|
|
171
|
-
// Extract roles and permissions (if present)
|
|
172
176
|
if (deployment.roles) {
|
|
173
|
-
|
|
177
|
+
optional.roles = deployment.roles;
|
|
174
178
|
}
|
|
175
179
|
if (deployment.permissions) {
|
|
176
|
-
|
|
180
|
+
optional.permissions = deployment.permissions;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return optional;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Extracts deployment JSON into variables.yaml structure
|
|
188
|
+
* @function extractVariablesYaml
|
|
189
|
+
* @param {Object} deployment - Deployment JSON object
|
|
190
|
+
* @returns {Object} Variables YAML structure
|
|
191
|
+
*/
|
|
192
|
+
function extractVariablesYaml(deployment) {
|
|
193
|
+
if (!deployment || typeof deployment !== 'object') {
|
|
194
|
+
throw new Error('Deployment object is required');
|
|
177
195
|
}
|
|
178
196
|
|
|
197
|
+
const variables = {};
|
|
198
|
+
|
|
199
|
+
// Extract app section
|
|
200
|
+
const appSection = extractAppSection(deployment);
|
|
201
|
+
if (appSection) {
|
|
202
|
+
variables.app = appSection;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Extract image section
|
|
206
|
+
const imageSection = extractImageSection(deployment);
|
|
207
|
+
if (imageSection) {
|
|
208
|
+
variables.image = imageSection;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Extract port
|
|
212
|
+
if (deployment.port !== undefined) {
|
|
213
|
+
variables.port = deployment.port;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Extract requirements section
|
|
217
|
+
const requirementsSection = extractRequirementsSection(deployment);
|
|
218
|
+
if (requirementsSection) {
|
|
219
|
+
variables.requires = requirementsSection;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Extract optional sections
|
|
223
|
+
const optionalSections = extractOptionalSections(deployment);
|
|
224
|
+
Object.assign(variables, optionalSections);
|
|
225
|
+
|
|
179
226
|
return variables;
|
|
180
227
|
}
|
|
181
228
|
|