@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
package/lib/app/index.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Fabrix Builder Application Management
|
|
3
|
+
*
|
|
4
|
+
* This module handles application building, running, and deployment.
|
|
5
|
+
* Includes runtime detection, Dockerfile generation, and container management.
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Application build and run management for AI Fabrix Builder
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 2.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs').promises;
|
|
13
|
+
const { readExistingEnv } = require('../core/env-reader');
|
|
14
|
+
const build = require('../build');
|
|
15
|
+
const appRun = require('./run');
|
|
16
|
+
const { promptForOptions } = require('./prompts');
|
|
17
|
+
const { generateConfigFiles } = require('./config');
|
|
18
|
+
const { pushApp } = require('./push');
|
|
19
|
+
const { generateDockerfileForApp } = require('./dockerfile');
|
|
20
|
+
const { loadTemplateVariables, updateTemplateVariables, mergeTemplateVariables } = require('../utils/template-helpers');
|
|
21
|
+
const { validateTemplate } = require('../validation/template');
|
|
22
|
+
const auditLogger = require('../core/audit-logger');
|
|
23
|
+
const { downApp } = require('./down');
|
|
24
|
+
const { getAppPath } = require('../utils/paths');
|
|
25
|
+
const { displaySuccessMessage } = require('./display');
|
|
26
|
+
const {
|
|
27
|
+
validateAppDirectoryNotExists,
|
|
28
|
+
getBaseDirForAppType,
|
|
29
|
+
handleGitHubWorkflows,
|
|
30
|
+
validateAppCreation,
|
|
31
|
+
processTemplateFiles,
|
|
32
|
+
setupAppFiles
|
|
33
|
+
} = require('./helpers');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates new application with scaffolded configuration files
|
|
37
|
+
* Prompts for configuration options and generates builder/ folder structure
|
|
38
|
+
*
|
|
39
|
+
* @async
|
|
40
|
+
* @function createApp
|
|
41
|
+
* @param {string} appName - Name of the application to create
|
|
42
|
+
* @param {Object} options - Creation options
|
|
43
|
+
* @param {number} [options.port] - Application port
|
|
44
|
+
* @param {boolean} [options.database] - Requires database
|
|
45
|
+
* @param {boolean} [options.redis] - Requires Redis
|
|
46
|
+
* @param {boolean} [options.storage] - Requires file storage
|
|
47
|
+
* @param {boolean} [options.authentication] - Requires authentication/RBAC
|
|
48
|
+
* @param {string} [options.language] - Runtime language (typescript/python)
|
|
49
|
+
* @param {string} [options.template] - Template to use (e.g., controller, keycloak)
|
|
50
|
+
* @returns {Promise<void>} Resolves when app is created
|
|
51
|
+
* @throws {Error} If creation fails
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* await createApp('myapp', { port: 3000, database: true, language: 'typescript' });
|
|
55
|
+
* // Creates builder/ with variables.yaml, env.template, rbac.yaml
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Validates app name and initial setup
|
|
59
|
+
* @function validateAppNameAndSetup
|
|
60
|
+
* @param {string} appName - Application name
|
|
61
|
+
* @param {Object} options - Options
|
|
62
|
+
* @returns {Object} Initial paths and type
|
|
63
|
+
*/
|
|
64
|
+
function validateAppNameAndSetup(appName, options) {
|
|
65
|
+
if (!appName || typeof appName !== 'string') {
|
|
66
|
+
throw new Error('Application name is required');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const initialType = options.type || 'webapp';
|
|
70
|
+
const baseDir = getBaseDirForAppType(initialType);
|
|
71
|
+
const appPath = getAppPath(appName, initialType);
|
|
72
|
+
|
|
73
|
+
return { initialType, baseDir, appPath };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Handles template validation and loading
|
|
78
|
+
* @async
|
|
79
|
+
* @function handleTemplateSetup
|
|
80
|
+
* @param {Object} options - Options
|
|
81
|
+
* @returns {Promise<Object>} Merged options with template variables
|
|
82
|
+
*/
|
|
83
|
+
async function handleTemplateSetup(options) {
|
|
84
|
+
if (options.template) {
|
|
85
|
+
await validateTemplate(options.template);
|
|
86
|
+
}
|
|
87
|
+
const templateVariables = await loadTemplateVariables(options.template);
|
|
88
|
+
return mergeTemplateVariables(options, templateVariables);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Validates and prepares final app path
|
|
93
|
+
* @async
|
|
94
|
+
* @function prepareFinalAppPath
|
|
95
|
+
* @param {string} appName - Application name
|
|
96
|
+
* @param {Object} config - Configuration
|
|
97
|
+
* @param {string} initialAppPath - Initial app path
|
|
98
|
+
* @returns {Promise<string>} Final app path
|
|
99
|
+
*/
|
|
100
|
+
async function prepareFinalAppPath(appName, config, initialAppPath) {
|
|
101
|
+
const finalBaseDir = getBaseDirForAppType(config.type);
|
|
102
|
+
const finalAppPath = getAppPath(appName, config.type);
|
|
103
|
+
|
|
104
|
+
// If path changed, validate the new path
|
|
105
|
+
if (finalAppPath !== initialAppPath) {
|
|
106
|
+
await validateAppDirectoryNotExists(finalAppPath, appName, finalBaseDir);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return finalAppPath;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Generates all application files
|
|
114
|
+
* @async
|
|
115
|
+
* @function generateApplicationFiles
|
|
116
|
+
* @param {string} finalAppPath - Final app path
|
|
117
|
+
* @param {string} appName - Application name
|
|
118
|
+
* @param {Object} config - Configuration
|
|
119
|
+
* @param {Object} options - Options
|
|
120
|
+
* @returns {Promise<string>} Environment conversion message
|
|
121
|
+
*/
|
|
122
|
+
async function generateApplicationFiles(finalAppPath, appName, config, options) {
|
|
123
|
+
await fs.mkdir(finalAppPath, { recursive: true });
|
|
124
|
+
await processTemplateFiles(options.template, finalAppPath, appName, options, config);
|
|
125
|
+
|
|
126
|
+
const existingEnv = await readExistingEnv(process.cwd());
|
|
127
|
+
const envConversionMessage = existingEnv
|
|
128
|
+
? '\n✓ Found existing .env file - sensitive values will be converted to kv:// references'
|
|
129
|
+
: '';
|
|
130
|
+
|
|
131
|
+
await generateConfigFiles(finalAppPath, appName, config, existingEnv);
|
|
132
|
+
|
|
133
|
+
// Generate external system files if type is external
|
|
134
|
+
if (config.type === 'external') {
|
|
135
|
+
const externalGenerator = require('../external-system/generator');
|
|
136
|
+
await externalGenerator.generateExternalSystemFiles(finalAppPath, appName, config);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (options.app) {
|
|
140
|
+
await setupAppFiles(appName, finalAppPath, config, options);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
await handleGitHubWorkflows(options, config);
|
|
144
|
+
return envConversionMessage;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Logs application creation for audit
|
|
149
|
+
* @async
|
|
150
|
+
* @function logApplicationCreation
|
|
151
|
+
* @param {string} appName - Application name
|
|
152
|
+
* @param {Object} config - Configuration
|
|
153
|
+
* @param {Object} options - Options
|
|
154
|
+
*/
|
|
155
|
+
async function logApplicationCreation(appName, config, options) {
|
|
156
|
+
await auditLogger.logApplicationCreation(appName, {
|
|
157
|
+
language: config.language,
|
|
158
|
+
port: config.port,
|
|
159
|
+
database: config.database,
|
|
160
|
+
redis: config.redis,
|
|
161
|
+
storage: config.storage,
|
|
162
|
+
authentication: config.authentication,
|
|
163
|
+
template: options.template,
|
|
164
|
+
api: null // Local operation, no API involved
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function createApp(appName, options = {}) {
|
|
169
|
+
try {
|
|
170
|
+
const { appPath } = validateAppNameAndSetup(appName, options);
|
|
171
|
+
await validateAppCreation(appName, options, appPath, getBaseDirForAppType(options.type || 'webapp'));
|
|
172
|
+
|
|
173
|
+
const mergedOptions = await handleTemplateSetup(options);
|
|
174
|
+
const config = await promptForOptions(appName, mergedOptions);
|
|
175
|
+
|
|
176
|
+
const finalAppPath = await prepareFinalAppPath(appName, config, appPath);
|
|
177
|
+
const envConversionMessage = await generateApplicationFiles(finalAppPath, appName, config, options);
|
|
178
|
+
|
|
179
|
+
displaySuccessMessage(appName, config, envConversionMessage, options.app, finalAppPath);
|
|
180
|
+
await logApplicationCreation(appName, config, options);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
throw new Error(`Failed to create application: ${error.message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Builds a container image for the specified application
|
|
188
|
+
* Auto-detects runtime and generates Dockerfile if needed
|
|
189
|
+
*
|
|
190
|
+
* @async
|
|
191
|
+
* @function buildApp
|
|
192
|
+
* @param {string} appName - Name of the application to build
|
|
193
|
+
* @param {Object} options - Build options
|
|
194
|
+
* @param {string} [options.language] - Override language detection
|
|
195
|
+
* @param {boolean} [options.forceTemplate] - Force rebuild from template
|
|
196
|
+
* @param {string} [options.tag] - Image tag (default: latest)
|
|
197
|
+
* @returns {Promise<string>} Image tag that was built
|
|
198
|
+
* @throws {Error} If build fails or app configuration is invalid
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* const imageTag = await buildApp('myapp', { language: 'typescript' });
|
|
202
|
+
* // Returns: 'myapp:latest'
|
|
203
|
+
*/
|
|
204
|
+
async function buildApp(appName, options = {}) {
|
|
205
|
+
return build.buildApp(appName, options);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Detects the runtime language of an application
|
|
210
|
+
* Analyzes project files to determine TypeScript, Python, etc.
|
|
211
|
+
*
|
|
212
|
+
* @function detectLanguage
|
|
213
|
+
* @param {string} appPath - Path to application directory
|
|
214
|
+
* @returns {string} Detected language ('typescript', 'python', etc.)
|
|
215
|
+
* @throws {Error} If language cannot be detected
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* const language = detectLanguage('./myapp');
|
|
219
|
+
* // Returns: 'typescript'
|
|
220
|
+
*/
|
|
221
|
+
function detectLanguage(appPath) {
|
|
222
|
+
return build.detectLanguage(appPath);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Generates a Dockerfile from template based on detected language
|
|
227
|
+
* Uses Handlebars templates to create optimized Dockerfiles
|
|
228
|
+
*
|
|
229
|
+
* @async
|
|
230
|
+
* @function generateDockerfile
|
|
231
|
+
* @param {string} appPath - Path to application directory
|
|
232
|
+
* @param {string} language - Target language ('typescript', 'python')
|
|
233
|
+
* @param {Object} config - Application configuration from variables.yaml
|
|
234
|
+
* @returns {Promise<string>} Path to generated Dockerfile
|
|
235
|
+
* @throws {Error} If template generation fails
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* const dockerfilePath = await generateDockerfile('./myapp', 'typescript', config);
|
|
239
|
+
* // Returns: './myapp/.aifabrix/Dockerfile.typescript'
|
|
240
|
+
*/
|
|
241
|
+
async function generateDockerfile(appPath, language, config) {
|
|
242
|
+
return build.generateDockerfile(appPath, language, config);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Runs the application locally using Docker
|
|
247
|
+
* Starts container with proper port mapping and environment
|
|
248
|
+
*
|
|
249
|
+
* @async
|
|
250
|
+
* @function runApp
|
|
251
|
+
* @param {string} appName - Name of the application to run
|
|
252
|
+
* @param {Object} options - Run options
|
|
253
|
+
* @param {number} [options.port] - Override local port
|
|
254
|
+
* @param {boolean} [options.debug] - Enable debug output
|
|
255
|
+
* @returns {Promise<void>} Resolves when app is running
|
|
256
|
+
* @throws {Error} If run fails or app is not built
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* await runApp('myapp', { port: 3001 });
|
|
260
|
+
* // Application is now running on localhost:3001
|
|
261
|
+
*/
|
|
262
|
+
async function runApp(appName, options = {}) {
|
|
263
|
+
return appRun.runApp(appName, options);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Deploys application to controller
|
|
268
|
+
* @async
|
|
269
|
+
* @function deployApp
|
|
270
|
+
* @param {string} appName - Name of the application
|
|
271
|
+
* @param {Object} options - Deployment options
|
|
272
|
+
* @returns {Promise<void>} Resolves when deployment is complete
|
|
273
|
+
*/
|
|
274
|
+
async function deployApp(appName, options = {}) {
|
|
275
|
+
const appDeploy = require('./deploy');
|
|
276
|
+
return appDeploy.deployApp(appName, options);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
createApp,
|
|
281
|
+
buildApp,
|
|
282
|
+
runApp,
|
|
283
|
+
downApp,
|
|
284
|
+
detectLanguage,
|
|
285
|
+
generateDockerfile,
|
|
286
|
+
generateDockerfileForApp,
|
|
287
|
+
pushApp,
|
|
288
|
+
deployApp,
|
|
289
|
+
loadTemplateVariables,
|
|
290
|
+
updateTemplateVariables,
|
|
291
|
+
mergeTemplateVariables,
|
|
292
|
+
checkImageExists: appRun.checkImageExists,
|
|
293
|
+
checkContainerRunning: appRun.checkContainerRunning,
|
|
294
|
+
stopAndRemoveContainer: appRun.stopAndRemoveContainer,
|
|
295
|
+
checkPortAvailable: appRun.checkPortAvailable,
|
|
296
|
+
generateDockerCompose: appRun.generateDockerCompose,
|
|
297
|
+
waitForHealthCheck: appRun.waitForHealthCheck
|
|
298
|
+
};
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
-
const { getConfig, normalizeControllerUrl } = require('
|
|
13
|
-
const { getOrRefreshDeviceToken } = require('
|
|
14
|
-
const { listEnvironmentApplications } = require('
|
|
15
|
-
const { formatApiError } = require('
|
|
16
|
-
const { formatAuthenticationError } = require('
|
|
17
|
-
const logger = require('
|
|
12
|
+
const { getConfig, normalizeControllerUrl } = require('../core/config');
|
|
13
|
+
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
14
|
+
const { listEnvironmentApplications } = require('../api/environments.api');
|
|
15
|
+
const { formatApiError } = require('../utils/api-error-handler');
|
|
16
|
+
const { formatAuthenticationError } = require('../utils/error-formatters/http-status-errors');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Extract wrapped array format: { success: true, data: { success: true, data: [...] } }
|
|
@@ -12,8 +12,8 @@ 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 pushUtils = require('
|
|
16
|
-
const logger = require('
|
|
15
|
+
const pushUtils = require('../deployment/push');
|
|
16
|
+
const logger = require('../utils/logger');
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Validate application name format
|
|
@@ -70,7 +70,7 @@ function extractImageName(config, appName) {
|
|
|
70
70
|
*/
|
|
71
71
|
async function loadPushConfig(appName, options) {
|
|
72
72
|
// Detect app type and get correct path (integration or builder)
|
|
73
|
-
const { detectAppType } = require('
|
|
73
|
+
const { detectAppType } = require('../utils/paths');
|
|
74
74
|
const { appPath } = await detectAppType(appName);
|
|
75
75
|
const configPath = path.join(appPath, 'variables.yaml');
|
|
76
76
|
try {
|
|
@@ -183,7 +183,7 @@ function displayPushResults(registry, imageName, tags) {
|
|
|
183
183
|
*/
|
|
184
184
|
async function pushApp(appName, options = {}) {
|
|
185
185
|
// Check if app type is external - skip push
|
|
186
|
-
const { detectAppType } = require('
|
|
186
|
+
const { detectAppType } = require('../utils/paths');
|
|
187
187
|
try {
|
|
188
188
|
const { isExternal } = await detectAppType(appName);
|
|
189
189
|
if (isExternal) {
|
|
@@ -48,7 +48,7 @@ function formatAppDisplayName(appName) {
|
|
|
48
48
|
*/
|
|
49
49
|
function _loadReadmeTemplate() {
|
|
50
50
|
// Use getProjectRoot to reliably find templates in all environments
|
|
51
|
-
const { getProjectRoot } = require('
|
|
51
|
+
const { getProjectRoot } = require('../utils/paths');
|
|
52
52
|
const projectRoot = getProjectRoot();
|
|
53
53
|
const templatePath = path.join(projectRoot, 'templates', 'applications', 'README.md.hbs');
|
|
54
54
|
|
|
@@ -71,32 +71,51 @@ function _loadReadmeTemplate() {
|
|
|
71
71
|
* @param {Object} config - Application configuration
|
|
72
72
|
* @returns {string} README.md content
|
|
73
73
|
*/
|
|
74
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Extracts service flags from config
|
|
76
|
+
* @function extractServiceFlags
|
|
77
|
+
* @param {Object} config - Application configuration
|
|
78
|
+
* @returns {Object} Service flags object
|
|
79
|
+
*/
|
|
80
|
+
function extractServiceFlags(config) {
|
|
81
|
+
return {
|
|
82
|
+
hasDatabase: config.database || config.requires?.database || false,
|
|
83
|
+
hasRedis: config.redis || config.requires?.redis || false,
|
|
84
|
+
hasStorage: config.storage || config.requires?.storage || false,
|
|
85
|
+
hasAuthentication: config.authentication || false
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Builds template context for README generation
|
|
91
|
+
* @function buildReadmeContext
|
|
92
|
+
* @param {string} appName - Application name
|
|
93
|
+
* @param {Object} config - Application configuration
|
|
94
|
+
* @returns {Object} Template context
|
|
95
|
+
*/
|
|
96
|
+
function buildReadmeContext(appName, config) {
|
|
75
97
|
const displayName = formatAppDisplayName(appName);
|
|
76
98
|
const imageName = `aifabrix/${appName}`;
|
|
77
99
|
const port = config.port || 3000;
|
|
78
100
|
// Extract registry from nested structure (config.image.registry) or flattened (config.registry)
|
|
79
101
|
const registry = config.image?.registry || config.registry || 'myacr.azurecr.io';
|
|
80
102
|
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const hasStorage = config.storage || config.requires?.storage || false;
|
|
84
|
-
const hasAuthentication = config.authentication || false;
|
|
85
|
-
const hasAnyService = hasDatabase || hasRedis || hasStorage || hasAuthentication;
|
|
103
|
+
const serviceFlags = extractServiceFlags(config);
|
|
104
|
+
const hasAnyService = serviceFlags.hasDatabase || serviceFlags.hasRedis || serviceFlags.hasStorage || serviceFlags.hasAuthentication;
|
|
86
105
|
|
|
87
|
-
|
|
106
|
+
return {
|
|
88
107
|
appName,
|
|
89
108
|
displayName,
|
|
90
109
|
imageName,
|
|
91
110
|
port,
|
|
92
111
|
registry,
|
|
93
|
-
|
|
94
|
-
hasRedis,
|
|
95
|
-
hasStorage,
|
|
96
|
-
hasAuthentication,
|
|
112
|
+
...serviceFlags,
|
|
97
113
|
hasAnyService
|
|
98
114
|
};
|
|
115
|
+
}
|
|
99
116
|
|
|
117
|
+
function generateReadmeMd(appName, config) {
|
|
118
|
+
const context = buildReadmeContext(appName, config);
|
|
100
119
|
// Always generate comprehensive README programmatically to ensure consistency
|
|
101
120
|
// regardless of template file content
|
|
102
121
|
return generateComprehensiveReadme(context);
|
|
@@ -220,10 +239,12 @@ For more information, see the [AI Fabrix Builder documentation](https://docs.aif
|
|
|
220
239
|
* @throws {Error} If file generation fails
|
|
221
240
|
*/
|
|
222
241
|
async function generateReadmeMdFile(appPath, appName, config) {
|
|
242
|
+
// Ensure directory exists
|
|
243
|
+
await fs.mkdir(appPath, { recursive: true });
|
|
223
244
|
const readmePath = path.join(appPath, 'README.md');
|
|
224
245
|
if (!(await fileExists(readmePath))) {
|
|
225
246
|
const readmeContent = generateReadmeMd(appName, config);
|
|
226
|
-
await fs.writeFile(readmePath, readmeContent);
|
|
247
|
+
await fs.writeFile(readmePath, readmeContent, 'utf8');
|
|
227
248
|
}
|
|
228
249
|
}
|
|
229
250
|
|
|
@@ -9,19 +9,19 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
-
const logger = require('
|
|
13
|
-
const { saveLocalSecret, isLocalhost } = require('
|
|
14
|
-
const { updateEnvTemplate } = require('
|
|
15
|
-
const { generateEnvFile } = require('
|
|
16
|
-
const { registerApplicationSchema, validateAppRegistrationData } = require('
|
|
12
|
+
const logger = require('../utils/logger');
|
|
13
|
+
const { saveLocalSecret, isLocalhost } = require('../utils/local-secrets');
|
|
14
|
+
const { updateEnvTemplate } = require('../utils/env-template');
|
|
15
|
+
const { generateEnvFile } = require('../core/secrets');
|
|
16
|
+
const { registerApplicationSchema, validateAppRegistrationData } = require('../utils/app-register-validator');
|
|
17
17
|
const {
|
|
18
18
|
loadVariablesYaml,
|
|
19
19
|
createMinimalAppIfNeeded,
|
|
20
20
|
extractAppConfiguration
|
|
21
|
-
} = require('
|
|
22
|
-
const { checkAuthentication } = require('
|
|
23
|
-
const { callRegisterApi } = require('
|
|
24
|
-
const { displayRegistrationResults, getEnvironmentPrefix } = require('
|
|
21
|
+
} = require('../utils/app-register-config');
|
|
22
|
+
const { checkAuthentication } = require('../utils/app-register-auth');
|
|
23
|
+
const { callRegisterApi } = require('../utils/app-register-api');
|
|
24
|
+
const { displayRegistrationResults, getEnvironmentPrefix } = require('../utils/app-register-display');
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Build registration data payload from app configuration
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
|
-
const { getConfig, normalizeControllerUrl } = require('
|
|
13
|
-
const { getOrRefreshDeviceToken } = require('
|
|
14
|
-
const { rotateApplicationSecret } = require('
|
|
15
|
-
const { formatApiError } = require('
|
|
16
|
-
const { formatAuthenticationError } = require('
|
|
17
|
-
const logger = require('
|
|
18
|
-
const { saveLocalSecret, isLocalhost } = require('
|
|
19
|
-
const { updateEnvTemplate } = require('
|
|
20
|
-
const { getEnvironmentPrefix } = require('./
|
|
21
|
-
const { generateEnvFile } = require('
|
|
12
|
+
const { getConfig, normalizeControllerUrl } = require('../core/config');
|
|
13
|
+
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
14
|
+
const { rotateApplicationSecret } = require('../api/applications.api');
|
|
15
|
+
const { formatApiError } = require('../utils/api-error-handler');
|
|
16
|
+
const { formatAuthenticationError } = require('../utils/error-formatters/http-status-errors');
|
|
17
|
+
const logger = require('../utils/logger');
|
|
18
|
+
const { saveLocalSecret, isLocalhost } = require('../utils/local-secrets');
|
|
19
|
+
const { updateEnvTemplate } = require('../utils/env-template');
|
|
20
|
+
const { getEnvironmentPrefix } = require('./register');
|
|
21
|
+
const { generateEnvFile } = require('../core/secrets');
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Find device token from config by trying each stored URL
|
|
@@ -16,16 +16,16 @@ const chalk = require('chalk');
|
|
|
16
16
|
const yaml = require('js-yaml');
|
|
17
17
|
const { exec } = require('child_process');
|
|
18
18
|
const { promisify } = require('util');
|
|
19
|
-
const validator = require('
|
|
20
|
-
const infra = require('
|
|
21
|
-
const secrets = require('
|
|
22
|
-
const config = require('
|
|
23
|
-
const buildCopy = require('
|
|
24
|
-
const logger = require('
|
|
25
|
-
const { waitForHealthCheck } = require('
|
|
26
|
-
const composeGenerator = require('
|
|
27
|
-
const dockerUtils = require('
|
|
28
|
-
const containerHelpers = require('
|
|
19
|
+
const validator = require('../validation/validator');
|
|
20
|
+
const infra = require('../infrastructure');
|
|
21
|
+
const secrets = require('../core/secrets');
|
|
22
|
+
const config = require('../core/config');
|
|
23
|
+
const buildCopy = require('../utils/build-copy');
|
|
24
|
+
const logger = require('../utils/logger');
|
|
25
|
+
const { waitForHealthCheck } = require('../utils/health-check');
|
|
26
|
+
const composeGenerator = require('../utils/compose-generator');
|
|
27
|
+
const dockerUtils = require('../utils/docker');
|
|
28
|
+
const containerHelpers = require('../utils/app-run-containers');
|
|
29
29
|
|
|
30
30
|
const execAsync = promisify(exec);
|
|
31
31
|
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const chalk = require('chalk');
|
|
13
|
-
const config = require('
|
|
14
|
-
const logger = require('
|
|
15
|
-
const { checkPortAvailable, waitForHealthCheck } = require('
|
|
16
|
-
const composeGenerator = require('
|
|
13
|
+
const config = require('../core/config');
|
|
14
|
+
const logger = require('../utils/logger');
|
|
15
|
+
const { checkPortAvailable, waitForHealthCheck } = require('../utils/health-check');
|
|
16
|
+
const composeGenerator = require('../utils/compose-generator');
|
|
17
17
|
// Helper functions extracted to reduce file size and complexity
|
|
18
|
-
const helpers = require('./
|
|
18
|
+
const helpers = require('./run-helpers');
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Validate app for run and check if it's an external system
|
|
@@ -31,7 +31,7 @@ async function validateAppForRun(appName, _debug) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Check if app type is external - skip Docker run
|
|
34
|
-
const { detectAppType } = require('
|
|
34
|
+
const { detectAppType } = require('../utils/paths');
|
|
35
35
|
try {
|
|
36
36
|
const { isExternal } = await detectAppType(appName);
|
|
37
37
|
if (isExternal) {
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
const fs = require('fs').promises;
|
|
14
14
|
const fsSync = require('fs');
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const paths = require('
|
|
17
|
-
const { detectAppType, getProjectRoot } = require('
|
|
16
|
+
const paths = require('../utils/paths');
|
|
17
|
+
const { detectAppType, getProjectRoot } = require('../utils/paths');
|
|
18
18
|
const chalk = require('chalk');
|
|
19
19
|
const yaml = require('js-yaml');
|
|
20
|
-
const secrets = require('
|
|
21
|
-
const config = require('
|
|
22
|
-
const logger = require('
|
|
23
|
-
const dockerfileUtils = require('
|
|
24
|
-
const dockerBuild = require('
|
|
25
|
-
const buildCopy = require('
|
|
26
|
-
const { buildDevImageName } = require('
|
|
27
|
-
const buildHelpers = require('
|
|
20
|
+
const secrets = require('../core/secrets');
|
|
21
|
+
const config = require('../core/config');
|
|
22
|
+
const logger = require('../utils/logger');
|
|
23
|
+
const dockerfileUtils = require('../utils/dockerfile-utils');
|
|
24
|
+
const dockerBuild = require('../utils/docker-build');
|
|
25
|
+
const buildCopy = require('../utils/build-copy');
|
|
26
|
+
const { buildDevImageName } = require('../utils/image-name');
|
|
27
|
+
const buildHelpers = require('../utils/build-helpers');
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Loads variables.yaml configuration for an application
|
|
@@ -208,7 +208,7 @@ async function postBuildTasks(appName, buildConfig) {
|
|
|
208
208
|
async function checkExternalAppType(appName) {
|
|
209
209
|
const variables = await loadVariablesYaml(appName);
|
|
210
210
|
if (variables.app && variables.app.type === 'external') {
|
|
211
|
-
const generator = require('
|
|
211
|
+
const generator = require('../generator');
|
|
212
212
|
const jsonPath = await generator.generateDeployJson(appName);
|
|
213
213
|
logger.log(chalk.green(`✓ Generated deployment JSON: ${jsonPath}`));
|
|
214
214
|
return true;
|
|
@@ -224,6 +224,51 @@ async function checkExternalAppType(appName) {
|
|
|
224
224
|
* @param {Object} options - Build options
|
|
225
225
|
* @returns {Promise<Object>} Object with devDir, effectiveImageName, imageName, appConfig, and developerId
|
|
226
226
|
*/
|
|
227
|
+
/**
|
|
228
|
+
* Copies application source files if they exist
|
|
229
|
+
* @async
|
|
230
|
+
* @function copyApplicationSourceFiles
|
|
231
|
+
* @param {string} appName - Application name
|
|
232
|
+
* @param {string} devDir - Developer directory
|
|
233
|
+
* @returns {Promise<boolean>} True if files were copied
|
|
234
|
+
*/
|
|
235
|
+
async function copyApplicationSourceFiles(appName, devDir) {
|
|
236
|
+
const appsPath = path.join(process.cwd(), 'apps', appName);
|
|
237
|
+
if (fsSync.existsSync(appsPath)) {
|
|
238
|
+
await buildCopy.copyAppSourceFiles(appsPath, devDir);
|
|
239
|
+
logger.log(chalk.green(`✓ Copied application source files from apps/${appName}`));
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Copies template files if needed
|
|
247
|
+
* @async
|
|
248
|
+
* @function copyTemplateFilesIfNeeded
|
|
249
|
+
* @param {string} devDir - Developer directory
|
|
250
|
+
* @param {string} language - Language type
|
|
251
|
+
* @param {Object} buildConfig - Build configuration
|
|
252
|
+
* @param {Object} options - Build options
|
|
253
|
+
*/
|
|
254
|
+
async function copyTemplateFilesIfNeeded(devDir, language, buildConfig, options) {
|
|
255
|
+
const detectedLanguage = options.language || buildConfig.language || detectLanguage(devDir);
|
|
256
|
+
const packageJsonPath = path.join(devDir, 'package.json');
|
|
257
|
+
const requirementsPath = path.join(devDir, 'requirements.txt');
|
|
258
|
+
|
|
259
|
+
if (detectedLanguage === 'typescript' && !fsSync.existsSync(packageJsonPath)) {
|
|
260
|
+
const projectRoot = getProjectRoot();
|
|
261
|
+
const templatePath = path.join(projectRoot, 'templates', 'typescript');
|
|
262
|
+
await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, detectedLanguage);
|
|
263
|
+
logger.log(chalk.green(`✓ Generated application files from ${detectedLanguage} template`));
|
|
264
|
+
} else if (detectedLanguage === 'python' && !fsSync.existsSync(requirementsPath)) {
|
|
265
|
+
const projectRoot = getProjectRoot();
|
|
266
|
+
const templatePath = path.join(projectRoot, 'templates', 'python');
|
|
267
|
+
await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, detectedLanguage);
|
|
268
|
+
logger.log(chalk.green(`✓ Generated application files from ${detectedLanguage} template`));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
227
272
|
async function prepareDevDirectory(appName, buildConfig, options) {
|
|
228
273
|
const developerId = await config.getDeveloperId();
|
|
229
274
|
const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
|
|
@@ -236,27 +281,9 @@ async function prepareDevDirectory(appName, buildConfig, options) {
|
|
|
236
281
|
const effectiveImageName = buildDevImageName(imageName, developerId);
|
|
237
282
|
|
|
238
283
|
// Check if application source files exist, if not copy from templates
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
await
|
|
242
|
-
logger.log(chalk.green(`✓ Copied application source files from apps/${appName}`));
|
|
243
|
-
} else {
|
|
244
|
-
// No apps directory - check if we need to copy template files
|
|
245
|
-
const language = options.language || buildConfig.language || detectLanguage(devDir);
|
|
246
|
-
const packageJsonPath = path.join(devDir, 'package.json');
|
|
247
|
-
const requirementsPath = path.join(devDir, 'requirements.txt');
|
|
248
|
-
|
|
249
|
-
if (language === 'typescript' && !fsSync.existsSync(packageJsonPath)) {
|
|
250
|
-
const projectRoot = getProjectRoot();
|
|
251
|
-
const templatePath = path.join(projectRoot, 'templates', 'typescript');
|
|
252
|
-
await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, language);
|
|
253
|
-
logger.log(chalk.green(`✓ Generated application files from ${language} template`));
|
|
254
|
-
} else if (language === 'python' && !fsSync.existsSync(requirementsPath)) {
|
|
255
|
-
const projectRoot = getProjectRoot();
|
|
256
|
-
const templatePath = path.join(projectRoot, 'templates', 'python');
|
|
257
|
-
await buildCopy.copyTemplateFilesToDevDir(templatePath, devDir, language);
|
|
258
|
-
logger.log(chalk.green(`✓ Generated application files from ${language} template`));
|
|
259
|
-
}
|
|
284
|
+
const filesCopied = await copyApplicationSourceFiles(appName, devDir);
|
|
285
|
+
if (!filesCopied) {
|
|
286
|
+
await copyTemplateFilesIfNeeded(devDir, null, buildConfig, options);
|
|
260
287
|
}
|
|
261
288
|
|
|
262
289
|
return { devDir, effectiveImageName, imageName, appConfig };
|