mirror of
https://github.com/hoverkraft-tech/compose-action.git
synced 2026-08-31 23:52:49 +08:00
fix: avoid buffering compose logs during cleanup
Co-authored-by: neilime <314088+neilime@users.noreply.github.com>
This commit is contained in:
parent
1b4933e684
commit
e7fba772e2
33
dist/index.js
generated
vendored
33
dist/index.js
generated
vendored
@ -31409,20 +31409,42 @@ var DockerComposeService = class {
|
|||||||
composeFiles: optionsInputs.composeFiles,
|
composeFiles: optionsInputs.composeFiles,
|
||||||
commandArgs: services
|
commandArgs: services
|
||||||
});
|
});
|
||||||
return await new Promise((resolve2, reject) => {
|
return new Promise((resolve2) => {
|
||||||
|
let settled = false;
|
||||||
const childProcess = spawn2("docker", commandArgs, {
|
const childProcess = spawn2("docker", commandArgs, {
|
||||||
cwd: optionsInputs.cwd
|
cwd: optionsInputs.cwd
|
||||||
});
|
});
|
||||||
childProcess.on("error", reject);
|
childProcess.on("error", (error2) => {
|
||||||
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
|
resolve2({
|
||||||
|
error: `Unable to collect docker compose logs: ${error2.message}`,
|
||||||
|
output: ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!childProcess.stdout || !childProcess.stderr) {
|
||||||
|
settled = true;
|
||||||
|
resolve2({
|
||||||
|
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
|
output: ""
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
childProcess.stdout.on("data", (chunk) => {
|
childProcess.stdout.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.stderr.on("data", (chunk) => {
|
childProcess.stderr.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.on("close", (exitCode) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
resolve2({
|
resolve2({
|
||||||
error: exitCode && exitCode !== 0 ? `Docker Compose logs command failed with exit code ${exitCode}` : "",
|
error: signal ? `Docker Compose logs command failed with signal ${signal}` : exitCode !== null && exitCode !== 0 ? `Docker Compose logs command failed with exit code ${exitCode}` : "",
|
||||||
output: ""
|
output: ""
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -31446,6 +31468,9 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Builds docker CLI arguments in the order expected by `docker compose`.
|
||||||
|
*/
|
||||||
getDockerComposeCommandArgs(command, {
|
getDockerComposeCommandArgs(command, {
|
||||||
dockerFlags,
|
dockerFlags,
|
||||||
composeFlags,
|
composeFlags,
|
||||||
|
|||||||
33
dist/post.js
generated
vendored
33
dist/post.js
generated
vendored
@ -27146,20 +27146,42 @@ var DockerComposeService = class {
|
|||||||
composeFiles: optionsInputs.composeFiles,
|
composeFiles: optionsInputs.composeFiles,
|
||||||
commandArgs: services
|
commandArgs: services
|
||||||
});
|
});
|
||||||
return await new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
|
let settled = false;
|
||||||
const childProcess = spawn("docker", commandArgs, {
|
const childProcess = spawn("docker", commandArgs, {
|
||||||
cwd: optionsInputs.cwd
|
cwd: optionsInputs.cwd
|
||||||
});
|
});
|
||||||
childProcess.on("error", reject);
|
childProcess.on("error", (error2) => {
|
||||||
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
|
resolve({
|
||||||
|
error: `Unable to collect docker compose logs: ${error2.message}`,
|
||||||
|
output: ""
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!childProcess.stdout || !childProcess.stderr) {
|
||||||
|
settled = true;
|
||||||
|
resolve({
|
||||||
|
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
|
output: ""
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
childProcess.stdout.on("data", (chunk) => {
|
childProcess.stdout.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.stderr.on("data", (chunk) => {
|
childProcess.stderr.on("data", (chunk) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.on("close", (exitCode) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
resolve({
|
resolve({
|
||||||
error: exitCode && exitCode !== 0 ? `Docker Compose logs command failed with exit code ${exitCode}` : "",
|
error: signal ? `Docker Compose logs command failed with signal ${signal}` : exitCode !== null && exitCode !== 0 ? `Docker Compose logs command failed with exit code ${exitCode}` : "",
|
||||||
output: ""
|
output: ""
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -27183,6 +27205,9 @@ var DockerComposeService = class {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Builds docker CLI arguments in the order expected by `docker compose`.
|
||||||
|
*/
|
||||||
getDockerComposeCommandArgs(command, {
|
getDockerComposeCommandArgs(command, {
|
||||||
dockerFlags,
|
dockerFlags,
|
||||||
composeFlags,
|
composeFlags,
|
||||||
|
|||||||
@ -440,5 +440,85 @@ describe("DockerComposeService", () => {
|
|||||||
output: "",
|
output: "",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should return a non-fatal error message when logs command is terminated by a signal", async () => {
|
||||||
|
const logsInputs = {
|
||||||
|
dockerFlags: [] as string[],
|
||||||
|
composeFiles: ["docker-compose.yml"] as string[],
|
||||||
|
services: [] as string[],
|
||||||
|
composeFlags: [] as string[],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
serviceLogger: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const childProcess = new EventEmitter() as EventEmitter & {
|
||||||
|
stdout: EventEmitter;
|
||||||
|
stderr: EventEmitter;
|
||||||
|
};
|
||||||
|
childProcess.stdout = new EventEmitter();
|
||||||
|
childProcess.stderr = new EventEmitter();
|
||||||
|
spawnMock.mockReturnValue(childProcess);
|
||||||
|
|
||||||
|
const logsPromise = service.logs(logsInputs);
|
||||||
|
|
||||||
|
childProcess.emit("close", null, "SIGTERM");
|
||||||
|
|
||||||
|
await expect(logsPromise).resolves.toEqual({
|
||||||
|
error: "Docker Compose logs command failed with signal SIGTERM",
|
||||||
|
output: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a non-fatal error message when spawning logs fails", async () => {
|
||||||
|
const logsInputs = {
|
||||||
|
dockerFlags: [] as string[],
|
||||||
|
composeFiles: ["docker-compose.yml"] as string[],
|
||||||
|
services: [] as string[],
|
||||||
|
composeFlags: [] as string[],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
serviceLogger: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const childProcess = new EventEmitter() as EventEmitter & {
|
||||||
|
stdout: EventEmitter;
|
||||||
|
stderr: EventEmitter;
|
||||||
|
};
|
||||||
|
childProcess.stdout = new EventEmitter();
|
||||||
|
childProcess.stderr = new EventEmitter();
|
||||||
|
spawnMock.mockReturnValue(childProcess);
|
||||||
|
|
||||||
|
const logsPromise = service.logs(logsInputs);
|
||||||
|
|
||||||
|
childProcess.emit("error", new Error("spawn ENOENT"));
|
||||||
|
|
||||||
|
await expect(logsPromise).resolves.toEqual({
|
||||||
|
error: "Unable to collect docker compose logs: spawn ENOENT",
|
||||||
|
output: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a non-fatal error message when output streams are unavailable", async () => {
|
||||||
|
const logsInputs = {
|
||||||
|
dockerFlags: [] as string[],
|
||||||
|
composeFiles: ["docker-compose.yml"] as string[],
|
||||||
|
services: [] as string[],
|
||||||
|
composeFlags: [] as string[],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
serviceLogger: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const childProcess = new EventEmitter() as EventEmitter & {
|
||||||
|
stdout: EventEmitter | null;
|
||||||
|
stderr: EventEmitter | null;
|
||||||
|
};
|
||||||
|
childProcess.stdout = null;
|
||||||
|
childProcess.stderr = null;
|
||||||
|
spawnMock.mockReturnValue(childProcess);
|
||||||
|
|
||||||
|
await expect(service.logs(logsInputs)).resolves.toEqual({
|
||||||
|
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
|
output: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -66,22 +66,47 @@ export class DockerComposeService {
|
|||||||
commandArgs: services,
|
commandArgs: services,
|
||||||
});
|
});
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
|
let settled = false;
|
||||||
const childProcess = spawn("docker", commandArgs, {
|
const childProcess = spawn("docker", commandArgs, {
|
||||||
cwd: optionsInputs.cwd,
|
cwd: optionsInputs.cwd,
|
||||||
});
|
});
|
||||||
|
|
||||||
childProcess.on("error", reject);
|
childProcess.on("error", (error) => {
|
||||||
childProcess.stdout.on("data", (chunk: Buffer) => {
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
|
resolve({
|
||||||
|
error: `Unable to collect docker compose logs: ${error.message}`,
|
||||||
|
output: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (!childProcess.stdout || !childProcess.stderr) {
|
||||||
|
settled = true;
|
||||||
|
resolve({
|
||||||
|
error: "Unable to collect docker compose logs: stdout/stderr unavailable",
|
||||||
|
output: "",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
childProcess.stdout.on("data", (chunk: Buffer | string) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.stderr.on("data", (chunk: Buffer) => {
|
childProcess.stderr.on("data", (chunk: Buffer | string) => {
|
||||||
optionsInputs.serviceLogger(chunk.toString());
|
optionsInputs.serviceLogger(chunk.toString());
|
||||||
});
|
});
|
||||||
childProcess.on("close", (exitCode) => {
|
childProcess.on("close", (exitCode, signal) => {
|
||||||
|
if (settled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settled = true;
|
||||||
resolve({
|
resolve({
|
||||||
error:
|
error:
|
||||||
exitCode && exitCode !== 0
|
signal
|
||||||
|
? `Docker Compose logs command failed with signal ${signal}`
|
||||||
|
: exitCode !== null && exitCode !== 0
|
||||||
? `Docker Compose logs command failed with exit code ${exitCode}`
|
? `Docker Compose logs command failed with exit code ${exitCode}`
|
||||||
: "",
|
: "",
|
||||||
output: "",
|
output: "",
|
||||||
@ -109,8 +134,11 @@ export class DockerComposeService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds docker CLI arguments in the order expected by `docker compose`.
|
||||||
|
*/
|
||||||
private getDockerComposeCommandArgs(
|
private getDockerComposeCommandArgs(
|
||||||
command: string,
|
command: "logs",
|
||||||
{
|
{
|
||||||
dockerFlags,
|
dockerFlags,
|
||||||
composeFlags,
|
composeFlags,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user