@aifabrix/builder 2.36.2 → 2.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -104
- package/lib/app/display.js +1 -1
- package/lib/app/run-helpers.js +1 -1
- package/lib/cli/index.js +45 -0
- package/lib/cli/setup-app.js +229 -0
- package/lib/cli/setup-auth.js +88 -0
- package/lib/cli/setup-dev.js +101 -0
- package/lib/cli/setup-environment.js +53 -0
- package/lib/cli/setup-external-system.js +86 -0
- package/lib/cli/setup-infra.js +219 -0
- package/lib/cli/setup-secrets.js +48 -0
- package/lib/cli/setup-utility.js +202 -0
- package/lib/cli.js +7 -961
- package/lib/commands/up-miso.js +1 -1
- package/lib/core/config.js +10 -0
- package/lib/core/ensure-encryption-key.js +56 -0
- package/lib/generator/wizard.js +19 -34
- package/lib/infrastructure/helpers.js +1 -1
- package/lib/utils/help-builder.js +5 -2
- package/package.json +1 -1
- package/templates/applications/README.md.hbs +3 -3
- package/templates/applications/dataplane/variables.yaml +0 -2
- package/templates/applications/miso-controller/variables.yaml +0 -2
- package/templates/external-system/deploy.js.hbs +58 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI utility command setup (resolve, json, split-json, genkey, show, validate, diff).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Utility command definitions for AI Fabrix Builder CLI
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const secrets = require('../core/secrets');
|
|
13
|
+
const generator = require('../generator');
|
|
14
|
+
const logger = require('../utils/logger');
|
|
15
|
+
const { handleCommandError } = require('../utils/cli-utils');
|
|
16
|
+
const { detectAppType, getDeployJsonPath } = require('../utils/paths');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handles split-json command logic
|
|
20
|
+
* @async
|
|
21
|
+
* @param {string} appName - Application name
|
|
22
|
+
* @param {Object} options - Command options
|
|
23
|
+
* @returns {Promise<Object>} Paths to generated files
|
|
24
|
+
*/
|
|
25
|
+
async function handleSplitJsonCommand(appName, options) {
|
|
26
|
+
const { appPath, appType } = await detectAppType(appName, options);
|
|
27
|
+
|
|
28
|
+
const outputDir = options.output || appPath;
|
|
29
|
+
if (appType === 'external') {
|
|
30
|
+
const schemaPath = path.join(appPath, 'application-schema.json');
|
|
31
|
+
if (!fs.existsSync(schemaPath)) {
|
|
32
|
+
throw new Error(`application-schema.json not found: ${schemaPath}`);
|
|
33
|
+
}
|
|
34
|
+
return generator.splitExternalApplicationSchema(schemaPath, outputDir);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const deployJsonPath = getDeployJsonPath(appName, appType, true);
|
|
38
|
+
if (!fs.existsSync(deployJsonPath)) {
|
|
39
|
+
throw new Error(`Deployment JSON file not found: ${deployJsonPath}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return generator.splitDeployJson(deployJsonPath, outputDir);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Logs split-json results
|
|
47
|
+
* @param {Object} result - Generated file paths
|
|
48
|
+
* @returns {void}
|
|
49
|
+
*/
|
|
50
|
+
function logSplitJsonResult(result) {
|
|
51
|
+
logger.log(chalk.green('\n✓ Successfully split deployment JSON into component files:'));
|
|
52
|
+
logger.log(` • env.template: ${result.envTemplate}`);
|
|
53
|
+
logger.log(` • variables.yaml: ${result.variables}`);
|
|
54
|
+
if (result.rbac) {
|
|
55
|
+
logger.log(` • rbac.yml: ${result.rbac}`);
|
|
56
|
+
}
|
|
57
|
+
logger.log(` • README.md: ${result.readme}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sets up utility commands
|
|
62
|
+
* @param {Command} program - Commander program instance
|
|
63
|
+
*/
|
|
64
|
+
function setupUtilityCommands(program) {
|
|
65
|
+
program.command('resolve <app>')
|
|
66
|
+
.description('Generate .env file from template and validate application files')
|
|
67
|
+
.option('-f, --force', 'Generate missing secret keys in secrets file')
|
|
68
|
+
.option('--skip-validation', 'Skip file validation after generating .env')
|
|
69
|
+
.action(async(appName, options) => {
|
|
70
|
+
try {
|
|
71
|
+
const envPath = await secrets.generateEnvFile(appName, undefined, 'docker', options.force);
|
|
72
|
+
logger.log(`✓ Generated .env file: ${envPath}`);
|
|
73
|
+
|
|
74
|
+
if (!options.skipValidation) {
|
|
75
|
+
const validate = require('../validation/validate');
|
|
76
|
+
const result = await validate.validateAppOrFile(appName);
|
|
77
|
+
validate.displayValidationResults(result);
|
|
78
|
+
if (!result.valid) {
|
|
79
|
+
logger.log(chalk.yellow('\n⚠️ Validation found errors. Fix them before deploying.'));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
handleCommandError(error, 'resolve');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
program.command('json <app>')
|
|
90
|
+
.description('Generate deployment JSON (aifabrix-deploy.json for normal apps, application-schema.json for external systems)')
|
|
91
|
+
.option('--type <type>', 'Application type (external) - if set, only checks integration folder')
|
|
92
|
+
.action(async(appName, options) => {
|
|
93
|
+
try {
|
|
94
|
+
const result = await generator.generateDeployJsonWithValidation(appName, options);
|
|
95
|
+
if (result.success) {
|
|
96
|
+
const fileName = result.path.includes('application-schema.json') ? 'application-schema.json' : 'deployment JSON';
|
|
97
|
+
logger.log(`✓ Generated ${fileName}: ${result.path}`);
|
|
98
|
+
|
|
99
|
+
if (result.validation.warnings && result.validation.warnings.length > 0) {
|
|
100
|
+
logger.log('\n⚠️ Warnings:');
|
|
101
|
+
result.validation.warnings.forEach(warning => logger.log(` • ${warning}`));
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
logger.log('❌ Validation failed:');
|
|
105
|
+
if (result.validation.errors && result.validation.errors.length > 0) {
|
|
106
|
+
result.validation.errors.forEach(error => logger.log(` • ${error}`));
|
|
107
|
+
}
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
handleCommandError(error, 'json');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
program.command('split-json <app>')
|
|
117
|
+
.description('Split deployment JSON into component files (env.template, variables.yaml, rbac.yml, README.md)')
|
|
118
|
+
.option('-o, --output <dir>', 'Output directory for component files (defaults to same directory as JSON)')
|
|
119
|
+
.option('--type <type>', 'Application type (external) - if set, only checks integration folder')
|
|
120
|
+
.action(async(appName, options) => {
|
|
121
|
+
try {
|
|
122
|
+
const result = await handleSplitJsonCommand(appName, options);
|
|
123
|
+
logSplitJsonResult(result);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
handleCommandError(error, 'split-json');
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
program.command('genkey <app>')
|
|
131
|
+
.description('Generate deployment key')
|
|
132
|
+
.action(async(appName) => {
|
|
133
|
+
try {
|
|
134
|
+
const jsonPath = await generator.generateDeployJson(appName);
|
|
135
|
+
|
|
136
|
+
const jsonContent = fs.readFileSync(jsonPath, 'utf8');
|
|
137
|
+
const deployment = JSON.parse(jsonContent);
|
|
138
|
+
|
|
139
|
+
const key = deployment.deploymentKey;
|
|
140
|
+
|
|
141
|
+
if (!key) {
|
|
142
|
+
throw new Error('deploymentKey not found in generated JSON');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
logger.log(`\nDeployment key for ${appName}:`);
|
|
146
|
+
logger.log(key);
|
|
147
|
+
logger.log(chalk.gray(`\nGenerated from: ${jsonPath}`));
|
|
148
|
+
} catch (error) {
|
|
149
|
+
handleCommandError(error, 'genkey');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
program.command('show <appKey>')
|
|
155
|
+
.description('Show application info from local builder/ or integration/ (offline) or from controller (--online)')
|
|
156
|
+
.option('--online', 'Fetch application data from the controller')
|
|
157
|
+
.option('--json', 'Output as JSON')
|
|
158
|
+
.action(async(appKey, options) => {
|
|
159
|
+
try {
|
|
160
|
+
const { showApp } = require('../app/show');
|
|
161
|
+
await showApp(appKey, { online: options.online, json: options.json });
|
|
162
|
+
} catch (error) {
|
|
163
|
+
logger.error(chalk.red(`Error: ${error.message}`));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
program.command('validate <appOrFile>')
|
|
169
|
+
.description('Validate application or external integration file')
|
|
170
|
+
.option('--type <type>', 'Application type (external) - if set, only checks integration folder')
|
|
171
|
+
.action(async(appOrFile, options) => {
|
|
172
|
+
try {
|
|
173
|
+
const validate = require('../validation/validate');
|
|
174
|
+
const result = await validate.validateAppOrFile(appOrFile, options);
|
|
175
|
+
validate.displayValidationResults(result);
|
|
176
|
+
if (!result.valid) {
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
handleCommandError(error, 'validate');
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
program.command('diff <file1> <file2>')
|
|
186
|
+
.description('Compare two configuration files (for deployment pipeline)')
|
|
187
|
+
.action(async(file1, file2) => {
|
|
188
|
+
try {
|
|
189
|
+
const diff = require('../core/diff');
|
|
190
|
+
const result = await diff.compareFiles(file1, file2);
|
|
191
|
+
diff.formatDiffOutput(result);
|
|
192
|
+
if (!result.identical) {
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
handleCommandError(error, 'diff');
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = { setupUtilityCommands };
|