@aifabrix/builder 2.3.2 → 2.3.3
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/lib/app-run-helpers.js +5 -1
- package/lib/infra.js +10 -6
- package/lib/utils/docker.js +73 -0
- package/lib/utils/environment-checker.js +3 -6
- package/package.json +1 -1
package/lib/app-run-helpers.js
CHANGED
|
@@ -24,6 +24,7 @@ const buildCopy = require('./utils/build-copy');
|
|
|
24
24
|
const logger = require('./utils/logger');
|
|
25
25
|
const { waitForHealthCheck } = require('./utils/health-check');
|
|
26
26
|
const composeGenerator = require('./utils/compose-generator');
|
|
27
|
+
const dockerUtils = require('./utils/docker');
|
|
27
28
|
|
|
28
29
|
const execAsync = promisify(exec);
|
|
29
30
|
|
|
@@ -308,6 +309,9 @@ async function prepareEnvironment(appName, appConfig, options) {
|
|
|
308
309
|
async function startContainer(appName, composePath, port, appConfig = null, debug = false) {
|
|
309
310
|
logger.log(chalk.blue(`Starting ${appName}...`));
|
|
310
311
|
|
|
312
|
+
// Ensure Docker + Compose available and determine correct compose command
|
|
313
|
+
const composeCmdBase = await dockerUtils.ensureDockerAndCompose().then(() => dockerUtils.getComposeCommand());
|
|
314
|
+
|
|
311
315
|
const adminSecretsPath = await infra.ensureAdminSecrets();
|
|
312
316
|
if (debug) {
|
|
313
317
|
logger.log(chalk.gray(`[DEBUG] Admin secrets path: ${adminSecretsPath}`));
|
|
@@ -327,7 +331,7 @@ async function startContainer(appName, composePath, port, appConfig = null, debu
|
|
|
327
331
|
logger.log(chalk.gray(`[DEBUG] Environment variables: ADMIN_SECRETS_PATH=${adminSecretsPath}, POSTGRES_PASSWORD=${postgresPassword ? '***' : '(not set)'}`));
|
|
328
332
|
}
|
|
329
333
|
|
|
330
|
-
const composeCmd =
|
|
334
|
+
const composeCmd = `${composeCmdBase} -f "${composePath}" up -d`;
|
|
331
335
|
if (debug) {
|
|
332
336
|
logger.log(chalk.gray(`[DEBUG] Executing: ${composeCmd}`));
|
|
333
337
|
logger.log(chalk.gray(`[DEBUG] Compose file: ${composePath}`));
|
package/lib/infra.js
CHANGED
|
@@ -20,6 +20,7 @@ const config = require('./config');
|
|
|
20
20
|
const devConfig = require('./utils/dev-config');
|
|
21
21
|
const logger = require('./utils/logger');
|
|
22
22
|
const containerUtils = require('./utils/infra-containers');
|
|
23
|
+
const dockerUtils = require('./utils/docker');
|
|
23
24
|
|
|
24
25
|
// Register Handlebars helper for equality check
|
|
25
26
|
handlebars.registerHelper('eq', (a, b) => a === b);
|
|
@@ -76,8 +77,7 @@ function execAsyncWithCwd(command, options = {}) {
|
|
|
76
77
|
*/
|
|
77
78
|
async function checkDockerAvailability() {
|
|
78
79
|
try {
|
|
79
|
-
await
|
|
80
|
-
await execAsync('docker-compose --version');
|
|
80
|
+
await dockerUtils.ensureDockerAndCompose();
|
|
81
81
|
} catch (error) {
|
|
82
82
|
throw new Error('Docker or Docker Compose is not available. Please install and start Docker.');
|
|
83
83
|
}
|
|
@@ -138,7 +138,8 @@ async function startInfra(developerId = null) {
|
|
|
138
138
|
logger.log(`Using compose file: ${composePath}`);
|
|
139
139
|
logger.log(`Starting infrastructure services for developer ${devId}...`);
|
|
140
140
|
const projectName = getInfraProjectName(devId);
|
|
141
|
-
|
|
141
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
142
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${adminSecretsPath}" up -d`, { cwd: infraDir });
|
|
142
143
|
logger.log('Infrastructure services started successfully');
|
|
143
144
|
|
|
144
145
|
await waitForServices(devId);
|
|
@@ -177,7 +178,8 @@ async function stopInfra() {
|
|
|
177
178
|
try {
|
|
178
179
|
logger.log('Stopping infrastructure services...');
|
|
179
180
|
const projectName = getInfraProjectName(devId);
|
|
180
|
-
|
|
181
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
182
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${adminSecretsPath}" down`, { cwd: infraDir });
|
|
181
183
|
logger.log('Infrastructure services stopped');
|
|
182
184
|
} finally {
|
|
183
185
|
// Keep the compose file for future use
|
|
@@ -213,7 +215,8 @@ async function stopInfraWithVolumes() {
|
|
|
213
215
|
try {
|
|
214
216
|
logger.log('Stopping infrastructure services and removing all data...');
|
|
215
217
|
const projectName = getInfraProjectName(devId);
|
|
216
|
-
|
|
218
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
219
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${adminSecretsPath}" down -v`, { cwd: infraDir });
|
|
217
220
|
logger.log('Infrastructure services stopped and all data removed');
|
|
218
221
|
} finally {
|
|
219
222
|
// Keep the compose file for future use
|
|
@@ -347,7 +350,8 @@ async function restartService(serviceName) {
|
|
|
347
350
|
try {
|
|
348
351
|
logger.log(`Restarting ${serviceName} service...`);
|
|
349
352
|
const projectName = getInfraProjectName(devId);
|
|
350
|
-
|
|
353
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
354
|
+
await execAsyncWithCwd(`${composeCmd} -f "${composePath}" -p ${projectName} --env-file "${adminSecretsPath}" restart ${serviceName}`, { cwd: infraDir });
|
|
351
355
|
logger.log(`${serviceName} service restarted successfully`);
|
|
352
356
|
} finally {
|
|
353
357
|
// Keep the compose file for future use
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker CLI Utilities
|
|
3
|
+
*
|
|
4
|
+
* Detects availability of Docker and determines the correct Docker Compose command
|
|
5
|
+
* across environments (Compose v2 plugin: "docker compose", Compose v1: "docker-compose").
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Docker/Compose detection helpers for AI Fabrix Builder
|
|
8
|
+
* @author AI Fabrix Team
|
|
9
|
+
* @version 2.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const { exec } = require('child_process');
|
|
15
|
+
const { promisify } = require('util');
|
|
16
|
+
|
|
17
|
+
const execAsync = promisify(exec);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Checks that Docker CLI is available.
|
|
21
|
+
* @async
|
|
22
|
+
* @function checkDockerCli
|
|
23
|
+
* @returns {Promise<void>} Resolves if docker is available
|
|
24
|
+
* @throws {Error} If docker is unavailable
|
|
25
|
+
*/
|
|
26
|
+
async function checkDockerCli() {
|
|
27
|
+
await execAsync('docker --version');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Determines the correct Docker Compose command on this system.
|
|
32
|
+
* Tries Docker Compose v2 plugin first: "docker compose", then falls back to v1: "docker-compose".
|
|
33
|
+
*
|
|
34
|
+
* @async
|
|
35
|
+
* @function getComposeCommand
|
|
36
|
+
* @returns {Promise<string>} The compose command to use ("docker compose" or "docker-compose")
|
|
37
|
+
* @throws {Error} If neither v2 nor v1 is available
|
|
38
|
+
*/
|
|
39
|
+
async function getComposeCommand() {
|
|
40
|
+
// Prefer Compose v2 plugin if present
|
|
41
|
+
try {
|
|
42
|
+
await execAsync('docker compose version');
|
|
43
|
+
return 'docker compose';
|
|
44
|
+
} catch (_) {
|
|
45
|
+
// Fall back to legacy docker-compose
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await execAsync('docker-compose --version');
|
|
50
|
+
return 'docker-compose';
|
|
51
|
+
} catch (_) {
|
|
52
|
+
throw new Error('Docker Compose is not available (neither "docker compose" nor "docker-compose" found).');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Ensures Docker and Docker Compose are available, returning the compose command to use.
|
|
58
|
+
* @async
|
|
59
|
+
* @function ensureDockerAndCompose
|
|
60
|
+
* @returns {Promise<string>} The compose command to use
|
|
61
|
+
* @throws {Error} If docker or compose is not available
|
|
62
|
+
*/
|
|
63
|
+
async function ensureDockerAndCompose() {
|
|
64
|
+
await checkDockerCli();
|
|
65
|
+
return await getComposeCommand();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
checkDockerCli,
|
|
70
|
+
getComposeCommand,
|
|
71
|
+
ensureDockerAndCompose
|
|
72
|
+
};
|
|
73
|
+
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const os = require('os');
|
|
15
|
+
const dockerUtils = require('./docker');
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Checks if Docker is installed and available
|
|
@@ -22,12 +23,8 @@ const os = require('os');
|
|
|
22
23
|
*/
|
|
23
24
|
async function checkDocker() {
|
|
24
25
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const execAsync = promisify(exec);
|
|
28
|
-
|
|
29
|
-
await execAsync('docker --version');
|
|
30
|
-
await execAsync('docker-compose --version');
|
|
26
|
+
await dockerUtils.checkDockerCli();
|
|
27
|
+
await dockerUtils.getComposeCommand();
|
|
31
28
|
return 'ok';
|
|
32
29
|
} catch (error) {
|
|
33
30
|
return 'error';
|