@aifabrix/builder 2.39.3 → 2.40.2
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/.cursor/rules/project-rules.mdc +6 -6
- package/README.md +3 -3
- package/babel.config.js +6 -0
- package/integration/hubspot/README.md +53 -141
- package/integration/hubspot/application.yaml +37 -0
- package/integration/hubspot/env.template +2 -11
- package/integration/hubspot/hubspot-deploy.json +1 -0
- package/integration/hubspot/test.js +5 -5
- package/jest.config.manual.js +29 -0
- package/lib/api/credentials.api.js +5 -5
- package/lib/api/deployments.api.js +2 -2
- package/lib/api/pipeline.api.js +17 -17
- package/lib/api/wizard.api.js +2 -2
- package/lib/app/config.js +11 -6
- package/lib/app/deploy-config.js +13 -16
- package/lib/app/deploy.js +29 -22
- package/lib/app/display.js +1 -1
- package/lib/app/dockerfile.js +11 -12
- package/lib/app/helpers.js +51 -13
- package/lib/app/index.js +14 -2
- package/lib/app/prompts.js +37 -45
- package/lib/app/push.js +8 -11
- package/lib/app/readme.js +16 -12
- package/lib/app/register.js +1 -1
- package/lib/app/run-helpers.js +31 -22
- package/lib/app/run.js +44 -5
- package/lib/app/show-display.js +104 -44
- package/lib/app/show.js +123 -43
- package/lib/build/index.js +11 -18
- package/lib/cli/setup-app.js +36 -29
- package/lib/cli/setup-auth.js +19 -15
- package/lib/cli/setup-credential-deployment.js +3 -1
- package/lib/cli/setup-external-system.js +35 -16
- package/lib/cli/setup-infra.js +45 -23
- package/lib/cli/setup-utility.js +85 -31
- package/lib/commands/app-logs.js +28 -20
- package/lib/commands/app.js +30 -26
- package/lib/commands/auth-status.js +36 -3
- package/lib/commands/convert.js +202 -0
- package/lib/commands/credential-list.js +78 -17
- package/lib/commands/datasource.js +24 -24
- package/lib/commands/deployment-list.js +13 -6
- package/lib/commands/up-common.js +80 -42
- package/lib/commands/up-dataplane.js +15 -14
- package/lib/commands/up-miso.js +15 -14
- package/lib/commands/upload.js +163 -0
- package/lib/commands/wizard-core.js +5 -4
- package/lib/core/diff.js +84 -9
- package/lib/core/key-generator.js +9 -12
- package/lib/core/secrets-docker-env.js +2 -2
- package/lib/core/secrets.js +3 -2
- package/lib/core/templates.js +2 -2
- package/lib/datasource/deploy.js +2 -1
- package/lib/deployment/deployer.js +76 -48
- package/lib/external-system/delete.js +0 -1
- package/lib/external-system/deploy-helpers.js +5 -6
- package/lib/external-system/deploy.js +7 -2
- package/lib/external-system/download-helpers.js +4 -4
- package/lib/external-system/download.js +11 -10
- package/lib/external-system/generator.js +19 -17
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +1 -1
- package/lib/generator/external-controller-manifest.js +26 -29
- package/lib/generator/external-schema-utils.js +6 -18
- package/lib/generator/external.js +32 -27
- package/lib/generator/github.js +1 -1
- package/lib/generator/helpers.js +12 -19
- package/lib/generator/index.js +15 -15
- package/lib/generator/parse-image.js +35 -0
- package/lib/generator/split-readme.js +105 -0
- package/lib/generator/split-variables.js +149 -0
- package/lib/generator/split.js +86 -246
- package/lib/generator/wizard.js +51 -70
- package/lib/schema/application-schema.json +4 -4
- package/lib/schema/external-datasource.schema.json +5 -0
- package/lib/schema/external-system.schema.json +10 -0
- package/lib/utils/app-config-resolver.js +52 -0
- package/lib/utils/app-register-api.js +1 -1
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +16 -23
- package/lib/utils/app-register-validator.js +2 -2
- package/lib/utils/cli-utils.js +47 -3
- package/lib/utils/config-format.js +154 -0
- package/lib/utils/config-paths.js +19 -52
- package/lib/utils/config-tokens.js +1 -0
- package/lib/utils/docker-build.js +71 -94
- package/lib/utils/dockerfile-utils.js +1 -1
- package/lib/utils/env-copy.js +4 -4
- package/lib/utils/env-ports.js +2 -2
- package/lib/utils/error-formatter.js +1 -1
- package/lib/utils/error-formatters/validation-errors.js +1 -1
- package/lib/utils/external-readme.js +12 -5
- package/lib/utils/external-system-test-helpers.js +2 -0
- package/lib/utils/health-check.js +55 -66
- package/lib/utils/image-version.js +12 -21
- package/lib/utils/paths.js +45 -66
- package/lib/utils/port-resolver.js +8 -8
- package/lib/utils/schema-loader.js +22 -0
- package/lib/utils/schema-resolver.js +23 -33
- package/lib/utils/secrets-helpers.js +7 -7
- package/lib/utils/secrets-utils.js +10 -12
- package/lib/utils/template-helpers.js +13 -13
- package/lib/utils/token-manager.js +20 -2
- package/lib/utils/variable-transformer.js +2 -2
- package/lib/validation/validate-display.js +3 -4
- package/lib/validation/validate.js +34 -28
- package/lib/validation/validator.js +50 -30
- package/package.json +4 -1
- package/templates/README.md +1 -1
- package/templates/applications/README.md.hbs +3 -3
- package/templates/applications/miso-controller/env.template +3 -1
- package/templates/external-system/README.md.hbs +4 -4
- package/templates/external-system/external-system.json.hbs +1 -16
- package/integration/hubspot/variables.yaml +0 -17
- /package/templates/applications/dataplane/{variables.yaml → application.yaml} +0 -0
- /package/templates/applications/keycloak/{variables.yaml → application.yaml} +0 -0
- /package/templates/applications/miso-controller/{variables.yaml → application.yaml} +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variables YAML extraction for deployment JSON split.
|
|
3
|
+
* Extracts application.yaml (variables) structure from deployment JSON.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Split variables extraction for deployment JSON reverse conversion
|
|
6
|
+
* @author AI Fabrix Team
|
|
7
|
+
* @version 2.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { parseImageReference } = require('./parse-image');
|
|
11
|
+
|
|
12
|
+
function extractAppSection(deployment) {
|
|
13
|
+
if (!deployment.key && !deployment.displayName && !deployment.description && !deployment.type) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const app = {};
|
|
17
|
+
if (deployment.key) app.key = deployment.key;
|
|
18
|
+
if (deployment.displayName) app.displayName = deployment.displayName;
|
|
19
|
+
if (deployment.description) app.description = deployment.description;
|
|
20
|
+
if (deployment.type) app.type = deployment.type;
|
|
21
|
+
if (deployment.version) app.version = deployment.version;
|
|
22
|
+
return app;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function extractImageSection(deployment) {
|
|
26
|
+
if (!deployment.image) return undefined;
|
|
27
|
+
const imageParts = parseImageReference(deployment.image);
|
|
28
|
+
const image = {};
|
|
29
|
+
if (imageParts.name) image.name = imageParts.name;
|
|
30
|
+
if (imageParts.registry) image.registry = imageParts.registry;
|
|
31
|
+
if (imageParts.tag) image.tag = imageParts.tag;
|
|
32
|
+
if (deployment.registryMode) image.registryMode = deployment.registryMode;
|
|
33
|
+
return image;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function extractRequirementsSection(deployment) {
|
|
37
|
+
if (!deployment.requiresDatabase && !deployment.requiresRedis && !deployment.requiresStorage && !deployment.databases) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const requires = {};
|
|
41
|
+
if (deployment.requiresDatabase !== undefined) requires.database = deployment.requiresDatabase;
|
|
42
|
+
if (deployment.requiresRedis !== undefined) requires.redis = deployment.requiresRedis;
|
|
43
|
+
if (deployment.requiresStorage !== undefined) requires.storage = deployment.requiresStorage;
|
|
44
|
+
if (deployment.databases) requires.databases = deployment.databases;
|
|
45
|
+
return requires;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function extractOptionalSection(deployment, sectionName, optional) {
|
|
49
|
+
if (!deployment[sectionName]) return;
|
|
50
|
+
optional[sectionName] = sectionName === 'authentication'
|
|
51
|
+
? { ...deployment[sectionName] }
|
|
52
|
+
: deployment[sectionName];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function extractOptionalSections(deployment) {
|
|
56
|
+
const optional = {};
|
|
57
|
+
const names = [
|
|
58
|
+
'healthCheck', 'authentication', 'build', 'repository', 'deployment',
|
|
59
|
+
'startupCommand', 'runtimeVersion', 'scaling', 'frontDoorRouting'
|
|
60
|
+
];
|
|
61
|
+
for (const sectionName of names) {
|
|
62
|
+
extractOptionalSection(deployment, sectionName, optional);
|
|
63
|
+
}
|
|
64
|
+
return optional;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Portal-only configuration for application.yaml (name + portalInput per entry).
|
|
69
|
+
* @param {Array} configuration - Configuration array from deployment JSON
|
|
70
|
+
* @returns {Array<{ name: string, portalInput: Object }>}
|
|
71
|
+
*/
|
|
72
|
+
function extractPortalInputConfiguration(configuration) {
|
|
73
|
+
if (!Array.isArray(configuration) || configuration.length === 0) return [];
|
|
74
|
+
return configuration
|
|
75
|
+
.filter(item => item && item.portalInput && typeof item.name === 'string')
|
|
76
|
+
.map(item => ({ name: item.name, portalInput: item.portalInput }));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Datasource filename for externalIntegration.dataSources.
|
|
81
|
+
* @param {string} systemKey - System key
|
|
82
|
+
* @param {Object} datasource - Datasource from deployment.dataSources
|
|
83
|
+
* @param {number} index - Index
|
|
84
|
+
* @returns {string} Filename e.g. test-hubspot-datasource-companies-data.yaml
|
|
85
|
+
*/
|
|
86
|
+
function getExternalDatasourceFileName(systemKey, datasource, index) {
|
|
87
|
+
const key = datasource.key || '';
|
|
88
|
+
let suffix;
|
|
89
|
+
if (key.startsWith(`${systemKey}-deploy-`)) suffix = key.slice(`${systemKey}-deploy-`.length);
|
|
90
|
+
else if (key.startsWith(`${systemKey}-`)) suffix = key.slice(systemKey.length + 1);
|
|
91
|
+
else if (key) suffix = key;
|
|
92
|
+
else suffix = datasource.entityType || datasource.entityKey || `entity${index + 1}`;
|
|
93
|
+
return `${systemKey}-datasource-${suffix}.yaml`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function extractVariablesYamlForExternal(deployment) {
|
|
97
|
+
const system = deployment.system;
|
|
98
|
+
const systemKey = system.key || 'external-system';
|
|
99
|
+
const dataSourcesList = deployment.dataSources || deployment.datasources || [];
|
|
100
|
+
const variables = {
|
|
101
|
+
app: {
|
|
102
|
+
key: systemKey,
|
|
103
|
+
displayName: system.displayName || systemKey,
|
|
104
|
+
description: system.description || `External system integration for ${systemKey}`,
|
|
105
|
+
type: 'external'
|
|
106
|
+
},
|
|
107
|
+
externalIntegration: {
|
|
108
|
+
schemaBasePath: './',
|
|
109
|
+
systems: [`${systemKey}-system.yaml`],
|
|
110
|
+
dataSources: dataSourcesList.map((ds, i) => getExternalDatasourceFileName(systemKey, ds, i)),
|
|
111
|
+
autopublish: true,
|
|
112
|
+
version: '1.0.0'
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const portalOnlyConfig = extractPortalInputConfiguration(deployment.configuration);
|
|
116
|
+
if (portalOnlyConfig.length > 0) variables.configuration = portalOnlyConfig;
|
|
117
|
+
return variables;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extracts deployment JSON into application config (variables) structure.
|
|
122
|
+
* @param {Object} deployment - Deployment JSON object
|
|
123
|
+
* @returns {Object} Variables YAML structure
|
|
124
|
+
*/
|
|
125
|
+
function extractVariablesYaml(deployment) {
|
|
126
|
+
if (!deployment || typeof deployment !== 'object') {
|
|
127
|
+
throw new Error('Deployment object is required');
|
|
128
|
+
}
|
|
129
|
+
if (deployment.system && typeof deployment.system === 'object') {
|
|
130
|
+
return extractVariablesYamlForExternal(deployment);
|
|
131
|
+
}
|
|
132
|
+
const variables = {};
|
|
133
|
+
const appSection = extractAppSection(deployment);
|
|
134
|
+
if (appSection) variables.app = appSection;
|
|
135
|
+
const imageSection = extractImageSection(deployment);
|
|
136
|
+
if (imageSection) variables.image = imageSection;
|
|
137
|
+
if (deployment.port !== undefined) variables.port = deployment.port;
|
|
138
|
+
const requirementsSection = extractRequirementsSection(deployment);
|
|
139
|
+
if (requirementsSection) variables.requires = requirementsSection;
|
|
140
|
+
Object.assign(variables, extractOptionalSections(deployment));
|
|
141
|
+
const portalOnlyConfig = extractPortalInputConfiguration(deployment.configuration);
|
|
142
|
+
if (portalOnlyConfig.length > 0) variables.configuration = portalOnlyConfig;
|
|
143
|
+
return variables;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
extractVariablesYaml,
|
|
148
|
+
getExternalDatasourceFileName
|
|
149
|
+
};
|
package/lib/generator/split.js
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
const fs = require('fs').promises;
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const yaml = require('js-yaml');
|
|
14
|
+
const { parseImageReference } = require('./parse-image');
|
|
15
|
+
const { generateReadmeFromDeployJson } = require('./split-readme');
|
|
16
|
+
const { extractVariablesYaml, getExternalDatasourceFileName } = require('./split-variables');
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Converts configuration array back to env.template format
|
|
@@ -43,191 +46,6 @@ function extractEnvTemplate(configuration) {
|
|
|
43
46
|
return lines.join('\n');
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
/**
|
|
47
|
-
* Parses image reference string into components
|
|
48
|
-
* @function parseImageReference
|
|
49
|
-
* @param {string} imageString - Full image string (e.g., "registry/name:tag")
|
|
50
|
-
* @returns {Object} Object with registry, name, and tag
|
|
51
|
-
*/
|
|
52
|
-
function parseImageReference(imageString) {
|
|
53
|
-
if (!imageString || typeof imageString !== 'string') {
|
|
54
|
-
return { registry: null, name: null, tag: 'latest' };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Handle format: registry/name:tag or name:tag or registry/name
|
|
58
|
-
const parts = imageString.split('/');
|
|
59
|
-
let registry = null;
|
|
60
|
-
let nameAndTag = imageString;
|
|
61
|
-
|
|
62
|
-
if (parts.length > 1) {
|
|
63
|
-
// Check if first part looks like a registry (contains .)
|
|
64
|
-
if (parts[0].includes('.')) {
|
|
65
|
-
registry = parts[0];
|
|
66
|
-
nameAndTag = parts.slice(1).join('/');
|
|
67
|
-
} else {
|
|
68
|
-
// No registry, just name:tag
|
|
69
|
-
nameAndTag = imageString;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Split name and tag
|
|
74
|
-
const tagIndex = nameAndTag.lastIndexOf(':');
|
|
75
|
-
let name = nameAndTag;
|
|
76
|
-
let tag = 'latest';
|
|
77
|
-
|
|
78
|
-
if (tagIndex !== -1) {
|
|
79
|
-
name = nameAndTag.substring(0, tagIndex);
|
|
80
|
-
tag = nameAndTag.substring(tagIndex + 1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return { registry, name, tag };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Extract app section from deployment
|
|
88
|
-
* @param {Object} deployment - Deployment JSON object
|
|
89
|
-
* @returns {Object|undefined} App section or undefined
|
|
90
|
-
*/
|
|
91
|
-
function extractAppSection(deployment) {
|
|
92
|
-
if (!deployment.key && !deployment.displayName && !deployment.description && !deployment.type) {
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
|
|
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
|
-
if (deployment.version) app.version = deployment.version;
|
|
102
|
-
return app;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Extract image section from deployment
|
|
107
|
-
* @param {Object} deployment - Deployment JSON object
|
|
108
|
-
* @returns {Object|undefined} Image section or undefined
|
|
109
|
-
*/
|
|
110
|
-
function extractImageSection(deployment) {
|
|
111
|
-
if (!deployment.image) {
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const imageParts = parseImageReference(deployment.image);
|
|
116
|
-
const image = {};
|
|
117
|
-
if (imageParts.name) image.name = imageParts.name;
|
|
118
|
-
if (imageParts.registry) image.registry = imageParts.registry;
|
|
119
|
-
if (imageParts.tag) image.tag = imageParts.tag;
|
|
120
|
-
if (deployment.registryMode) image.registryMode = deployment.registryMode;
|
|
121
|
-
return image;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Extract requirements section from deployment
|
|
126
|
-
* @param {Object} deployment - Deployment JSON object
|
|
127
|
-
* @returns {Object|undefined} Requirements section or undefined
|
|
128
|
-
*/
|
|
129
|
-
function extractRequirementsSection(deployment) {
|
|
130
|
-
if (!deployment.requiresDatabase && !deployment.requiresRedis && !deployment.requiresStorage && !deployment.databases) {
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const requires = {};
|
|
135
|
-
if (deployment.requiresDatabase !== undefined) requires.database = deployment.requiresDatabase;
|
|
136
|
-
if (deployment.requiresRedis !== undefined) requires.redis = deployment.requiresRedis;
|
|
137
|
-
if (deployment.requiresStorage !== undefined) requires.storage = deployment.requiresStorage;
|
|
138
|
-
if (deployment.databases) requires.databases = deployment.databases;
|
|
139
|
-
return requires;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Extract optional sections from deployment
|
|
144
|
-
* @param {Object} deployment - Deployment JSON object
|
|
145
|
-
* @returns {Object} Object with optional sections
|
|
146
|
-
*/
|
|
147
|
-
/**
|
|
148
|
-
* Extracts a single optional section if present
|
|
149
|
-
* @function extractOptionalSection
|
|
150
|
-
* @param {Object} deployment - Deployment object
|
|
151
|
-
* @param {string} sectionName - Section name to extract
|
|
152
|
-
* @param {Object} optional - Optional sections object to update
|
|
153
|
-
*/
|
|
154
|
-
function extractOptionalSection(deployment, sectionName, optional) {
|
|
155
|
-
if (deployment[sectionName]) {
|
|
156
|
-
if (sectionName === 'authentication') {
|
|
157
|
-
optional[sectionName] = { ...deployment[sectionName] };
|
|
158
|
-
} else {
|
|
159
|
-
optional[sectionName] = deployment[sectionName];
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function extractOptionalSections(deployment) {
|
|
165
|
-
const optional = {};
|
|
166
|
-
|
|
167
|
-
const optionalSectionNames = [
|
|
168
|
-
'healthCheck',
|
|
169
|
-
'authentication',
|
|
170
|
-
'build',
|
|
171
|
-
'repository',
|
|
172
|
-
'deployment',
|
|
173
|
-
'startupCommand',
|
|
174
|
-
'runtimeVersion',
|
|
175
|
-
'scaling',
|
|
176
|
-
'frontDoorRouting',
|
|
177
|
-
'roles',
|
|
178
|
-
'permissions'
|
|
179
|
-
];
|
|
180
|
-
|
|
181
|
-
for (const sectionName of optionalSectionNames) {
|
|
182
|
-
extractOptionalSection(deployment, sectionName, optional);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return optional;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Extracts deployment JSON into variables.yaml structure
|
|
190
|
-
* @function extractVariablesYaml
|
|
191
|
-
* @param {Object} deployment - Deployment JSON object
|
|
192
|
-
* @returns {Object} Variables YAML structure
|
|
193
|
-
*/
|
|
194
|
-
function extractVariablesYaml(deployment) {
|
|
195
|
-
if (!deployment || typeof deployment !== 'object') {
|
|
196
|
-
throw new Error('Deployment object is required');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const variables = {};
|
|
200
|
-
|
|
201
|
-
// Extract app section
|
|
202
|
-
const appSection = extractAppSection(deployment);
|
|
203
|
-
if (appSection) {
|
|
204
|
-
variables.app = appSection;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Extract image section
|
|
208
|
-
const imageSection = extractImageSection(deployment);
|
|
209
|
-
if (imageSection) {
|
|
210
|
-
variables.image = imageSection;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Extract port
|
|
214
|
-
if (deployment.port !== undefined) {
|
|
215
|
-
variables.port = deployment.port;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Extract requirements section
|
|
219
|
-
const requirementsSection = extractRequirementsSection(deployment);
|
|
220
|
-
if (requirementsSection) {
|
|
221
|
-
variables.requires = requirementsSection;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Extract optional sections
|
|
225
|
-
const optionalSections = extractOptionalSections(deployment);
|
|
226
|
-
Object.assign(variables, optionalSections);
|
|
227
|
-
|
|
228
|
-
return variables;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
49
|
/**
|
|
232
50
|
* Extracts roles and permissions from deployment JSON
|
|
233
51
|
* @function extractRbacYaml
|
|
@@ -257,62 +75,6 @@ function extractRbacYaml(deployment) {
|
|
|
257
75
|
return rbac;
|
|
258
76
|
}
|
|
259
77
|
|
|
260
|
-
/**
|
|
261
|
-
* Generates README.md content from deployment JSON
|
|
262
|
-
* @function generateReadmeFromDeployJson
|
|
263
|
-
* @param {Object} deployment - Deployment JSON object
|
|
264
|
-
* @returns {string} README.md content
|
|
265
|
-
*/
|
|
266
|
-
function generateReadmeFromDeployJson(deployment) {
|
|
267
|
-
if (!deployment || typeof deployment !== 'object') {
|
|
268
|
-
throw new Error('Deployment object is required');
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const appName = deployment.key || 'application';
|
|
272
|
-
const displayName = deployment.displayName || appName;
|
|
273
|
-
const description = deployment.description || 'Application deployment configuration';
|
|
274
|
-
const port = deployment.port || 3000;
|
|
275
|
-
const image = deployment.image || 'unknown';
|
|
276
|
-
|
|
277
|
-
const lines = [
|
|
278
|
-
`# ${displayName}`,
|
|
279
|
-
'',
|
|
280
|
-
description,
|
|
281
|
-
'',
|
|
282
|
-
'## Quick Start',
|
|
283
|
-
'',
|
|
284
|
-
'This application is configured via deployment JSON and component files.',
|
|
285
|
-
'',
|
|
286
|
-
'## Configuration',
|
|
287
|
-
'',
|
|
288
|
-
`- **Application Key**: \`${appName}\``,
|
|
289
|
-
`- **Port**: \`${port}\``,
|
|
290
|
-
`- **Image**: \`${image}\``,
|
|
291
|
-
'',
|
|
292
|
-
'## Files',
|
|
293
|
-
'',
|
|
294
|
-
'- `variables.yaml` - Application configuration',
|
|
295
|
-
'- `env.template` - Environment variables template',
|
|
296
|
-
'- `rbac.yml` - Roles and permissions (if applicable)',
|
|
297
|
-
'- `README.md` - This file',
|
|
298
|
-
'',
|
|
299
|
-
'## Documentation',
|
|
300
|
-
'',
|
|
301
|
-
'For more information, see the [AI Fabrix Builder documentation](../../docs/README.md).'
|
|
302
|
-
];
|
|
303
|
-
|
|
304
|
-
return lines.join('\n');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Splits a deployment JSON file into component files
|
|
309
|
-
* @async
|
|
310
|
-
* @function splitDeployJson
|
|
311
|
-
* @param {string} deployJsonPath - Path to deployment JSON file
|
|
312
|
-
* @param {string} [outputDir] - Directory to write component files (defaults to same directory as JSON)
|
|
313
|
-
* @returns {Promise<Object>} Object with paths to generated files
|
|
314
|
-
* @throws {Error} If JSON file not found or invalid
|
|
315
|
-
*/
|
|
316
78
|
/**
|
|
317
79
|
* Validates deployment JSON path
|
|
318
80
|
* @function validateDeployJsonPath
|
|
@@ -396,8 +158,8 @@ async function writeComponentFiles(outputDir, envTemplate, variables, rbac, read
|
|
|
396
158
|
await writeComponentFile(envTemplatePath, envTemplate);
|
|
397
159
|
results.envTemplate = envTemplatePath;
|
|
398
160
|
|
|
399
|
-
// Write
|
|
400
|
-
const variablesPath = path.join(outputDir, '
|
|
161
|
+
// Write application.yaml
|
|
162
|
+
const variablesPath = path.join(outputDir, 'application.yaml');
|
|
401
163
|
const variablesYaml = yaml.dump(variables, { indent: 2, lineWidth: -1 });
|
|
402
164
|
await writeComponentFile(variablesPath, variablesYaml);
|
|
403
165
|
results.variables = variablesPath;
|
|
@@ -418,18 +180,96 @@ async function writeComponentFiles(outputDir, envTemplate, variables, rbac, read
|
|
|
418
180
|
return results;
|
|
419
181
|
}
|
|
420
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Writes external system and datasource YAML files when deployment has system (external format).
|
|
185
|
+
* @async
|
|
186
|
+
* @param {string} outputDir - Output directory
|
|
187
|
+
* @param {Object} deployment - Deployment with system and dataSources
|
|
188
|
+
* @returns {Promise<{ systemFile?: string, datasourceFiles?: string[] }>} Paths to written files
|
|
189
|
+
*/
|
|
190
|
+
async function writeExternalSystemAndDatasourceFiles(outputDir, deployment) {
|
|
191
|
+
if (!deployment || !deployment.system) {
|
|
192
|
+
return {};
|
|
193
|
+
}
|
|
194
|
+
const system = deployment.system;
|
|
195
|
+
const systemKey = system.key || 'external-system';
|
|
196
|
+
const dataSourcesList = deployment.dataSources || deployment.datasources || [];
|
|
197
|
+
const results = {};
|
|
198
|
+
|
|
199
|
+
const systemPath = path.join(outputDir, `${systemKey}-system.yaml`);
|
|
200
|
+
const systemYaml = yaml.dump(system, { indent: 2, lineWidth: -1 });
|
|
201
|
+
await writeComponentFile(systemPath, systemYaml);
|
|
202
|
+
results.systemFile = systemPath;
|
|
203
|
+
|
|
204
|
+
const datasourcePaths = [];
|
|
205
|
+
for (let i = 0; i < dataSourcesList.length; i++) {
|
|
206
|
+
const ds = dataSourcesList[i];
|
|
207
|
+
const fileName = getExternalDatasourceFileName(systemKey, ds, i);
|
|
208
|
+
const dsPath = path.join(outputDir, fileName);
|
|
209
|
+
const dsYaml = yaml.dump(ds, { indent: 2, lineWidth: -1 });
|
|
210
|
+
await writeComponentFile(dsPath, dsYaml);
|
|
211
|
+
datasourcePaths.push(dsPath);
|
|
212
|
+
}
|
|
213
|
+
results.datasourceFiles = datasourcePaths;
|
|
214
|
+
|
|
215
|
+
return results;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Normalizes deployment for split: for external format (deployment.system),
|
|
220
|
+
* lifts configuration and roles/permissions to top level so extractors work.
|
|
221
|
+
* @param {Object} deployment - Raw deployment object
|
|
222
|
+
* @returns {Object} Deployment (mutated) with configuration/roles/permissions at top level when from system
|
|
223
|
+
*/
|
|
224
|
+
function normalizeDeploymentForSplit(deployment) {
|
|
225
|
+
if (!deployment || !deployment.system) {
|
|
226
|
+
return deployment;
|
|
227
|
+
}
|
|
228
|
+
const system = deployment.system;
|
|
229
|
+
if (system.configuration && !deployment.configuration) {
|
|
230
|
+
deployment.configuration = system.configuration;
|
|
231
|
+
}
|
|
232
|
+
if (system.roles && !deployment.roles) {
|
|
233
|
+
deployment.roles = system.roles;
|
|
234
|
+
}
|
|
235
|
+
if (system.permissions && !deployment.permissions) {
|
|
236
|
+
deployment.permissions = system.permissions;
|
|
237
|
+
}
|
|
238
|
+
return deployment;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Splits a deployment JSON file into component files.
|
|
243
|
+
* @async
|
|
244
|
+
* @function splitDeployJson
|
|
245
|
+
* @param {string} deployJsonPath - Path to deployment JSON file
|
|
246
|
+
* @param {string} [outputDir] - Directory to write component files (defaults to same directory as JSON)
|
|
247
|
+
* @returns {Promise<Object>} Object with paths to generated files
|
|
248
|
+
* @throws {Error} If JSON file not found or invalid
|
|
249
|
+
*/
|
|
421
250
|
async function splitDeployJson(deployJsonPath, outputDir = null) {
|
|
422
251
|
validateDeployJsonPath(deployJsonPath);
|
|
423
252
|
const finalOutputDir = await prepareOutputDirectory(deployJsonPath, outputDir);
|
|
424
253
|
const deployment = await loadDeploymentJson(deployJsonPath);
|
|
254
|
+
normalizeDeploymentForSplit(deployment);
|
|
425
255
|
|
|
426
|
-
|
|
427
|
-
const envTemplate = extractEnvTemplate(
|
|
256
|
+
const configArray = deployment.configuration || [];
|
|
257
|
+
const envTemplate = extractEnvTemplate(configArray);
|
|
428
258
|
const variables = extractVariablesYaml(deployment);
|
|
429
259
|
const rbac = extractRbacYaml(deployment);
|
|
430
260
|
const readme = generateReadmeFromDeployJson(deployment);
|
|
431
261
|
|
|
432
|
-
|
|
262
|
+
const result = await writeComponentFiles(finalOutputDir, envTemplate, variables, rbac, readme);
|
|
263
|
+
|
|
264
|
+
if (deployment.system && typeof deployment.system === 'object') {
|
|
265
|
+
const externalFiles = await writeExternalSystemAndDatasourceFiles(finalOutputDir, deployment);
|
|
266
|
+
if (externalFiles.systemFile) result.systemFile = externalFiles.systemFile;
|
|
267
|
+
if (externalFiles.datasourceFiles && externalFiles.datasourceFiles.length > 0) {
|
|
268
|
+
result.datasourceFiles = externalFiles.datasourceFiles;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return result;
|
|
433
273
|
}
|
|
434
274
|
|
|
435
275
|
module.exports = {
|