mirror of
https://github.com/hoverkraft-tech/compose-action.git
synced 2026-01-10 06:33:06 +08:00
fix: ensure given docker-compose file(s) are valid and at least one is provided
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
This commit is contained in:
parent
8d12e916ef
commit
2bd57c29bd
8
.github/workflows/__check-action.yml
vendored
8
.github/workflows/__check-action.yml
vendored
@ -23,11 +23,11 @@ jobs:
|
||||
|
||||
- name: "Assert: only expected services are running"
|
||||
run: |
|
||||
docker-compose -f ./docker/docker-compose.yml ps
|
||||
docker compose -f ./docker/docker-compose.yml ps
|
||||
|
||||
docker-compose -f ./docker/docker-compose.yml ps | grep docker-service-b-1 || (echo "Service service-b is not running" && exit 1)
|
||||
docker-compose -f ./docker/docker-compose.yml ps | grep docker-service-c-1 || (echo "Service service-c is not running" && exit 1)
|
||||
(docker-compose -f ./docker/docker-compose.yml ps | grep docker-service-a-1 && echo "Unexpected service service-a is running" && exit 1) || true
|
||||
docker compose -f ./docker/docker-compose.yml ps | grep docker-service-b-1 || (echo "Service service-b is not running" && exit 1)
|
||||
docker compose -f ./docker/docker-compose.yml ps | grep docker-service-c-1 || (echo "Service service-c is not running" && exit 1)
|
||||
(docker compose -f ./docker/docker-compose.yml ps | grep docker-service-a-1 && echo "Unexpected service service-a is running" && exit 1) || true
|
||||
|
||||
test-action-with-down-flags:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
19
dist/index.js
generated
vendored
19
dist/index.js
generated
vendored
@ -25937,14 +25937,10 @@ const docker_compose_service_1 = __nccwpck_require__(2911);
|
||||
async function run(callback) {
|
||||
try {
|
||||
const loggerService = new logger_service_1.LoggerService();
|
||||
const inputService = new input_service_1.InputService(loggerService);
|
||||
const inputService = new input_service_1.InputService();
|
||||
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
||||
const inputs = inputService.getInputs();
|
||||
loggerService.debug(`inputs: ${JSON.stringify(inputs)}`);
|
||||
if (!inputs.composeFiles.length) {
|
||||
loggerService.warn("no compose files found");
|
||||
return;
|
||||
}
|
||||
await callback(inputs, loggerService, dockerComposeService);
|
||||
}
|
||||
catch (error) {
|
||||
@ -26032,10 +26028,6 @@ var InputNames;
|
||||
InputNames["Cwd"] = "cwd";
|
||||
})(InputNames || (exports.InputNames = InputNames = {}));
|
||||
class InputService {
|
||||
logger;
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
getInputs() {
|
||||
return {
|
||||
composeFiles: this.getComposeFiles(),
|
||||
@ -26048,16 +26040,19 @@ class InputService {
|
||||
}
|
||||
getComposeFiles() {
|
||||
const cwd = this.getCwd();
|
||||
return (0, core_1.getMultilineInput)(InputNames.ComposeFile).filter((composeFile) => {
|
||||
const composeFiles = (0, core_1.getMultilineInput)(InputNames.ComposeFile).filter((composeFile) => {
|
||||
if (!composeFile.length) {
|
||||
return false;
|
||||
}
|
||||
if (!(0, fs_1.existsSync)((0, path_1.join)(cwd, composeFile))) {
|
||||
this.logger.warn(`${composeFile} does not exist in ${cwd}`);
|
||||
return false;
|
||||
throw new Error(`${composeFile} does not exist in ${cwd}`);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!composeFiles.length) {
|
||||
throw new Error("No compose files found");
|
||||
}
|
||||
return composeFiles;
|
||||
}
|
||||
getServices() {
|
||||
return (0, core_1.getMultilineInput)(InputNames.Services, { required: false });
|
||||
|
||||
19
dist/post.js
generated
vendored
19
dist/post.js
generated
vendored
@ -25937,14 +25937,10 @@ const docker_compose_service_1 = __nccwpck_require__(2911);
|
||||
async function run(callback) {
|
||||
try {
|
||||
const loggerService = new logger_service_1.LoggerService();
|
||||
const inputService = new input_service_1.InputService(loggerService);
|
||||
const inputService = new input_service_1.InputService();
|
||||
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
||||
const inputs = inputService.getInputs();
|
||||
loggerService.debug(`inputs: ${JSON.stringify(inputs)}`);
|
||||
if (!inputs.composeFiles.length) {
|
||||
loggerService.warn("no compose files found");
|
||||
return;
|
||||
}
|
||||
await callback(inputs, loggerService, dockerComposeService);
|
||||
}
|
||||
catch (error) {
|
||||
@ -26032,10 +26028,6 @@ var InputNames;
|
||||
InputNames["Cwd"] = "cwd";
|
||||
})(InputNames || (exports.InputNames = InputNames = {}));
|
||||
class InputService {
|
||||
logger;
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
getInputs() {
|
||||
return {
|
||||
composeFiles: this.getComposeFiles(),
|
||||
@ -26048,16 +26040,19 @@ class InputService {
|
||||
}
|
||||
getComposeFiles() {
|
||||
const cwd = this.getCwd();
|
||||
return (0, core_1.getMultilineInput)(InputNames.ComposeFile).filter((composeFile) => {
|
||||
const composeFiles = (0, core_1.getMultilineInput)(InputNames.ComposeFile).filter((composeFile) => {
|
||||
if (!composeFile.length) {
|
||||
return false;
|
||||
}
|
||||
if (!(0, fs_1.existsSync)((0, path_1.join)(cwd, composeFile))) {
|
||||
this.logger.warn(`${composeFile} does not exist in ${cwd}`);
|
||||
return false;
|
||||
throw new Error(`${composeFile} does not exist in ${cwd}`);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!composeFiles.length) {
|
||||
throw new Error("No compose files found");
|
||||
}
|
||||
return composeFiles;
|
||||
}
|
||||
getServices() {
|
||||
return (0, core_1.getMultilineInput)(InputNames.Services, { required: false });
|
||||
|
||||
@ -17,7 +17,6 @@ const runMock = jest.spyOn(runner, "run");
|
||||
|
||||
// Mock the external libraries and services used by the action
|
||||
let debugMock: jest.SpiedFunction<typeof LoggerService.prototype.debug>;
|
||||
let warnMock: jest.SpiedFunction<typeof LoggerService.prototype.warn>;
|
||||
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>;
|
||||
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;
|
||||
describe("run", () => {
|
||||
@ -25,58 +24,11 @@ describe("run", () => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
debugMock = jest.spyOn(LoggerService.prototype, "debug").mockImplementation();
|
||||
warnMock = jest.spyOn(LoggerService.prototype, "warn").mockImplementation();
|
||||
setFailedMock = jest.spyOn(core, "setFailed").mockImplementation();
|
||||
getInputsMock = jest.spyOn(InputService.prototype, "getInputs");
|
||||
});
|
||||
|
||||
it("should return and warns when composeFile is empty", async () => {
|
||||
getInputsMock.mockImplementation(() => ({
|
||||
composeFiles: [],
|
||||
services: [],
|
||||
composeFlags: [],
|
||||
upFlags: [],
|
||||
downFlags: [],
|
||||
cwd: "/current/working/dir",
|
||||
}));
|
||||
|
||||
const callbackMock = jest.fn();
|
||||
|
||||
await runner.run(callbackMock);
|
||||
expect(runMock).toHaveReturned();
|
||||
|
||||
// Verify that all of the functions were called correctly
|
||||
expect(debugMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'inputs: {"composeFiles":[],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
||||
);
|
||||
expect(warnMock).toHaveBeenNthCalledWith(1, "no compose files found");
|
||||
expect(callbackMock).not.toHaveBeenCalled();
|
||||
expect(setFailedMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets a failed status", async () => {
|
||||
getInputsMock.mockImplementation(() => ({
|
||||
composeFiles: ["docker-compose.yml"],
|
||||
services: [],
|
||||
composeFlags: [],
|
||||
upFlags: [],
|
||||
downFlags: [],
|
||||
cwd: "/current/working/dir",
|
||||
}));
|
||||
|
||||
const callbackMock = jest.fn();
|
||||
callbackMock.mockRejectedValueOnce(new Error("unkown error"));
|
||||
|
||||
await runner.run(callbackMock);
|
||||
expect(runMock).toHaveReturned();
|
||||
|
||||
// Verify that all of the functions were called correctly
|
||||
expect(callbackMock).toHaveBeenCalled();
|
||||
expect(setFailedMock).toHaveBeenNthCalledWith(1, "Error: unkown error");
|
||||
});
|
||||
|
||||
it("should call callback when some compose files are provided", async () => {
|
||||
it("should call given callback when inputs are valid", async () => {
|
||||
getInputsMock.mockImplementation(() => ({
|
||||
composeFiles: ["docker-compose.yml"],
|
||||
services: [],
|
||||
@ -113,4 +65,25 @@ describe("run", () => {
|
||||
|
||||
expect(setFailedMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sets a failed status", async () => {
|
||||
getInputsMock.mockImplementation(() => ({
|
||||
composeFiles: ["docker-compose.yml"],
|
||||
services: [],
|
||||
composeFlags: [],
|
||||
upFlags: [],
|
||||
downFlags: [],
|
||||
cwd: "/current/working/dir",
|
||||
}));
|
||||
|
||||
const callbackMock = jest.fn();
|
||||
callbackMock.mockRejectedValueOnce(new Error("unkown error"));
|
||||
|
||||
await runner.run(callbackMock);
|
||||
expect(runMock).toHaveReturned();
|
||||
|
||||
// Verify that all of the functions were called correctly
|
||||
expect(callbackMock).toHaveBeenCalled();
|
||||
expect(setFailedMock).toHaveBeenNthCalledWith(1, "Error: unkown error");
|
||||
});
|
||||
});
|
||||
|
||||
@ -16,17 +16,12 @@ export type RunCallback = (
|
||||
export async function run(callback: RunCallback): Promise<void> {
|
||||
try {
|
||||
const loggerService = new LoggerService();
|
||||
const inputService = new InputService(loggerService);
|
||||
const inputService = new InputService();
|
||||
const dockerComposeService = new DockerComposeService();
|
||||
|
||||
const inputs = inputService.getInputs();
|
||||
loggerService.debug(`inputs: ${JSON.stringify(inputs)}`);
|
||||
|
||||
if (!inputs.composeFiles.length) {
|
||||
loggerService.warn("no compose files found");
|
||||
return;
|
||||
}
|
||||
|
||||
await callback(inputs, loggerService, dockerComposeService);
|
||||
} catch (error) {
|
||||
setFailed(`${error instanceof Error ? error : JSON.stringify(error)}`);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { InputService, InputNames } from "./input.service";
|
||||
import { LoggerService } from "./logger.service";
|
||||
import * as core from "@actions/core";
|
||||
import * as fs from "fs";
|
||||
|
||||
@ -13,14 +12,12 @@ jest.mock("@actions/core");
|
||||
|
||||
describe("InputService", () => {
|
||||
let service: InputService;
|
||||
let logger: LoggerService;
|
||||
let getInputMock: jest.SpiedFunction<typeof core.getInput>;
|
||||
let getMultilineInputMock: jest.SpiedFunction<typeof core.getMultilineInput>;
|
||||
let existsSyncMock: jest.SpiedFunction<typeof fs.existsSync>;
|
||||
|
||||
beforeEach(() => {
|
||||
logger = new LoggerService();
|
||||
service = new InputService(logger);
|
||||
service = new InputService();
|
||||
|
||||
existsSyncMock = jest.spyOn(fs, "existsSync").mockImplementation();
|
||||
getInputMock = jest.spyOn(core, "getInput").mockImplementation();
|
||||
@ -52,7 +49,7 @@ describe("InputService", () => {
|
||||
expect(inputs.composeFiles).toEqual(["file1", "file2"]);
|
||||
});
|
||||
|
||||
it("should return only existing composeFiles input", () => {
|
||||
it("should throws an error when a compose file does not exist", () => {
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
@ -62,13 +59,28 @@ describe("InputService", () => {
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.Cwd:
|
||||
return "/current/working/directory";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
existsSyncMock.mockImplementation((file) => file === "/current/working/directory/file1");
|
||||
|
||||
expect(() => service.getInputs()).toThrow(
|
||||
"file2 does not exist in /current/working/directory"
|
||||
);
|
||||
});
|
||||
|
||||
it("should throws an error when no composeFiles input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
|
||||
getInputMock.mockReturnValue("");
|
||||
|
||||
existsSyncMock.mockImplementation((file) => file === "file1");
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.composeFiles).toEqual(["file1"]);
|
||||
expect(() => service.getInputs()).toThrow("No compose files found");
|
||||
});
|
||||
});
|
||||
|
||||
@ -78,12 +90,15 @@ describe("InputService", () => {
|
||||
switch (inputName) {
|
||||
case InputNames.Services:
|
||||
return ["service1", "service2"];
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockReturnValue("");
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
@ -93,7 +108,14 @@ describe("InputService", () => {
|
||||
|
||||
describe("compose-flags", () => {
|
||||
it("should return given compose-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
@ -104,15 +126,27 @@ describe("InputService", () => {
|
||||
}
|
||||
});
|
||||
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.composeFlags).toEqual(["compose-flag1", "compose-flag2"]);
|
||||
});
|
||||
|
||||
it("should return empty array when no compose-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockReturnValue("");
|
||||
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.composeFlags).toEqual([]);
|
||||
@ -121,7 +155,14 @@ describe("InputService", () => {
|
||||
|
||||
describe("up-flags", () => {
|
||||
it("should return given up-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
@ -132,15 +173,27 @@ describe("InputService", () => {
|
||||
}
|
||||
});
|
||||
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.upFlags).toEqual(["up-flag1", "up-flag2"]);
|
||||
});
|
||||
|
||||
it("should return empty array when no up-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockReturnValue("");
|
||||
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.upFlags).toEqual([]);
|
||||
@ -149,7 +202,14 @@ describe("InputService", () => {
|
||||
|
||||
describe("down-flags", () => {
|
||||
it("should return given down-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
@ -160,15 +220,26 @@ describe("InputService", () => {
|
||||
}
|
||||
});
|
||||
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.downFlags).toEqual(["down-flag1", "down-flag2"]);
|
||||
});
|
||||
|
||||
it("should return empty array when no down-flags input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
getInputMock.mockReturnValue("");
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
expect(inputs.downFlags).toEqual([]);
|
||||
@ -177,7 +248,14 @@ describe("InputService", () => {
|
||||
|
||||
describe("cwd", () => {
|
||||
it("should return given cwd input", () => {
|
||||
getMultilineInputMock.mockReturnValue([]);
|
||||
getMultilineInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.ComposeFile:
|
||||
return ["file1"];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
getInputMock.mockImplementation((inputName) => {
|
||||
switch (inputName) {
|
||||
case InputNames.Cwd:
|
||||
@ -186,6 +264,7 @@ describe("InputService", () => {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
existsSyncMock.mockReturnValue(true);
|
||||
|
||||
const inputs = service.getInputs();
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { getInput, getMultilineInput } from "@actions/core";
|
||||
import { LoggerService } from "./logger.service";
|
||||
import { existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
@ -22,8 +21,6 @@ export enum InputNames {
|
||||
}
|
||||
|
||||
export class InputService {
|
||||
constructor(private readonly logger: LoggerService) {}
|
||||
|
||||
getInputs(): Inputs {
|
||||
return {
|
||||
composeFiles: this.getComposeFiles(),
|
||||
@ -37,18 +34,23 @@ export class InputService {
|
||||
|
||||
private getComposeFiles(): string[] {
|
||||
const cwd = this.getCwd();
|
||||
return getMultilineInput(InputNames.ComposeFile).filter((composeFile) => {
|
||||
const composeFiles = getMultilineInput(InputNames.ComposeFile).filter((composeFile) => {
|
||||
if (!composeFile.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!existsSync(join(cwd, composeFile))) {
|
||||
this.logger.warn(`${composeFile} does not exist in ${cwd}`);
|
||||
return false;
|
||||
throw new Error(`${composeFile} does not exist in ${cwd}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!composeFiles.length) {
|
||||
throw new Error("No compose files found");
|
||||
}
|
||||
|
||||
return composeFiles;
|
||||
}
|
||||
|
||||
private getServices(): string[] {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user