@forge/cli-shared

9.4.1-next.39.4.1-next.3-experimental-e9e08bb
out/tunnel/compose-project-lifecycle.js
+out/tunnel/compose-project-lifecycle.jsNew file
+105
Index: package/out/tunnel/compose-project-lifecycle.js
===================================================================
--- package/out/tunnel/compose-project-lifecycle.js
+++ package/out/tunnel/compose-project-lifecycle.js
@@ -0,0 +1,105 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.parseComposePs = exports.ComposeProjectLifecycle = void 0;
+const tslib_1 = require("tslib");
+const path = tslib_1.__importStar(require("path"));
+const docker_compose_1 = require("docker-compose");
+const docker_compose_lifecycle_1 = require("./docker-compose-lifecycle");
+const defaultAdapter = {
+    pullOne: (service, options) => (0, docker_compose_1.pullOne)(service, options),
+    exec: (command, args, options) => (0, docker_compose_1.execCompose)(command, args, options),
+    down: (options) => (0, docker_compose_1.downAll)(options)
+};
+class ComposeProjectLifecycle {
+    configPath;
+    projectName;
+    logger;
+    adapter;
+    constructor(configPath, projectName, logger, adapter = defaultAdapter) {
+        this.configPath = configPath;
+        this.projectName = projectName;
+        this.logger = logger;
+        this.adapter = adapter;
+    }
+    options(log = false) {
+        return {
+            cwd: path.dirname(this.configPath),
+            log,
+            config: this.configPath,
+            composeOptions: [`-p${this.projectName}`],
+            callback: (0, docker_compose_lifecycle_1.createDockerLifecycleLogFilter)(this.logger)
+        };
+    }
+    async pull(services) {
+        for (const service of services) {
+            try {
+                await this.adapter.pullOne(service, this.options());
+            }
+            catch (error) {
+                throw new Error(`Unable to pull the ${service} image: ${(0, docker_compose_lifecycle_1.getDockerComposeErrorMessage)(error)}`);
+            }
+        }
+    }
+    async up(services) {
+        try {
+            await this.adapter.exec('up', ['--detach', '--no-build', '--remove-orphans', ...services], this.options());
+        }
+        catch (error) {
+            throw new Error(`Unable to start the Docker Compose project: ${(0, docker_compose_lifecycle_1.getDockerComposeErrorMessage)(error)}`);
+        }
+    }
+    async down() {
+        try {
+            await this.adapter.down(this.options());
+        }
+        catch (error) {
+            throw new Error(`Unable to stop the Docker Compose project: ${(0, docker_compose_lifecycle_1.getDockerComposeErrorMessage)(error)}`);
+        }
+    }
+    async states() {
+        try {
+            const result = await this.adapter.exec('ps', ['--all', '--format', 'json'], this.options());
+            return (0, exports.parseComposePs)(result.out ?? '');
+        }
+        catch (error) {
+            throw new Error(`Unable to inspect the Docker Compose project: ${(0, docker_compose_lifecycle_1.getDockerComposeErrorMessage)(error)}`);
+        }
+    }
+    async logs(service, lines = 80) {
+        try {
+            const result = await this.adapter.exec('logs', ['--no-color', '--tail', lines.toString(), service], this.options());
+            return [result.out, result.err].filter(Boolean).join('\n').trim();
+        }
+        catch (error) {
+            return (0, docker_compose_lifecycle_1.getDockerComposeErrorMessage)(error);
+        }
+    }
+}
+exports.ComposeProjectLifecycle = ComposeProjectLifecycle;
+const parseComposePs = (output) => {
+    const trimmed = output.trim();
+    if (!trimmed)
+        return [];
+    const records = (() => {
+        try {
+            const parsed = JSON.parse(trimmed);
+            return Array.isArray(parsed) ? parsed : [parsed];
+        }
+        catch {
+            return trimmed
+                .split('\n')
+                .filter(Boolean)
+                .map((line) => JSON.parse(line));
+        }
+    })();
+    return records.map((item) => {
+        const value = item;
+        return {
+            name: String(value.Name ?? value.name ?? ''),
+            service: String(value.Service ?? value.service ?? ''),
+            state: String(value.State ?? value.state ?? ''),
+            health: value.Health == null && value.health == null ? undefined : String(value.Health ?? value.health)
+        };
+    });
+};
+exports.parseComposePs = parseComposePs;