mirror of
https://github.com/hoverkraft-tech/compose-action.git
synced 2026-08-31 23:52:49 +08:00
fix: restore post-job compose logs header
Co-authored-by: neilime <314088+neilime@users.noreply.github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
This commit is contained in:
parent
75b024b03b
commit
6f330cd1dc
85
dist/index.js
generated
vendored
85
dist/index.js
generated
vendored
@ -31403,16 +31403,12 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async logs({ services, ...optionsInputs }) {
|
async logs({ services, ...optionsInputs }) {
|
||||||
const commandArgs = this.getDockerComposeCommandArgs("logs", {
|
const options = this.getCommonOptions(optionsInputs);
|
||||||
dockerFlags: optionsInputs.dockerFlags,
|
const { executablePath, executableArgs } = this.getDockerComposeCommandExecution("logs", services, options);
|
||||||
composeFlags: optionsInputs.composeFlags,
|
|
||||||
composeFiles: optionsInputs.composeFiles,
|
|
||||||
commandArgs: services
|
|
||||||
});
|
|
||||||
return new Promise((resolve2) => {
|
return new Promise((resolve2) => {
|
||||||
let settled = false;
|
let settled = false;
|
||||||
const childProcess = spawn2("docker", commandArgs, {
|
const childProcess = spawn2(executablePath, executableArgs, {
|
||||||
cwd: optionsInputs.cwd
|
cwd: options.cwd
|
||||||
});
|
});
|
||||||
childProcess.on("error", (error2) => {
|
childProcess.on("error", (error2) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
@ -31433,10 +31429,10 @@ var DockerComposeService = class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
childProcess.stdout.on("data", (chunk) => {
|
childProcess.stdout.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stdout");
|
||||||
});
|
});
|
||||||
childProcess.stderr.on("data", (chunk) => {
|
childProcess.stderr.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stderr");
|
||||||
});
|
});
|
||||||
childProcess.on("close", (exitCode, signal) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
@ -31468,30 +31464,55 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Builds docker CLI arguments in the order expected by `docker compose`.
|
|
||||||
*/
|
|
||||||
getDockerComposeCommandArgs(command, {
|
|
||||||
dockerFlags,
|
|
||||||
composeFlags,
|
|
||||||
composeFiles,
|
|
||||||
commandArgs
|
|
||||||
}) {
|
|
||||||
return [
|
|
||||||
...dockerFlags,
|
|
||||||
"compose",
|
|
||||||
...composeFlags,
|
|
||||||
...composeFiles.flatMap((composeFile) => ["-f", composeFile]),
|
|
||||||
command,
|
|
||||||
...commandArgs
|
|
||||||
];
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Formats docker-compose errors into proper Error objects with readable messages
|
* Formats docker-compose errors into proper Error objects with readable messages
|
||||||
*/
|
*/
|
||||||
formatDockerComposeError(error2) {
|
formatDockerComposeError(error2) {
|
||||||
|
return new Error(this.getDockerComposeErrorMessage(error2));
|
||||||
|
}
|
||||||
|
getDockerComposeCommandExecution(command, commandArgs, options) {
|
||||||
|
const composeArgs = [
|
||||||
|
...this.getComposeOptionArgs(options.composeOptions),
|
||||||
|
...this.getConfigArgs(options.config),
|
||||||
|
command,
|
||||||
|
...this.getComposeOptionArgs(options.commandOptions),
|
||||||
|
...commandArgs
|
||||||
|
];
|
||||||
|
if (options.executable?.standalone) {
|
||||||
|
return {
|
||||||
|
executablePath: options.executable.executablePath ?? "docker-compose",
|
||||||
|
executableArgs: composeArgs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
executablePath: options.executable?.executablePath ?? "docker",
|
||||||
|
executableArgs: [
|
||||||
|
...this.getComposeOptionArgs(options.executable?.options),
|
||||||
|
"compose",
|
||||||
|
...composeArgs
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getConfigArgs(config) {
|
||||||
|
if (typeof config === "undefined") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (typeof config === "string") {
|
||||||
|
return ["-f", config];
|
||||||
|
}
|
||||||
|
return config.flatMap((item) => ["-f", item]);
|
||||||
|
}
|
||||||
|
getComposeOptionArgs(composeOptions) {
|
||||||
|
if (!composeOptions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return composeOptions.flatMap(
|
||||||
|
(option) => Array.isArray(option) ? option : [option]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
getDockerComposeErrorMessage(error2) {
|
||||||
if (error2 instanceof Error) {
|
if (error2 instanceof Error) {
|
||||||
return error2;
|
return error2.message;
|
||||||
}
|
}
|
||||||
if (this.isDockerComposeResult(error2)) {
|
if (this.isDockerComposeResult(error2)) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
@ -31510,12 +31531,12 @@ var DockerComposeService = class {
|
|||||||
parts.push("\nStandard output:");
|
parts.push("\nStandard output:");
|
||||||
parts.push(error2.out.trim());
|
parts.push(error2.out.trim());
|
||||||
}
|
}
|
||||||
return new Error(parts.join("\n"));
|
return parts.join("\n");
|
||||||
}
|
}
|
||||||
if (typeof error2 === "string") {
|
if (typeof error2 === "string") {
|
||||||
return new Error(error2);
|
return error2;
|
||||||
}
|
}
|
||||||
return new Error(JSON.stringify(error2));
|
return JSON.stringify(error2);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Type guard to check if an object is a docker-compose result
|
* Type guard to check if an object is a docker-compose result
|
||||||
|
|||||||
86
dist/post.js
generated
vendored
86
dist/post.js
generated
vendored
@ -27140,16 +27140,12 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async logs({ services, ...optionsInputs }) {
|
async logs({ services, ...optionsInputs }) {
|
||||||
const commandArgs = this.getDockerComposeCommandArgs("logs", {
|
const options = this.getCommonOptions(optionsInputs);
|
||||||
dockerFlags: optionsInputs.dockerFlags,
|
const { executablePath, executableArgs } = this.getDockerComposeCommandExecution("logs", services, options);
|
||||||
composeFlags: optionsInputs.composeFlags,
|
|
||||||
composeFiles: optionsInputs.composeFiles,
|
|
||||||
commandArgs: services
|
|
||||||
});
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let settled = false;
|
let settled = false;
|
||||||
const childProcess = spawn("docker", commandArgs, {
|
const childProcess = spawn(executablePath, executableArgs, {
|
||||||
cwd: optionsInputs.cwd
|
cwd: options.cwd
|
||||||
});
|
});
|
||||||
childProcess.on("error", (error2) => {
|
childProcess.on("error", (error2) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
@ -27170,10 +27166,10 @@ var DockerComposeService = class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
childProcess.stdout.on("data", (chunk) => {
|
childProcess.stdout.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stdout");
|
||||||
});
|
});
|
||||||
childProcess.stderr.on("data", (chunk) => {
|
childProcess.stderr.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stderr");
|
||||||
});
|
});
|
||||||
childProcess.on("close", (exitCode, signal) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
@ -27205,30 +27201,55 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Builds docker CLI arguments in the order expected by `docker compose`.
|
|
||||||
*/
|
|
||||||
getDockerComposeCommandArgs(command, {
|
|
||||||
dockerFlags,
|
|
||||||
composeFlags,
|
|
||||||
composeFiles,
|
|
||||||
commandArgs
|
|
||||||
}) {
|
|
||||||
return [
|
|
||||||
...dockerFlags,
|
|
||||||
"compose",
|
|
||||||
...composeFlags,
|
|
||||||
...composeFiles.flatMap((composeFile) => ["-f", composeFile]),
|
|
||||||
command,
|
|
||||||
...commandArgs
|
|
||||||
];
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Formats docker-compose errors into proper Error objects with readable messages
|
* Formats docker-compose errors into proper Error objects with readable messages
|
||||||
*/
|
*/
|
||||||
formatDockerComposeError(error2) {
|
formatDockerComposeError(error2) {
|
||||||
|
return new Error(this.getDockerComposeErrorMessage(error2));
|
||||||
|
}
|
||||||
|
getDockerComposeCommandExecution(command, commandArgs, options) {
|
||||||
|
const composeArgs = [
|
||||||
|
...this.getComposeOptionArgs(options.composeOptions),
|
||||||
|
...this.getConfigArgs(options.config),
|
||||||
|
command,
|
||||||
|
...this.getComposeOptionArgs(options.commandOptions),
|
||||||
|
...commandArgs
|
||||||
|
];
|
||||||
|
if (options.executable?.standalone) {
|
||||||
|
return {
|
||||||
|
executablePath: options.executable.executablePath ?? "docker-compose",
|
||||||
|
executableArgs: composeArgs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
executablePath: options.executable?.executablePath ?? "docker",
|
||||||
|
executableArgs: [
|
||||||
|
...this.getComposeOptionArgs(options.executable?.options),
|
||||||
|
"compose",
|
||||||
|
...composeArgs
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getConfigArgs(config) {
|
||||||
|
if (typeof config === "undefined") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (typeof config === "string") {
|
||||||
|
return ["-f", config];
|
||||||
|
}
|
||||||
|
return config.flatMap((item) => ["-f", item]);
|
||||||
|
}
|
||||||
|
getComposeOptionArgs(composeOptions) {
|
||||||
|
if (!composeOptions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return composeOptions.flatMap(
|
||||||
|
(option) => Array.isArray(option) ? option : [option]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
getDockerComposeErrorMessage(error2) {
|
||||||
if (error2 instanceof Error) {
|
if (error2 instanceof Error) {
|
||||||
return error2;
|
return error2.message;
|
||||||
}
|
}
|
||||||
if (this.isDockerComposeResult(error2)) {
|
if (this.isDockerComposeResult(error2)) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
@ -27247,12 +27268,12 @@ var DockerComposeService = class {
|
|||||||
parts.push("\nStandard output:");
|
parts.push("\nStandard output:");
|
||||||
parts.push(error2.out.trim());
|
parts.push(error2.out.trim());
|
||||||
}
|
}
|
||||||
return new Error(parts.join("\n"));
|
return parts.join("\n");
|
||||||
}
|
}
|
||||||
if (typeof error2 === "string") {
|
if (typeof error2 === "string") {
|
||||||
return new Error(error2);
|
return error2;
|
||||||
}
|
}
|
||||||
return new Error(JSON.stringify(error2));
|
return JSON.stringify(error2);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Type guard to check if an object is a docker-compose result
|
* Type guard to check if an object is a docker-compose result
|
||||||
@ -27392,6 +27413,7 @@ async function run() {
|
|||||||
const dockerComposeService = new DockerComposeService();
|
const dockerComposeService = new DockerComposeService();
|
||||||
const inputs = inputService.getInputs();
|
const inputs = inputService.getInputs();
|
||||||
try {
|
try {
|
||||||
|
loggerService.debug("docker compose logs:");
|
||||||
const { error: error2 } = await dockerComposeService.logs({
|
const { error: error2 } = await dockerComposeService.logs({
|
||||||
dockerFlags: inputs.dockerFlags,
|
dockerFlags: inputs.dockerFlags,
|
||||||
composeFiles: inputs.composeFiles,
|
composeFiles: inputs.composeFiles,
|
||||||
|
|||||||
@ -134,6 +134,7 @@ describe("run", () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
expect(debugMock).toHaveBeenCalledWith("docker compose logs:");
|
||||||
expect(debugMock).toHaveBeenCalledWith(
|
expect(debugMock).toHaveBeenCalledWith(
|
||||||
"docker compose error:\ntest logs error",
|
"docker compose error:\ntest logs error",
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,6 +16,8 @@ export async function run(): Promise<void> {
|
|||||||
const inputs = inputService.getInputs();
|
const inputs = inputService.getInputs();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
loggerService.debug("docker compose logs:");
|
||||||
|
|
||||||
const { error } = await dockerComposeService.logs({
|
const { error } = await dockerComposeService.logs({
|
||||||
dockerFlags: inputs.dockerFlags,
|
dockerFlags: inputs.dockerFlags,
|
||||||
composeFiles: inputs.composeFiles,
|
composeFiles: inputs.composeFiles,
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
import { EventEmitter } from "node:events";
|
||||||
import type {
|
import type {
|
||||||
IDockerComposeOptions,
|
IDockerComposeOptions,
|
||||||
IDockerComposeResult,
|
IDockerComposeResult,
|
||||||
} from "docker-compose";
|
} from "docker-compose";
|
||||||
import { EventEmitter } from "node:events";
|
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
// Mock docker-compose before importing the module under test
|
// Mock docker-compose before importing the module under test
|
||||||
@ -357,13 +357,13 @@ describe("DockerComposeService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("logs", () => {
|
describe("logs", () => {
|
||||||
it("should stream logs with correct command arguments", async () => {
|
it("should stream logs with wrapper-compatible command arguments", async () => {
|
||||||
const debugMock = vi.fn();
|
const debugMock = vi.fn();
|
||||||
const logsInputs = {
|
const logsInputs = {
|
||||||
dockerFlags: [] as string[],
|
dockerFlags: ["--context", "dev"] as string[],
|
||||||
composeFiles: ["docker-compose.yml"],
|
composeFiles: ["docker-compose.yml"],
|
||||||
services: ["helloworld2", "helloworld3"],
|
services: ["helloworld2", "helloworld3"],
|
||||||
composeFlags: [] as string[],
|
composeFlags: ["--profile", "ci"] as string[],
|
||||||
cwd: "/current/working/dir",
|
cwd: "/current/working/dir",
|
||||||
serviceLogger: debugMock,
|
serviceLogger: debugMock,
|
||||||
};
|
};
|
||||||
@ -380,22 +380,31 @@ describe("DockerComposeService", () => {
|
|||||||
|
|
||||||
const logsPromise = service.logs(logsInputs);
|
const logsPromise = service.logs(logsInputs);
|
||||||
|
|
||||||
expect(spawnMock).toHaveBeenCalledWith("docker", [
|
expect(spawnMock).toHaveBeenCalledWith(
|
||||||
|
"docker",
|
||||||
|
[
|
||||||
|
"--context",
|
||||||
|
"dev",
|
||||||
"compose",
|
"compose",
|
||||||
|
"--profile",
|
||||||
|
"ci",
|
||||||
"-f",
|
"-f",
|
||||||
"docker-compose.yml",
|
"docker-compose.yml",
|
||||||
"logs",
|
"logs",
|
||||||
"helloworld2",
|
"helloworld2",
|
||||||
"helloworld3",
|
"helloworld3",
|
||||||
], {
|
],
|
||||||
|
{
|
||||||
cwd: "/current/working/dir",
|
cwd: "/current/working/dir",
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
stdout.emit("data", Buffer.from("logs"));
|
stdout.emit("data", Buffer.from("logs"));
|
||||||
stderr.emit("data", Buffer.from("error logs"));
|
stderr.emit("data", Buffer.from("error logs"));
|
||||||
childProcess.emit("close", 0);
|
childProcess.emit("close", 0);
|
||||||
|
|
||||||
await expect(logsPromise).resolves.toEqual({ error: "", output: "" });
|
await expect(logsPromise).resolves.toEqual({ error: "", output: "" });
|
||||||
|
|
||||||
expect(debugMock).toHaveBeenNthCalledWith(1, "logs");
|
expect(debugMock).toHaveBeenNthCalledWith(1, "logs");
|
||||||
expect(debugMock).toHaveBeenNthCalledWith(2, "error logs");
|
expect(debugMock).toHaveBeenNthCalledWith(2, "error logs");
|
||||||
});
|
});
|
||||||
@ -420,19 +429,6 @@ describe("DockerComposeService", () => {
|
|||||||
|
|
||||||
const logsPromise = service.logs(logsInputs);
|
const logsPromise = service.logs(logsInputs);
|
||||||
|
|
||||||
expect(spawnMock).toHaveBeenCalledWith("docker", [
|
|
||||||
"--context",
|
|
||||||
"dev",
|
|
||||||
"compose",
|
|
||||||
"--profile",
|
|
||||||
"ci",
|
|
||||||
"-f",
|
|
||||||
"docker-compose.yml",
|
|
||||||
"logs",
|
|
||||||
], {
|
|
||||||
cwd: "/current/working/dir",
|
|
||||||
});
|
|
||||||
|
|
||||||
childProcess.emit("close", 1);
|
childProcess.emit("close", 1);
|
||||||
|
|
||||||
await expect(logsPromise).resolves.toEqual({
|
await expect(logsPromise).resolves.toEqual({
|
||||||
@ -516,7 +512,8 @@ describe("DockerComposeService", () => {
|
|||||||
spawnMock.mockReturnValue(childProcess);
|
spawnMock.mockReturnValue(childProcess);
|
||||||
|
|
||||||
await expect(service.logs(logsInputs)).resolves.toEqual({
|
await expect(service.logs(logsInputs)).resolves.toEqual({
|
||||||
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
error:
|
||||||
|
"Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
output: "",
|
output: "",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -59,52 +59,54 @@ export class DockerComposeService {
|
|||||||
error: string;
|
error: string;
|
||||||
output: string;
|
output: string;
|
||||||
}> {
|
}> {
|
||||||
const commandArgs = this.getDockerComposeCommandArgs("logs", {
|
const options = this.getCommonOptions(optionsInputs);
|
||||||
dockerFlags: optionsInputs.dockerFlags,
|
const { executablePath, executableArgs } =
|
||||||
composeFlags: optionsInputs.composeFlags,
|
this.getDockerComposeCommandExecution("logs", services, options);
|
||||||
composeFiles: optionsInputs.composeFiles,
|
|
||||||
commandArgs: services,
|
|
||||||
});
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
let settled = false;
|
let settled = false;
|
||||||
const childProcess = spawn("docker", commandArgs, {
|
const childProcess = spawn(executablePath, executableArgs, {
|
||||||
cwd: optionsInputs.cwd,
|
cwd: options.cwd,
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.on("error", (error) => {
|
childProcess.on("error", (error) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
settled = true;
|
settled = true;
|
||||||
resolve({
|
resolve({
|
||||||
error: `Unable to collect docker compose logs: ${error.message}`,
|
error: `Unable to collect docker compose logs: ${error.message}`,
|
||||||
output: "",
|
output: "",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!childProcess.stdout || !childProcess.stderr) {
|
if (!childProcess.stdout || !childProcess.stderr) {
|
||||||
settled = true;
|
settled = true;
|
||||||
resolve({
|
resolve({
|
||||||
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
error:
|
||||||
|
"Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
output: "",
|
output: "",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
childProcess.stdout.on("data", (chunk: Buffer | string) => {
|
childProcess.stdout.on("data", (chunk: Buffer | string) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stdout");
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.stderr.on("data", (chunk: Buffer | string) => {
|
childProcess.stderr.on("data", (chunk: Buffer | string) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
options.callback?.(Buffer.from(chunk), "stderr");
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.on("close", (exitCode, signal) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
if (settled) {
|
if (settled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
settled = true;
|
settled = true;
|
||||||
resolve({
|
resolve({
|
||||||
error:
|
error: signal
|
||||||
signal
|
|
||||||
? `Docker Compose logs command failed with signal ${signal}`
|
? `Docker Compose logs command failed with signal ${signal}`
|
||||||
: exitCode !== null && exitCode !== 0
|
: exitCode !== null && exitCode !== 0
|
||||||
? `Docker Compose logs command failed with exit code ${exitCode}`
|
? `Docker Compose logs command failed with exit code ${exitCode}`
|
||||||
@ -134,47 +136,81 @@ export class DockerComposeService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds docker CLI arguments in the order expected by `docker compose`.
|
|
||||||
*/
|
|
||||||
private getDockerComposeCommandArgs(
|
|
||||||
command: "logs",
|
|
||||||
{
|
|
||||||
dockerFlags,
|
|
||||||
composeFlags,
|
|
||||||
composeFiles,
|
|
||||||
commandArgs,
|
|
||||||
}: {
|
|
||||||
dockerFlags: string[];
|
|
||||||
composeFlags: string[];
|
|
||||||
composeFiles: string[];
|
|
||||||
commandArgs: string[];
|
|
||||||
},
|
|
||||||
): string[] {
|
|
||||||
return [
|
|
||||||
...dockerFlags,
|
|
||||||
"compose",
|
|
||||||
...composeFlags,
|
|
||||||
...composeFiles.flatMap((composeFile) => ["-f", composeFile]),
|
|
||||||
command,
|
|
||||||
...commandArgs,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats docker-compose errors into proper Error objects with readable messages
|
* Formats docker-compose errors into proper Error objects with readable messages
|
||||||
*/
|
*/
|
||||||
private formatDockerComposeError(error: unknown): Error {
|
private formatDockerComposeError(error: unknown): Error {
|
||||||
// If it's already an Error, return it
|
return new Error(this.getDockerComposeErrorMessage(error));
|
||||||
if (error instanceof Error) {
|
}
|
||||||
return error;
|
|
||||||
|
private getDockerComposeCommandExecution(
|
||||||
|
command: string,
|
||||||
|
commandArgs: string[],
|
||||||
|
options: IDockerComposeOptions,
|
||||||
|
): {
|
||||||
|
executablePath: string;
|
||||||
|
executableArgs: string[];
|
||||||
|
} {
|
||||||
|
const composeArgs = [
|
||||||
|
...this.getComposeOptionArgs(options.composeOptions),
|
||||||
|
...this.getConfigArgs(options.config),
|
||||||
|
command,
|
||||||
|
...this.getComposeOptionArgs(options.commandOptions),
|
||||||
|
...commandArgs,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (options.executable?.standalone) {
|
||||||
|
return {
|
||||||
|
executablePath: options.executable.executablePath ?? "docker-compose",
|
||||||
|
executableArgs: composeArgs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
executablePath: options.executable?.executablePath ?? "docker",
|
||||||
|
executableArgs: [
|
||||||
|
...this.getComposeOptionArgs(options.executable?.options),
|
||||||
|
"compose",
|
||||||
|
...composeArgs,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getConfigArgs(config: IDockerComposeOptions["config"]): string[] {
|
||||||
|
if (typeof config === "undefined") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof config === "string") {
|
||||||
|
return ["-f", config];
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.flatMap((item) => ["-f", item]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getComposeOptionArgs(
|
||||||
|
composeOptions:
|
||||||
|
| IDockerComposeOptions["composeOptions"]
|
||||||
|
| IDockerComposeOptions["commandOptions"]
|
||||||
|
| NonNullable<IDockerComposeOptions["executable"]>["options"],
|
||||||
|
): string[] {
|
||||||
|
if (!composeOptions) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return composeOptions.flatMap((option) =>
|
||||||
|
Array.isArray(option) ? option : [option],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDockerComposeErrorMessage(error: unknown): string {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return error.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle docker-compose result objects
|
|
||||||
if (this.isDockerComposeResult(error)) {
|
if (this.isDockerComposeResult(error)) {
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
// Add exit code information
|
|
||||||
if (error.exitCode !== null) {
|
if (error.exitCode !== null) {
|
||||||
parts.push(
|
parts.push(
|
||||||
`Docker Compose command failed with exit code ${error.exitCode}`,
|
`Docker Compose command failed with exit code ${error.exitCode}`,
|
||||||
@ -183,30 +219,25 @@ export class DockerComposeService {
|
|||||||
parts.push("Docker Compose command failed");
|
parts.push("Docker Compose command failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add error stream output if available
|
|
||||||
if (error.err?.trim()) {
|
if (error.err?.trim()) {
|
||||||
parts.push("\nError output:");
|
parts.push("\nError output:");
|
||||||
parts.push(error.err.trim());
|
parts.push(error.err.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add standard output if available and different from error output
|
|
||||||
if (error.out?.trim() && error.out !== error.err) {
|
if (error.out?.trim() && error.out !== error.err) {
|
||||||
parts.push("\nStandard output:");
|
parts.push("\nStandard output:");
|
||||||
parts.push(error.out.trim());
|
parts.push(error.out.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Error(parts.join("\n"));
|
return parts.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle string errors
|
|
||||||
if (typeof error === "string") {
|
if (typeof error === "string") {
|
||||||
return new Error(error);
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for unknown error types
|
return JSON.stringify(error);
|
||||||
return new Error(JSON.stringify(error));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type guard to check if an object is a docker-compose result
|
* Type guard to check if an object is a docker-compose result
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user