@aifabrix/builder 2.31.1 → 2.32.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/README.md +9 -9
- package/integration/hubspot/README.md +2 -2
- package/integration/hubspot/hubspot-deploy-company.json +17 -14
- package/integration/hubspot/hubspot-deploy-contact.json +19 -16
- package/integration/hubspot/hubspot-deploy-deal.json +21 -18
- package/lib/api/types/datasources.types.js +31 -5
- package/lib/api/types/wizard.types.js +142 -0
- package/lib/api/wizard.api.js +177 -0
- package/lib/{app-config.js → app/config.js} +4 -4
- package/lib/{app-deploy.js → app/deploy.js} +8 -8
- package/lib/app/display.js +90 -0
- package/lib/{app-dockerfile.js → app/dockerfile.js} +4 -4
- package/lib/{app-down.js → app/down.js} +4 -4
- package/lib/app/helpers.js +218 -0
- package/lib/app/index.js +298 -0
- package/lib/{app-list.js → app/list.js} +6 -6
- package/lib/{app-push.js → app/push.js} +4 -4
- package/lib/{app-readme.js → app/readme.js} +34 -13
- package/lib/{app-register.js → app/register.js} +9 -9
- package/lib/{app-rotate-secret.js → app/rotate-secret.js} +10 -10
- package/lib/{app-run-helpers.js → app/run-helpers.js} +10 -10
- package/lib/{app-run.js → app/run.js} +6 -6
- package/lib/{build.js → build/index.js} +59 -32
- package/lib/build/package.json +7 -0
- package/lib/cli.js +245 -179
- package/lib/commands/app.js +3 -3
- package/lib/commands/datasource.js +4 -4
- package/lib/commands/login-credentials.js +209 -0
- package/lib/commands/login-device.js +254 -0
- package/lib/commands/login.js +67 -378
- package/lib/commands/logout.js +1 -1
- package/lib/commands/secrets-set.js +1 -1
- package/lib/commands/secure.js +2 -2
- package/lib/commands/wizard.js +498 -0
- package/lib/{audit-logger.js → core/audit-logger.js} +1 -1
- package/lib/{config.js → core/config.js} +28 -26
- package/lib/{diff.js → core/diff.js} +157 -72
- package/lib/{secrets.js → core/secrets.js} +86 -49
- package/lib/{templates.js → core/templates-env.js} +14 -222
- package/lib/core/templates.js +279 -0
- package/lib/{datasource-deploy.js → datasource/deploy.js} +6 -6
- package/lib/{datasource-diff.js → datasource/diff.js} +2 -2
- package/lib/datasource/list.js +223 -0
- package/lib/{datasource-validate.js → datasource/validate.js} +2 -2
- package/lib/{deployer.js → deployment/deployer.js} +48 -18
- package/lib/{environment-deploy.js → deployment/environment.js} +163 -84
- package/lib/{push.js → deployment/push.js} +1 -1
- package/lib/external-system/deploy-helpers.js +145 -0
- package/lib/{external-system-deploy.js → external-system/deploy.js} +156 -111
- package/lib/external-system/download-helpers.js +114 -0
- package/lib/{external-system-download.js → external-system/download.js} +92 -135
- package/lib/{external-system-generator.js → external-system/generator.js} +15 -11
- package/lib/external-system/test-auth.js +40 -0
- package/lib/external-system/test-execution.js +84 -0
- package/lib/external-system/test-helpers.js +109 -0
- package/lib/{external-system-test.js → external-system/test.js} +174 -192
- package/lib/{generator-builders.js → generator/builders.js} +87 -10
- package/lib/{generator-external.js → generator/external.js} +115 -52
- package/lib/{github-generator.js → generator/github.js} +116 -15
- package/lib/{generator-helpers.js → generator/helpers.js} +92 -42
- package/lib/{generator.js → generator/index.js} +49 -22
- package/lib/{generator-split.js → generator/split.js} +108 -55
- package/lib/generator/wizard-prompts.js +357 -0
- package/lib/generator/wizard.js +490 -0
- package/lib/{infra.js → infrastructure/index.js} +49 -22
- package/lib/schema/external-datasource.schema.json +158 -136
- package/lib/schema/external-system.schema.json +43 -1
- package/lib/utils/api.js +9 -5
- package/lib/utils/app-register-api.js +60 -32
- package/lib/utils/app-register-auth.js +172 -47
- package/lib/utils/app-register-config.js +130 -59
- package/lib/utils/app-run-containers.js +29 -8
- package/lib/utils/build-helpers.js +1 -1
- package/lib/utils/cli-utils.js +78 -30
- package/lib/utils/compose-generator.js +145 -65
- package/lib/utils/config-paths.js +2 -0
- package/lib/utils/deployment-errors.js +1 -1
- package/lib/utils/device-code.js +99 -41
- package/lib/utils/env-config-loader.js +1 -1
- package/lib/utils/env-copy.js +21 -18
- package/lib/utils/env-endpoints.js +115 -67
- package/lib/utils/env-map.js +13 -14
- package/lib/utils/env-ports.js +45 -25
- package/lib/utils/env-template.js +84 -42
- package/lib/utils/error-formatter.js +26 -9
- package/lib/utils/error-formatters/error-parser.js +90 -4
- package/lib/utils/error-formatters/http-status-errors.js +54 -17
- package/lib/utils/error-formatters/network-errors.js +103 -26
- package/lib/utils/external-system-display.js +184 -90
- package/lib/utils/external-system-validators.js +164 -42
- package/lib/utils/file-upload.js +109 -0
- package/lib/utils/health-check.js +199 -83
- package/lib/utils/infra-containers.js +1 -1
- package/lib/utils/infra-status.js +66 -15
- package/lib/utils/local-secrets.js +45 -25
- package/lib/utils/paths.js +45 -33
- package/lib/utils/schema-loader.js +42 -25
- package/lib/utils/schema-resolver.js +123 -74
- package/lib/utils/secrets-encryption.js +62 -25
- package/lib/utils/secrets-helpers.js +126 -63
- package/lib/utils/secrets-path.js +1 -1
- package/lib/utils/secrets-url.js +1 -1
- package/lib/utils/token-manager-refresh.js +181 -0
- package/lib/utils/token-manager.js +76 -123
- package/lib/utils/variable-transformer.js +154 -77
- package/lib/utils/yaml-preserve.js +41 -47
- package/lib/{template-validator.js → validation/template.js} +54 -23
- package/lib/{validate.js → validation/validate.js} +205 -125
- package/lib/{validator.js → validation/validator.js} +58 -39
- package/package.json +31 -2
- package/templates/external-system/deploy.ps1.hbs +34 -0
- package/templates/external-system/deploy.sh.hbs +34 -0
- package/templates/external-system/external-datasource.json.hbs +31 -12
- package/lib/app.js +0 -467
- package/lib/datasource-list.js +0 -141
- /package/lib/{app-prompts.js → app/prompts.js} +0 -0
- /package/lib/{env-reader.js → core/env-reader.js} +0 -0
- /package/lib/{key-generator.js → core/key-generator.js} +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Wizard API functions
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { ApiClient } = require('./index');
|
|
8
|
+
const { uploadFile } = require('../utils/file-upload');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Select wizard mode
|
|
12
|
+
* POST /api/v1/wizard/mode-selection
|
|
13
|
+
* @async
|
|
14
|
+
* @function selectMode
|
|
15
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
16
|
+
* @param {Object} authConfig - Authentication configuration
|
|
17
|
+
* @param {string} mode - Wizard mode ('create-system' | 'add-datasource')
|
|
18
|
+
* @returns {Promise<Object>} Mode selection response
|
|
19
|
+
* @throws {Error} If request fails
|
|
20
|
+
*/
|
|
21
|
+
async function selectMode(dataplaneUrl, authConfig, mode) {
|
|
22
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
23
|
+
return await client.post('/api/v1/wizard/mode-selection', {
|
|
24
|
+
body: { mode }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Select wizard source
|
|
30
|
+
* POST /api/v1/wizard/source-selection
|
|
31
|
+
* @async
|
|
32
|
+
* @function selectSource
|
|
33
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
34
|
+
* @param {Object} authConfig - Authentication configuration
|
|
35
|
+
* @param {string} sourceType - Source type ('openapi-file' | 'openapi-url' | 'mcp-server' | 'known-platform')
|
|
36
|
+
* @param {string} [sourceData] - Source data (file path, URL, etc.)
|
|
37
|
+
* @returns {Promise<Object>} Source selection response
|
|
38
|
+
* @throws {Error} If request fails
|
|
39
|
+
*/
|
|
40
|
+
async function selectSource(dataplaneUrl, authConfig, sourceType, sourceData) {
|
|
41
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
42
|
+
return await client.post('/api/v1/wizard/source-selection', {
|
|
43
|
+
body: {
|
|
44
|
+
sourceType,
|
|
45
|
+
sourceData
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parse OpenAPI file
|
|
52
|
+
* POST /api/v1/wizard/parse-openapi
|
|
53
|
+
* @async
|
|
54
|
+
* @function parseOpenApi
|
|
55
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
56
|
+
* @param {Object} authConfig - Authentication configuration
|
|
57
|
+
* @param {string} openApiFilePath - Path to OpenAPI file
|
|
58
|
+
* @returns {Promise<Object>} Parsed OpenAPI response
|
|
59
|
+
* @throws {Error} If request fails
|
|
60
|
+
*/
|
|
61
|
+
async function parseOpenApi(dataplaneUrl, authConfig, openApiFilePath) {
|
|
62
|
+
const url = `${dataplaneUrl.replace(/\/$/, '')}/api/v1/wizard/parse-openapi`;
|
|
63
|
+
return await uploadFile(url, openApiFilePath, 'file', authConfig);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Detect API type from OpenAPI spec
|
|
68
|
+
* POST /api/v1/wizard/detect-type
|
|
69
|
+
* @async
|
|
70
|
+
* @function detectType
|
|
71
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
72
|
+
* @param {Object} authConfig - Authentication configuration
|
|
73
|
+
* @param {Object} openApiSpec - OpenAPI specification object
|
|
74
|
+
* @returns {Promise<Object>} Type detection response
|
|
75
|
+
* @throws {Error} If request fails
|
|
76
|
+
*/
|
|
77
|
+
async function detectType(dataplaneUrl, authConfig, openApiSpec) {
|
|
78
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
79
|
+
return await client.post('/api/v1/wizard/detect-type', {
|
|
80
|
+
body: { openApiSpec }
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate configuration via AI
|
|
86
|
+
* POST /api/v1/wizard/generate-config
|
|
87
|
+
* @async
|
|
88
|
+
* @function generateConfig
|
|
89
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
90
|
+
* @param {Object} authConfig - Authentication configuration
|
|
91
|
+
* @param {Object} config - Generation configuration
|
|
92
|
+
* @param {string} config.mode - Wizard mode
|
|
93
|
+
* @param {string} config.sourceType - Source type
|
|
94
|
+
* @param {Object} [config.openApiSpec] - OpenAPI specification (if applicable)
|
|
95
|
+
* @param {string} [config.userIntent] - User intent (e.g., 'sales-focused', 'support-focused')
|
|
96
|
+
* @param {Object} [config.preferences] - User preferences
|
|
97
|
+
* @returns {Promise<Object>} Generated configuration response
|
|
98
|
+
* @throws {Error} If request fails
|
|
99
|
+
*/
|
|
100
|
+
async function generateConfig(dataplaneUrl, authConfig, config) {
|
|
101
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
102
|
+
return await client.post('/api/v1/wizard/generate-config', {
|
|
103
|
+
body: config
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Validate wizard configuration
|
|
109
|
+
* POST /api/v1/wizard/validate
|
|
110
|
+
* @async
|
|
111
|
+
* @function validateWizardConfig
|
|
112
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
113
|
+
* @param {Object} authConfig - Authentication configuration
|
|
114
|
+
* @param {Object} systemConfig - System configuration to validate
|
|
115
|
+
* @param {Object[]} datasourceConfigs - Array of datasource configurations to validate
|
|
116
|
+
* @returns {Promise<Object>} Validation response
|
|
117
|
+
* @throws {Error} If request fails
|
|
118
|
+
*/
|
|
119
|
+
async function validateWizardConfig(dataplaneUrl, authConfig, systemConfig, datasourceConfigs) {
|
|
120
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
121
|
+
return await client.post('/api/v1/wizard/validate', {
|
|
122
|
+
body: {
|
|
123
|
+
systemConfig,
|
|
124
|
+
datasourceConfigs
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Test MCP server connection
|
|
131
|
+
* POST /api/v1/wizard/test-mcp-connection
|
|
132
|
+
* @async
|
|
133
|
+
* @function testMcpConnection
|
|
134
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
135
|
+
* @param {Object} authConfig - Authentication configuration
|
|
136
|
+
* @param {string} serverUrl - MCP server URL
|
|
137
|
+
* @param {string} token - MCP server authentication token
|
|
138
|
+
* @returns {Promise<Object>} Connection test response
|
|
139
|
+
* @throws {Error} If request fails
|
|
140
|
+
*/
|
|
141
|
+
async function testMcpConnection(dataplaneUrl, authConfig, serverUrl, token) {
|
|
142
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
143
|
+
return await client.post('/api/v1/wizard/test-mcp-connection', {
|
|
144
|
+
body: {
|
|
145
|
+
serverUrl,
|
|
146
|
+
token
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get deployment documentation for a system
|
|
153
|
+
* GET /api/v1/wizard/deployment-docs/{systemKey}
|
|
154
|
+
* @async
|
|
155
|
+
* @function getDeploymentDocs
|
|
156
|
+
* @param {string} dataplaneUrl - Dataplane base URL
|
|
157
|
+
* @param {Object} authConfig - Authentication configuration
|
|
158
|
+
* @param {string} systemKey - System key identifier
|
|
159
|
+
* @returns {Promise<Object>} Deployment documentation response
|
|
160
|
+
* @throws {Error} If request fails
|
|
161
|
+
*/
|
|
162
|
+
async function getDeploymentDocs(dataplaneUrl, authConfig, systemKey) {
|
|
163
|
+
const client = new ApiClient(dataplaneUrl, authConfig);
|
|
164
|
+
return await client.get(`/api/v1/wizard/deployment-docs/${systemKey}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
selectMode,
|
|
169
|
+
selectSource,
|
|
170
|
+
parseOpenApi,
|
|
171
|
+
detectType,
|
|
172
|
+
generateConfig,
|
|
173
|
+
validateWizardConfig,
|
|
174
|
+
testMcpConnection,
|
|
175
|
+
getDeploymentDocs
|
|
176
|
+
};
|
|
177
|
+
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
const fs = require('fs').promises;
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const chalk = require('chalk');
|
|
14
|
-
const { generateVariablesYaml, generateEnvTemplate, generateRbacYaml } = require('
|
|
15
|
-
const { generateEnvTemplate: generateEnvTemplateFromReader } = require('
|
|
16
|
-
const { generateReadmeMdFile } = require('./
|
|
17
|
-
const logger = require('
|
|
14
|
+
const { generateVariablesYaml, generateEnvTemplate, generateRbacYaml } = require('../core/templates');
|
|
15
|
+
const { generateEnvTemplate: generateEnvTemplateFromReader } = require('../core/env-reader');
|
|
16
|
+
const { generateReadmeMdFile } = require('./readme');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Checks if a file exists
|
|
@@ -13,11 +13,11 @@ const fs = require('fs').promises;
|
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const yaml = require('js-yaml');
|
|
15
15
|
const chalk = require('chalk');
|
|
16
|
-
const pushUtils = require('
|
|
17
|
-
const logger = require('
|
|
18
|
-
const config = require('
|
|
19
|
-
const { getDeploymentAuth } = require('
|
|
20
|
-
const { detectAppType } = require('
|
|
16
|
+
const pushUtils = require('../deployment/push');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
|
+
const config = require('../core/config');
|
|
19
|
+
const { getDeploymentAuth } = require('../utils/token-manager');
|
|
20
|
+
const { detectAppType } = require('../utils/paths');
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Validate application name format
|
|
@@ -294,7 +294,7 @@ async function loadDeploymentConfig(appName, options) {
|
|
|
294
294
|
*/
|
|
295
295
|
async function generateAndValidateManifest(appName) {
|
|
296
296
|
logger.log(chalk.blue(`\n📋 Generating deployment manifest for ${appName}...`));
|
|
297
|
-
const generator = require('
|
|
297
|
+
const generator = require('../generator');
|
|
298
298
|
|
|
299
299
|
// generateDeployJson already validates against schema and throws on error
|
|
300
300
|
const manifestPath = await generator.generateDeployJson(appName);
|
|
@@ -327,7 +327,7 @@ function displayDeploymentInfo(manifest, manifestPath) {
|
|
|
327
327
|
*/
|
|
328
328
|
async function executeDeployment(manifest, deploymentConfig) {
|
|
329
329
|
logger.log(chalk.blue(`\n🚀 Deploying to ${deploymentConfig.controllerUrl} (environment: ${deploymentConfig.envKey})...`));
|
|
330
|
-
const deployer = require('
|
|
330
|
+
const deployer = require('../deployment/deployer');
|
|
331
331
|
return await deployer.deployToController(
|
|
332
332
|
manifest,
|
|
333
333
|
deploymentConfig.controllerUrl,
|
|
@@ -418,7 +418,7 @@ async function deployApp(appName, options = {}) {
|
|
|
418
418
|
const alreadyLogged = error._logged === true;
|
|
419
419
|
const url = controllerUrl || options.controller || 'unknown';
|
|
420
420
|
|
|
421
|
-
const deployer = require('
|
|
421
|
+
const deployer = require('../deployment/deployer');
|
|
422
422
|
// handleDeploymentErrors will log, format, and throw the error
|
|
423
423
|
await deployer.handleDeploymentErrors(error, appName, url, alreadyLogged);
|
|
424
424
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Display Utilities
|
|
3
|
+
*
|
|
4
|
+
* Handles display of success messages and user guidance
|
|
5
|
+
* for application creation.
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Display utilities for application creation
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 2.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const chalk = require('chalk');
|
|
14
|
+
const logger = require('../utils/logger');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Displays external system success message
|
|
18
|
+
* @function displayExternalSystemSuccess
|
|
19
|
+
* @param {string} appName - Application name
|
|
20
|
+
* @param {Object} config - Configuration
|
|
21
|
+
* @param {string} location - Application location
|
|
22
|
+
*/
|
|
23
|
+
function displayExternalSystemSuccess(appName, config, location) {
|
|
24
|
+
logger.log(chalk.blue('Type: External System'));
|
|
25
|
+
logger.log(chalk.blue(`System Key: ${config.systemKey || appName}`));
|
|
26
|
+
logger.log(chalk.green('\nNext steps:'));
|
|
27
|
+
logger.log(chalk.white('1. Edit external system JSON files in ' + location));
|
|
28
|
+
logger.log(chalk.white('2. Run: aifabrix app register ' + appName + ' --environment dev'));
|
|
29
|
+
logger.log(chalk.white('3. Run: aifabrix build ' + appName + ' (deploys to dataplane)'));
|
|
30
|
+
logger.log(chalk.white('4. Run: aifabrix deploy ' + appName + ' (publishes to dataplane)'));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Displays webapp success message
|
|
35
|
+
* @function displayWebappSuccess
|
|
36
|
+
* @param {string} appName - Application name
|
|
37
|
+
* @param {Object} config - Configuration
|
|
38
|
+
* @param {string} envConversionMessage - Environment conversion message
|
|
39
|
+
*/
|
|
40
|
+
function displayWebappSuccess(appName, config, envConversionMessage) {
|
|
41
|
+
logger.log(chalk.blue(`Language: ${config.language}`));
|
|
42
|
+
logger.log(chalk.blue(`Port: ${config.port}`));
|
|
43
|
+
|
|
44
|
+
if (config.database) logger.log(chalk.yellow(' - Database enabled'));
|
|
45
|
+
if (config.redis) logger.log(chalk.yellow(' - Redis enabled'));
|
|
46
|
+
if (config.storage) logger.log(chalk.yellow(' - Storage enabled'));
|
|
47
|
+
if (config.authentication) logger.log(chalk.yellow(' - Authentication enabled'));
|
|
48
|
+
|
|
49
|
+
logger.log(chalk.gray(envConversionMessage));
|
|
50
|
+
|
|
51
|
+
logger.log(chalk.green('\nNext steps:'));
|
|
52
|
+
logger.log(chalk.white('1. Copy env.template to .env and fill in your values'));
|
|
53
|
+
logger.log(chalk.white('2. Run: aifabrix build ' + appName));
|
|
54
|
+
logger.log(chalk.white('3. Run: aifabrix run ' + appName));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Displays success message after app creation
|
|
59
|
+
* @param {string} appName - Application name
|
|
60
|
+
* @param {Object} config - Final configuration
|
|
61
|
+
* @param {string} envConversionMessage - Environment conversion message
|
|
62
|
+
* @param {boolean} hasAppFiles - Whether app files were created
|
|
63
|
+
* @param {string} appPath - Application path
|
|
64
|
+
*/
|
|
65
|
+
function displaySuccessMessage(appName, config, envConversionMessage, hasAppFiles = false, appPath = null) {
|
|
66
|
+
logger.log(chalk.green('\n✓ Application created successfully!'));
|
|
67
|
+
logger.log(chalk.blue(`\nApplication: ${appName}`));
|
|
68
|
+
|
|
69
|
+
// Determine location based on app type
|
|
70
|
+
const baseDir = config.type === 'external' ? 'integration' : 'builder';
|
|
71
|
+
const location = appPath ? path.relative(process.cwd(), appPath) : `${baseDir}/${appName}/`;
|
|
72
|
+
logger.log(chalk.blue(`Location: ${location}`));
|
|
73
|
+
|
|
74
|
+
if (hasAppFiles) {
|
|
75
|
+
logger.log(chalk.blue(`Application files: apps/${appName}/`));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (config.type === 'external') {
|
|
79
|
+
displayExternalSystemSuccess(appName, config, location);
|
|
80
|
+
} else {
|
|
81
|
+
displayWebappSuccess(appName, config, envConversionMessage);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
displaySuccessMessage,
|
|
87
|
+
displayExternalSystemSuccess,
|
|
88
|
+
displayWebappSuccess
|
|
89
|
+
};
|
|
90
|
+
|
|
@@ -12,9 +12,9 @@ const fs = require('fs').promises;
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const chalk = require('chalk');
|
|
14
14
|
const yaml = require('js-yaml');
|
|
15
|
-
const build = require('
|
|
16
|
-
const { validateAppName } = require('./
|
|
17
|
-
const logger = require('
|
|
15
|
+
const build = require('../build');
|
|
16
|
+
const { validateAppName } = require('./push');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Checks if Dockerfile exists and validates overwrite permission
|
|
@@ -85,7 +85,7 @@ async function generateAndCopyDockerfile(appPath, dockerfilePath, config) {
|
|
|
85
85
|
*/
|
|
86
86
|
async function generateDockerfileForApp(appName, options = {}) {
|
|
87
87
|
// Check if app type is external - skip Dockerfile generation
|
|
88
|
-
const { detectAppType } = require('
|
|
88
|
+
const { detectAppType } = require('../utils/paths');
|
|
89
89
|
try {
|
|
90
90
|
const { isExternal } = await detectAppType(appName);
|
|
91
91
|
if (isExternal) {
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
const chalk = require('chalk');
|
|
15
15
|
const { exec } = require('child_process');
|
|
16
|
-
const logger = require('
|
|
17
|
-
const config = require('
|
|
18
|
-
const helpers = require('./
|
|
19
|
-
const { validateAppName } = require('./
|
|
16
|
+
const logger = require('../utils/logger');
|
|
17
|
+
const config = require('../core/config');
|
|
18
|
+
const helpers = require('./run-helpers');
|
|
19
|
+
const { validateAppName } = require('./push');
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Executes a shell command asynchronously.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Helper Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for application creation and validation
|
|
5
|
+
*
|
|
6
|
+
* @fileoverview Helper utilities for application management
|
|
7
|
+
* @author AI Fabrix Team
|
|
8
|
+
* @version 2.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs').promises;
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const chalk = require('chalk');
|
|
14
|
+
const { validateTemplate, copyTemplateFiles, copyAppFiles } = require('../validation/template');
|
|
15
|
+
const logger = require('../utils/logger');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Validates that app directory doesn't already exist
|
|
19
|
+
* @async
|
|
20
|
+
* @param {string} appPath - Application directory path
|
|
21
|
+
* @param {string} appName - Application name
|
|
22
|
+
* @param {string} baseDir - Base directory name
|
|
23
|
+
* @throws {Error} If directory already exists
|
|
24
|
+
*/
|
|
25
|
+
async function validateAppDirectoryNotExists(appPath, appName, baseDir = 'builder') {
|
|
26
|
+
try {
|
|
27
|
+
await fs.access(appPath);
|
|
28
|
+
throw new Error(`Application '${appName}' already exists in ${baseDir}/${appName}/`);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code !== 'ENOENT') {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Gets the base directory path for an app based on its type
|
|
38
|
+
* @param {string} appType - Application type ('external' or other)
|
|
39
|
+
* @returns {string} Base directory path ('integration' or 'builder')
|
|
40
|
+
*/
|
|
41
|
+
function getBaseDirForAppType(appType) {
|
|
42
|
+
return appType === 'external' ? 'integration' : 'builder';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Handles GitHub workflow generation if requested
|
|
47
|
+
* @async
|
|
48
|
+
* @param {Object} options - Creation options
|
|
49
|
+
* @param {Object} config - Final configuration
|
|
50
|
+
*/
|
|
51
|
+
async function handleGitHubWorkflows(options, config) {
|
|
52
|
+
if (!options.github) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const githubGen = require('../generator/github');
|
|
57
|
+
|
|
58
|
+
// Parse github-steps if provided
|
|
59
|
+
const githubSteps = options.githubSteps
|
|
60
|
+
? options.githubSteps.split(',').map(s => s.trim()).filter(s => s.length > 0)
|
|
61
|
+
: [];
|
|
62
|
+
|
|
63
|
+
const workflowFiles = await githubGen.generateGithubWorkflows(
|
|
64
|
+
process.cwd(),
|
|
65
|
+
config,
|
|
66
|
+
{
|
|
67
|
+
mainBranch: options.mainBranch || 'main',
|
|
68
|
+
uploadCoverage: true,
|
|
69
|
+
githubSteps: githubSteps
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
logger.log(chalk.green('✓ Generated GitHub Actions workflows:'));
|
|
74
|
+
workflowFiles.forEach(file => logger.log(chalk.gray(` - ${file}`)));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validates app creation prerequisites
|
|
79
|
+
* @async
|
|
80
|
+
* @function validateAppCreation
|
|
81
|
+
* @param {string} appName - Application name
|
|
82
|
+
* @param {Object} options - Creation options
|
|
83
|
+
* @param {string} appPath - Application directory path
|
|
84
|
+
* @param {string} baseDir - Base directory name
|
|
85
|
+
* @throws {Error} If validation fails
|
|
86
|
+
*/
|
|
87
|
+
async function validateAppCreation(appName, options, appPath, baseDir = 'builder') {
|
|
88
|
+
const { validateAppName } = require('./push');
|
|
89
|
+
validateAppName(appName);
|
|
90
|
+
await validateAppDirectoryNotExists(appPath, appName, baseDir);
|
|
91
|
+
|
|
92
|
+
if (!options.app) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const appsPath = path.join(process.cwd(), 'apps', appName);
|
|
97
|
+
try {
|
|
98
|
+
await fs.access(appsPath);
|
|
99
|
+
throw new Error(`Application '${appName}' already exists in apps/${appName}/`);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error.code !== 'ENOENT') {
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Processes template files if template is specified
|
|
109
|
+
* @async
|
|
110
|
+
* @function processTemplateFiles
|
|
111
|
+
* @param {string} template - Template name
|
|
112
|
+
* @param {string} appPath - Application directory path
|
|
113
|
+
* @param {string} appName - Application name
|
|
114
|
+
* @param {Object} options - Creation options
|
|
115
|
+
* @param {Object} config - Final configuration
|
|
116
|
+
* @throws {Error} If template processing fails
|
|
117
|
+
*/
|
|
118
|
+
async function processTemplateFiles(template, appPath, appName, options, config) {
|
|
119
|
+
if (!template) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await validateTemplate(template);
|
|
124
|
+
const copiedFiles = await copyTemplateFiles(template, appPath);
|
|
125
|
+
logger.log(chalk.green(`✓ Copied ${copiedFiles.length} file(s) from template '${template}'`));
|
|
126
|
+
const { updateTemplateVariables } = require('../utils/template-helpers');
|
|
127
|
+
await updateTemplateVariables(appPath, appName, options, config);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Updates variables.yaml for --app flag
|
|
132
|
+
* @async
|
|
133
|
+
* @function updateVariablesForAppFlag
|
|
134
|
+
* @param {string} appPath - Application directory path
|
|
135
|
+
* @param {string} appName - Application name
|
|
136
|
+
* @throws {Error} If update fails
|
|
137
|
+
*/
|
|
138
|
+
async function updateVariablesForAppFlag(appPath, appName) {
|
|
139
|
+
try {
|
|
140
|
+
const yaml = require('js-yaml');
|
|
141
|
+
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
142
|
+
const variablesContent = await fs.readFile(variablesPath, 'utf8');
|
|
143
|
+
const variables = yaml.load(variablesContent);
|
|
144
|
+
|
|
145
|
+
if (variables.build) {
|
|
146
|
+
variables.build.context = '../..';
|
|
147
|
+
variables.build.envOutputPath = `../../apps/${appName}/.env`;
|
|
148
|
+
} else {
|
|
149
|
+
variables.build = {
|
|
150
|
+
context: '../..',
|
|
151
|
+
envOutputPath: `../../apps/${appName}/.env`
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await fs.writeFile(variablesPath, yaml.dump(variables, { indent: 2, lineWidth: 120, noRefs: true }));
|
|
156
|
+
} catch (error) {
|
|
157
|
+
logger.warn(chalk.yellow(`⚠️ Warning: Could not update variables.yaml: ${error.message}`));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Gets language from config or variables.yaml
|
|
163
|
+
* @async
|
|
164
|
+
* @function getLanguageForAppFiles
|
|
165
|
+
* @param {string} language - Language from config
|
|
166
|
+
* @param {string} appPath - Application directory path
|
|
167
|
+
* @returns {Promise<string>} Language to use
|
|
168
|
+
* @throws {Error} If language cannot be determined
|
|
169
|
+
*/
|
|
170
|
+
async function getLanguageForAppFiles(language, appPath) {
|
|
171
|
+
if (language) {
|
|
172
|
+
return language;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const yaml = require('js-yaml');
|
|
176
|
+
const variablesPath = path.join(appPath, 'variables.yaml');
|
|
177
|
+
const variablesContent = await fs.readFile(variablesPath, 'utf8');
|
|
178
|
+
const variables = yaml.load(variablesContent);
|
|
179
|
+
const languageFromYaml = variables?.build?.language;
|
|
180
|
+
|
|
181
|
+
if (!languageFromYaml) {
|
|
182
|
+
throw new Error('Language not specified and could not be determined from variables.yaml. Use --language flag or ensure variables.yaml contains build.language');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return languageFromYaml;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Sets up apps directory and copies application files
|
|
190
|
+
* @async
|
|
191
|
+
* @function setupAppFiles
|
|
192
|
+
* @param {string} appName - Application name
|
|
193
|
+
* @param {string} appPath - Application directory path
|
|
194
|
+
* @param {Object} config - Final configuration
|
|
195
|
+
* @param {Object} options - Creation options
|
|
196
|
+
* @throws {Error} If setup fails
|
|
197
|
+
*/
|
|
198
|
+
async function setupAppFiles(appName, appPath, config, options) {
|
|
199
|
+
const appsPath = path.join(process.cwd(), 'apps', appName);
|
|
200
|
+
await fs.mkdir(appsPath, { recursive: true });
|
|
201
|
+
await updateVariablesForAppFlag(appPath, appName);
|
|
202
|
+
|
|
203
|
+
const language = await getLanguageForAppFiles(config.language || options.language, appPath);
|
|
204
|
+
const copiedFiles = await copyAppFiles(language, appsPath);
|
|
205
|
+
logger.log(chalk.green(`✓ Copied ${copiedFiles.length} application file(s) to apps/${appName}/`));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = {
|
|
209
|
+
validateAppDirectoryNotExists,
|
|
210
|
+
getBaseDirForAppType,
|
|
211
|
+
handleGitHubWorkflows,
|
|
212
|
+
validateAppCreation,
|
|
213
|
+
processTemplateFiles,
|
|
214
|
+
updateVariablesForAppFlag,
|
|
215
|
+
getLanguageForAppFiles,
|
|
216
|
+
setupAppFiles
|
|
217
|
+
};
|
|
218
|
+
|