mirror of
https://github.com/hoverkraft-tech/compose-action.git
synced 2026-01-11 23:23:06 +08:00
feat: add logs debug on post
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
This commit is contained in:
parent
a48c80beab
commit
bc90ff6758
20
README.md
20
README.md
@ -11,9 +11,6 @@
|
|||||||
|
|
||||||
<!-- end title -->
|
<!-- end title -->
|
||||||
<!-- start badges -->
|
<!-- start badges -->
|
||||||
|
|
||||||
<a href="https%3A%2F%2Fgithub.com%2Fhoverkraft-tech%2Fcompose-action%2Freleases%2Flatest"><img src="https://img.shields.io/github/v/release/hoverkraft-tech/compose-action?display_name=tag&sort=semver&logo=github&style=flat-square" alt="Release%20by%20tag" /></a><a href="https%3A%2F%2Fgithub.com%2Fhoverkraft-tech%2Fcompose-action%2Freleases%2Flatest"><img src="https://img.shields.io/github/release-date/hoverkraft-tech/compose-action?display_name=tag&sort=semver&logo=github&style=flat-square" alt="Release%20by%20date" /></a><img src="https://img.shields.io/github/last-commit/hoverkraft-tech/compose-action?logo=github&style=flat-square" alt="Commit" /><a href="https%3A%2F%2Fgithub.com%2Fhoverkraft-tech%2Fcompose-action%2Fissues"><img src="https://img.shields.io/github/issues/hoverkraft-tech/compose-action?logo=github&style=flat-square" alt="Open%20Issues" /></a><img src="https://img.shields.io/github/downloads/hoverkraft-tech/compose-action/total?logo=github&style=flat-square" alt="Downloads" />
|
|
||||||
|
|
||||||
<!-- end badges -->
|
<!-- end badges -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -22,8 +19,25 @@
|
|||||||
This action runs your docker-compose file and clean up before action finished
|
This action runs your docker-compose file and clean up before action finished
|
||||||
|
|
||||||
<!-- end description -->
|
<!-- end description -->
|
||||||
|
|
||||||
<!-- start contents -->
|
<!-- start contents -->
|
||||||
<!-- end contents -->
|
<!-- end contents -->
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Action
|
||||||
|
|
||||||
|
The action will run `docker-compose up` to start the services defined in the given compose file(s).
|
||||||
|
The compose file(s) can be specified using the `compose-file` input.
|
||||||
|
Some extra options can be passed to the `docker-compose up` command using the `up-flags` input.
|
||||||
|
|
||||||
|
### Post hook
|
||||||
|
|
||||||
|
On post hook, the action will run `docker-compose down` to clean up the services.
|
||||||
|
In debug mode, the logs of the running services are printed before the cleanup.
|
||||||
|
|
||||||
|
Some extra options can be passed to the `docker-compose down` command using the `down-flags` input.
|
||||||
|
|
||||||
<!-- start usage -->
|
<!-- start usage -->
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
54
dist/index.js
generated
vendored
54
dist/index.js
generated
vendored
@ -25919,50 +25919,36 @@ exports["default"] = _default;
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 399:
|
/***/ 3878:
|
||||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.run = exports.RunAction = void 0;
|
exports.run = void 0;
|
||||||
const core_1 = __nccwpck_require__(2186);
|
const core_1 = __nccwpck_require__(2186);
|
||||||
const docker_compose_service_1 = __nccwpck_require__(2911);
|
|
||||||
const input_service_1 = __nccwpck_require__(6492);
|
const input_service_1 = __nccwpck_require__(6492);
|
||||||
const logger_service_1 = __nccwpck_require__(6716);
|
const logger_service_1 = __nccwpck_require__(6716);
|
||||||
var RunAction;
|
const docker_compose_service_1 = __nccwpck_require__(2911);
|
||||||
(function (RunAction) {
|
|
||||||
RunAction["UP"] = "up";
|
|
||||||
RunAction["DOWN"] = "down";
|
|
||||||
})(RunAction || (exports.RunAction = RunAction = {}));
|
|
||||||
/**
|
/**
|
||||||
* The main function for the action.
|
* The run function for the action.
|
||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
*/
|
*/
|
||||||
async function run(run) {
|
async function run(callback) {
|
||||||
try {
|
try {
|
||||||
const loggerService = new logger_service_1.LoggerService();
|
const loggerService = new logger_service_1.LoggerService();
|
||||||
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
|
||||||
const inputService = new input_service_1.InputService(loggerService);
|
const inputService = new input_service_1.InputService(loggerService);
|
||||||
|
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
||||||
const inputs = inputService.getInputs();
|
const inputs = inputService.getInputs();
|
||||||
(0, core_1.debug)(`inputs: ${JSON.stringify(inputs)}`);
|
loggerService.debug(`inputs: ${JSON.stringify(inputs)}`);
|
||||||
if (!inputs.composeFiles.length) {
|
if (!inputs.composeFiles.length) {
|
||||||
loggerService.warn("no compose files found");
|
loggerService.warn("no compose files found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (run) {
|
await callback(inputs, loggerService, dockerComposeService);
|
||||||
case RunAction.UP:
|
|
||||||
await dockerComposeService.up(inputs);
|
|
||||||
loggerService.info("compose started");
|
|
||||||
break;
|
|
||||||
case RunAction.DOWN:
|
|
||||||
await dockerComposeService.down(inputs);
|
|
||||||
loggerService.info("compose removed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
(0, core_1.setFailed)(`compose ${run} failed. ${error instanceof Error ? error : JSON.stringify(error)}`);
|
(0, core_1.setFailed)(`${error instanceof Error ? error : JSON.stringify(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.run = run;
|
exports.run = run;
|
||||||
@ -25997,6 +25983,17 @@ class DockerComposeService {
|
|||||||
};
|
};
|
||||||
await docker_compose_1.v2.down(options);
|
await docker_compose_1.v2.down(options);
|
||||||
}
|
}
|
||||||
|
async logs(inputs) {
|
||||||
|
const options = {
|
||||||
|
...this.getCommonOptions(inputs),
|
||||||
|
follow: false,
|
||||||
|
};
|
||||||
|
const { err, out } = await docker_compose_1.v2.logs(inputs.services, options);
|
||||||
|
return {
|
||||||
|
error: err,
|
||||||
|
output: out,
|
||||||
|
};
|
||||||
|
}
|
||||||
getCommonOptions(inputs) {
|
getCommonOptions(inputs) {
|
||||||
return {
|
return {
|
||||||
config: inputs.composeFiles,
|
config: inputs.composeFiles,
|
||||||
@ -26100,6 +26097,9 @@ class LoggerService {
|
|||||||
info(message) {
|
info(message) {
|
||||||
(0, core_1.info)(message);
|
(0, core_1.info)(message);
|
||||||
}
|
}
|
||||||
|
debug(message) {
|
||||||
|
(0, core_1.debug)(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.LoggerService = LoggerService;
|
exports.LoggerService = LoggerService;
|
||||||
|
|
||||||
@ -36438,9 +36438,13 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|||||||
/**
|
/**
|
||||||
* The entrypoint for the action.
|
* The entrypoint for the action.
|
||||||
*/
|
*/
|
||||||
const main_1 = __nccwpck_require__(399);
|
const runner_1 = __nccwpck_require__(3878);
|
||||||
|
const callback = async (inputs, loggerService, dockerComposeService) => {
|
||||||
|
await dockerComposeService.up(inputs);
|
||||||
|
loggerService.info("compose started");
|
||||||
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
(0, main_1.run)(main_1.RunAction.UP);
|
(0, runner_1.run)(callback);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
59
dist/post.js
generated
vendored
59
dist/post.js
generated
vendored
@ -25919,50 +25919,36 @@ exports["default"] = _default;
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 399:
|
/***/ 3878:
|
||||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.run = exports.RunAction = void 0;
|
exports.run = void 0;
|
||||||
const core_1 = __nccwpck_require__(2186);
|
const core_1 = __nccwpck_require__(2186);
|
||||||
const docker_compose_service_1 = __nccwpck_require__(2911);
|
|
||||||
const input_service_1 = __nccwpck_require__(6492);
|
const input_service_1 = __nccwpck_require__(6492);
|
||||||
const logger_service_1 = __nccwpck_require__(6716);
|
const logger_service_1 = __nccwpck_require__(6716);
|
||||||
var RunAction;
|
const docker_compose_service_1 = __nccwpck_require__(2911);
|
||||||
(function (RunAction) {
|
|
||||||
RunAction["UP"] = "up";
|
|
||||||
RunAction["DOWN"] = "down";
|
|
||||||
})(RunAction || (exports.RunAction = RunAction = {}));
|
|
||||||
/**
|
/**
|
||||||
* The main function for the action.
|
* The run function for the action.
|
||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
*/
|
*/
|
||||||
async function run(run) {
|
async function run(callback) {
|
||||||
try {
|
try {
|
||||||
const loggerService = new logger_service_1.LoggerService();
|
const loggerService = new logger_service_1.LoggerService();
|
||||||
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
|
||||||
const inputService = new input_service_1.InputService(loggerService);
|
const inputService = new input_service_1.InputService(loggerService);
|
||||||
|
const dockerComposeService = new docker_compose_service_1.DockerComposeService();
|
||||||
const inputs = inputService.getInputs();
|
const inputs = inputService.getInputs();
|
||||||
(0, core_1.debug)(`inputs: ${JSON.stringify(inputs)}`);
|
loggerService.debug(`inputs: ${JSON.stringify(inputs)}`);
|
||||||
if (!inputs.composeFiles.length) {
|
if (!inputs.composeFiles.length) {
|
||||||
loggerService.warn("no compose files found");
|
loggerService.warn("no compose files found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (run) {
|
await callback(inputs, loggerService, dockerComposeService);
|
||||||
case RunAction.UP:
|
|
||||||
await dockerComposeService.up(inputs);
|
|
||||||
loggerService.info("compose started");
|
|
||||||
break;
|
|
||||||
case RunAction.DOWN:
|
|
||||||
await dockerComposeService.down(inputs);
|
|
||||||
loggerService.info("compose removed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
(0, core_1.setFailed)(`compose ${run} failed. ${error instanceof Error ? error : JSON.stringify(error)}`);
|
(0, core_1.setFailed)(`${error instanceof Error ? error : JSON.stringify(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.run = run;
|
exports.run = run;
|
||||||
@ -25997,6 +25983,17 @@ class DockerComposeService {
|
|||||||
};
|
};
|
||||||
await docker_compose_1.v2.down(options);
|
await docker_compose_1.v2.down(options);
|
||||||
}
|
}
|
||||||
|
async logs(inputs) {
|
||||||
|
const options = {
|
||||||
|
...this.getCommonOptions(inputs),
|
||||||
|
follow: false,
|
||||||
|
};
|
||||||
|
const { err, out } = await docker_compose_1.v2.logs(inputs.services, options);
|
||||||
|
return {
|
||||||
|
error: err,
|
||||||
|
output: out,
|
||||||
|
};
|
||||||
|
}
|
||||||
getCommonOptions(inputs) {
|
getCommonOptions(inputs) {
|
||||||
return {
|
return {
|
||||||
config: inputs.composeFiles,
|
config: inputs.composeFiles,
|
||||||
@ -26100,6 +26097,9 @@ class LoggerService {
|
|||||||
info(message) {
|
info(message) {
|
||||||
(0, core_1.info)(message);
|
(0, core_1.info)(message);
|
||||||
}
|
}
|
||||||
|
debug(message) {
|
||||||
|
(0, core_1.debug)(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.LoggerService = LoggerService;
|
exports.LoggerService = LoggerService;
|
||||||
|
|
||||||
@ -36438,9 +36438,18 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|||||||
/**
|
/**
|
||||||
* The entrypoint for the post action.
|
* The entrypoint for the post action.
|
||||||
*/
|
*/
|
||||||
const main_1 = __nccwpck_require__(399);
|
const runner_1 = __nccwpck_require__(3878);
|
||||||
|
const callback = async (inputs, loggerService, dockerComposeService) => {
|
||||||
|
const { error, output } = await dockerComposeService.logs(inputs);
|
||||||
|
if (error) {
|
||||||
|
loggerService.debug("compose error:\n" + error);
|
||||||
|
}
|
||||||
|
loggerService.debug("compose logs:\n" + output);
|
||||||
|
await dockerComposeService.down(inputs);
|
||||||
|
loggerService.info("compose removed");
|
||||||
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
(0, main_1.run)(main_1.RunAction.DOWN);
|
(0, runner_1.run)(callback);
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,56 @@
|
|||||||
/**
|
import * as core from "@actions/core";
|
||||||
* Unit tests for the action's entrypoint, src/index.ts
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
*/
|
import { InputService } from "./services/input.service";
|
||||||
|
import { LoggerService } from "./services/logger.service";
|
||||||
|
|
||||||
import * as main from "./main";
|
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>;
|
||||||
|
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;
|
||||||
// Mock the action's entrypoint
|
let debugMock: jest.SpiedFunction<typeof LoggerService.prototype.debug>;
|
||||||
const runMock = jest.spyOn(main, "run").mockImplementation();
|
let infoMock: jest.SpiedFunction<typeof LoggerService.prototype.info>;
|
||||||
|
let upMock: jest.SpiedFunction<typeof DockerComposeService.prototype.up>;
|
||||||
|
|
||||||
describe("index", () => {
|
describe("index", () => {
|
||||||
it("calls run when imported", async () => {
|
beforeEach(() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
jest.clearAllMocks();
|
||||||
require("../src/index");
|
|
||||||
|
|
||||||
expect(runMock).toHaveBeenCalled();
|
setFailedMock = jest.spyOn(core, "setFailed").mockImplementation();
|
||||||
|
infoMock = jest.spyOn(LoggerService.prototype, "info").mockImplementation();
|
||||||
|
debugMock = jest.spyOn(LoggerService.prototype, "debug").mockImplementation();
|
||||||
|
getInputsMock = jest.spyOn(InputService.prototype, "getInputs");
|
||||||
|
upMock = jest.spyOn(DockerComposeService.prototype, "up");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls run when imported", async () => {
|
||||||
|
getInputsMock.mockImplementation(() => ({
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: [],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
}));
|
||||||
|
|
||||||
|
upMock.mockResolvedValueOnce();
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
await require("../src/index");
|
||||||
|
|
||||||
|
// Verify that all of the functions were called correctly
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'inputs: {"composeFiles":["docker-compose.yml"],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(upMock).toHaveBeenCalledWith({
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: [],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(setFailedMock).not.toHaveBeenCalled();
|
||||||
|
expect(infoMock).toHaveBeenCalledWith("compose started");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
16
src/index.ts
16
src/index.ts
@ -1,7 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* The entrypoint for the action.
|
* The entrypoint for the action.
|
||||||
*/
|
*/
|
||||||
import { run, RunAction } from "./main";
|
import { RunCallback, run } from "./runner";
|
||||||
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
|
import { Inputs } from "./services/input.service";
|
||||||
|
import { LoggerService } from "./services/logger.service";
|
||||||
|
|
||||||
|
const callback: RunCallback = async (
|
||||||
|
inputs: Inputs,
|
||||||
|
loggerService: LoggerService,
|
||||||
|
dockerComposeService: DockerComposeService
|
||||||
|
) => {
|
||||||
|
await dockerComposeService.up(inputs);
|
||||||
|
loggerService.info("compose started");
|
||||||
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
run(RunAction.UP);
|
run(callback);
|
||||||
|
|||||||
42
src/main.ts
42
src/main.ts
@ -1,42 +0,0 @@
|
|||||||
import { debug, setFailed } from "@actions/core";
|
|
||||||
import { DockerComposeService } from "./services/docker-compose.service";
|
|
||||||
import { InputService } from "./services/input.service";
|
|
||||||
import { LoggerService } from "./services/logger.service";
|
|
||||||
|
|
||||||
export enum RunAction {
|
|
||||||
UP = "up",
|
|
||||||
DOWN = "down",
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main function for the action.
|
|
||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
|
||||||
*/
|
|
||||||
export async function run(run: RunAction): Promise<void> {
|
|
||||||
try {
|
|
||||||
const loggerService = new LoggerService();
|
|
||||||
const dockerComposeService = new DockerComposeService();
|
|
||||||
const inputService = new InputService(loggerService);
|
|
||||||
|
|
||||||
const inputs = inputService.getInputs();
|
|
||||||
debug(`inputs: ${JSON.stringify(inputs)}`);
|
|
||||||
|
|
||||||
if (!inputs.composeFiles.length) {
|
|
||||||
loggerService.warn("no compose files found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (run) {
|
|
||||||
case RunAction.UP:
|
|
||||||
await dockerComposeService.up(inputs);
|
|
||||||
loggerService.info("compose started");
|
|
||||||
break;
|
|
||||||
case RunAction.DOWN:
|
|
||||||
await dockerComposeService.down(inputs);
|
|
||||||
loggerService.info("compose removed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
setFailed(`compose ${run} failed. ${error instanceof Error ? error : JSON.stringify(error)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +1,71 @@
|
|||||||
/**
|
import * as core from "@actions/core";
|
||||||
* Unit tests for the action's entrypoint, src/index.ts
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
*/
|
import { InputService } from "./services/input.service";
|
||||||
|
import { LoggerService } from "./services/logger.service";
|
||||||
|
|
||||||
import * as main from "./main";
|
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>;
|
||||||
|
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;
|
||||||
// Mock the action's entrypoint
|
let debugMock: jest.SpiedFunction<typeof LoggerService.prototype.debug>;
|
||||||
const runMock = jest.spyOn(main, "run").mockImplementation();
|
let infoMock: jest.SpiedFunction<typeof LoggerService.prototype.info>;
|
||||||
|
let downMock: jest.SpiedFunction<typeof DockerComposeService.prototype.down>;
|
||||||
|
let logsMock: jest.SpiedFunction<typeof DockerComposeService.prototype.logs>;
|
||||||
|
|
||||||
describe("post", () => {
|
describe("post", () => {
|
||||||
it("calls run when imported", async () => {
|
beforeEach(() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
jest.clearAllMocks();
|
||||||
require("../src/post");
|
|
||||||
|
|
||||||
expect(runMock).toHaveBeenCalled();
|
setFailedMock = jest.spyOn(core, "setFailed").mockImplementation();
|
||||||
|
infoMock = jest.spyOn(LoggerService.prototype, "info").mockImplementation();
|
||||||
|
debugMock = jest.spyOn(LoggerService.prototype, "debug").mockImplementation();
|
||||||
|
getInputsMock = jest.spyOn(InputService.prototype, "getInputs");
|
||||||
|
downMock = jest.spyOn(DockerComposeService.prototype, "down");
|
||||||
|
logsMock = jest.spyOn(DockerComposeService.prototype, "logs");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls run when imported", async () => {
|
||||||
|
getInputsMock.mockImplementation(() => ({
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: [],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
}));
|
||||||
|
|
||||||
|
logsMock.mockResolvedValueOnce({ error: "", output: "log" });
|
||||||
|
downMock.mockResolvedValueOnce();
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
await require("../src/post");
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
|
// Verify that all of the functions were called correctly
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'inputs: {"composeFiles":["docker-compose.yml"],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(logsMock).toHaveBeenCalledWith({
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: [],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(debugMock).toHaveBeenNthCalledWith(2, "compose logs:\nlog");
|
||||||
|
|
||||||
|
expect(downMock).toHaveBeenCalledWith({
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: [],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(setFailedMock).not.toHaveBeenCalled();
|
||||||
|
expect(infoMock).toHaveBeenCalledWith("compose removed");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
25
src/post.ts
25
src/post.ts
@ -1,7 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* The entrypoint for the post action.
|
* The entrypoint for the post action.
|
||||||
*/
|
*/
|
||||||
import { run, RunAction } from "./main";
|
import { RunCallback, run } from "./runner";
|
||||||
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
|
import { Inputs } from "./services/input.service";
|
||||||
|
import { LoggerService } from "./services/logger.service";
|
||||||
|
|
||||||
|
const callback: RunCallback = async (
|
||||||
|
inputs: Inputs,
|
||||||
|
loggerService: LoggerService,
|
||||||
|
dockerComposeService: DockerComposeService
|
||||||
|
) => {
|
||||||
|
const { error, output } = await dockerComposeService.logs(inputs);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
loggerService.debug("compose error:\n" + error);
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerService.debug("compose logs:\n" + output);
|
||||||
|
|
||||||
|
await dockerComposeService.down(inputs);
|
||||||
|
|
||||||
|
loggerService.info("compose removed");
|
||||||
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
run(RunAction.DOWN);
|
run(callback);
|
||||||
|
|||||||
@ -10,31 +10,24 @@ import * as core from "@actions/core";
|
|||||||
import { DockerComposeService } from "./services/docker-compose.service";
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
import { InputService } from "./services/input.service";
|
import { InputService } from "./services/input.service";
|
||||||
import { LoggerService } from "./services/logger.service";
|
import { LoggerService } from "./services/logger.service";
|
||||||
import * as main from "./main";
|
import * as runner from "./runner";
|
||||||
|
|
||||||
// Mock the action's main function
|
// Mock the action's main function
|
||||||
const runMock = jest.spyOn(main, "run");
|
const runMock = jest.spyOn(runner, "run");
|
||||||
|
|
||||||
// Mock the external libraries and services used by the action
|
// Mock the external libraries and services used by the action
|
||||||
let debugMock: jest.SpiedFunction<typeof core.debug>;
|
let debugMock: jest.SpiedFunction<typeof LoggerService.prototype.debug>;
|
||||||
let warnMock: jest.SpiedFunction<typeof LoggerService.prototype.warn>;
|
let warnMock: jest.SpiedFunction<typeof LoggerService.prototype.warn>;
|
||||||
let infoMock: jest.SpiedFunction<typeof LoggerService.prototype.info>;
|
|
||||||
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>;
|
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>;
|
||||||
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;
|
let getInputsMock: jest.SpiedFunction<typeof InputService.prototype.getInputs>;
|
||||||
let upMock: jest.SpiedFunction<typeof DockerComposeService.prototype.up>;
|
|
||||||
let downMock: jest.SpiedFunction<typeof DockerComposeService.prototype.down>;
|
|
||||||
|
|
||||||
describe("run", () => {
|
describe("run", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
||||||
debugMock = jest.spyOn(core, "debug").mockImplementation();
|
debugMock = jest.spyOn(LoggerService.prototype, "debug").mockImplementation();
|
||||||
warnMock = jest.spyOn(LoggerService.prototype, "warn").mockImplementation();
|
warnMock = jest.spyOn(LoggerService.prototype, "warn").mockImplementation();
|
||||||
infoMock = jest.spyOn(LoggerService.prototype, "info").mockImplementation();
|
|
||||||
setFailedMock = jest.spyOn(core, "setFailed").mockImplementation();
|
setFailedMock = jest.spyOn(core, "setFailed").mockImplementation();
|
||||||
getInputsMock = jest.spyOn(InputService.prototype, "getInputs");
|
getInputsMock = jest.spyOn(InputService.prototype, "getInputs");
|
||||||
upMock = jest.spyOn(DockerComposeService.prototype, "up");
|
|
||||||
downMock = jest.spyOn(DockerComposeService.prototype, "down");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return and warns when composeFile is empty", async () => {
|
it("should return and warns when composeFile is empty", async () => {
|
||||||
@ -47,7 +40,9 @@ describe("run", () => {
|
|||||||
cwd: "/current/working/dir",
|
cwd: "/current/working/dir",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await main.run(main.RunAction.UP);
|
const callbackMock = jest.fn();
|
||||||
|
|
||||||
|
await runner.run(callbackMock);
|
||||||
expect(runMock).toHaveReturned();
|
expect(runMock).toHaveReturned();
|
||||||
|
|
||||||
// Verify that all of the functions were called correctly
|
// Verify that all of the functions were called correctly
|
||||||
@ -56,44 +51,10 @@ describe("run", () => {
|
|||||||
'inputs: {"composeFiles":[],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
'inputs: {"composeFiles":[],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
||||||
);
|
);
|
||||||
expect(warnMock).toHaveBeenNthCalledWith(1, "no compose files found");
|
expect(warnMock).toHaveBeenNthCalledWith(1, "no compose files found");
|
||||||
expect(upMock).not.toHaveBeenCalled();
|
expect(callbackMock).not.toHaveBeenCalled();
|
||||||
expect(setFailedMock).not.toHaveBeenCalled();
|
expect(setFailedMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call up when some compose files are provided", async () => {
|
|
||||||
getInputsMock.mockImplementation(() => ({
|
|
||||||
composeFiles: ["docker-compose.yml"],
|
|
||||||
services: [],
|
|
||||||
composeFlags: [],
|
|
||||||
upFlags: [],
|
|
||||||
downFlags: [],
|
|
||||||
cwd: "/current/working/dir",
|
|
||||||
}));
|
|
||||||
|
|
||||||
upMock.mockResolvedValueOnce();
|
|
||||||
|
|
||||||
await main.run(main.RunAction.UP);
|
|
||||||
expect(runMock).toHaveReturned();
|
|
||||||
|
|
||||||
// Verify that all of the functions were called correctly
|
|
||||||
expect(debugMock).toHaveBeenNthCalledWith(
|
|
||||||
1,
|
|
||||||
'inputs: {"composeFiles":["docker-compose.yml"],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(upMock).toHaveBeenCalledWith({
|
|
||||||
composeFiles: ["docker-compose.yml"],
|
|
||||||
services: [],
|
|
||||||
composeFlags: [],
|
|
||||||
upFlags: [],
|
|
||||||
downFlags: [],
|
|
||||||
cwd: "/current/working/dir",
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(setFailedMock).not.toHaveBeenCalled();
|
|
||||||
expect(infoMock).toHaveBeenCalledWith("compose started");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets a failed status", async () => {
|
it("sets a failed status", async () => {
|
||||||
getInputsMock.mockImplementation(() => ({
|
getInputsMock.mockImplementation(() => ({
|
||||||
composeFiles: ["docker-compose.yml"],
|
composeFiles: ["docker-compose.yml"],
|
||||||
@ -104,16 +65,18 @@ describe("run", () => {
|
|||||||
cwd: "/current/working/dir",
|
cwd: "/current/working/dir",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
upMock.mockRejectedValueOnce(new Error("unkown error"));
|
const callbackMock = jest.fn();
|
||||||
|
callbackMock.mockRejectedValueOnce(new Error("unkown error"));
|
||||||
|
|
||||||
await main.run(main.RunAction.UP);
|
await runner.run(callbackMock);
|
||||||
expect(runMock).toHaveReturned();
|
expect(runMock).toHaveReturned();
|
||||||
|
|
||||||
// Verify that all of the functions were called correctly
|
// Verify that all of the functions were called correctly
|
||||||
expect(setFailedMock).toHaveBeenNthCalledWith(1, "compose up failed. Error: unkown error");
|
expect(callbackMock).toHaveBeenCalled();
|
||||||
|
expect(setFailedMock).toHaveBeenNthCalledWith(1, "Error: unkown error");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call down when some compose files are provided", async () => {
|
it("should call callback when some compose files are provided", async () => {
|
||||||
getInputsMock.mockImplementation(() => ({
|
getInputsMock.mockImplementation(() => ({
|
||||||
composeFiles: ["docker-compose.yml"],
|
composeFiles: ["docker-compose.yml"],
|
||||||
services: [],
|
services: [],
|
||||||
@ -123,9 +86,10 @@ describe("run", () => {
|
|||||||
cwd: "/current/working/dir",
|
cwd: "/current/working/dir",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
downMock.mockResolvedValueOnce();
|
const callbackMock = jest.fn();
|
||||||
|
callbackMock.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
await main.run(main.RunAction.DOWN);
|
await runner.run(callbackMock);
|
||||||
expect(runMock).toHaveReturned();
|
expect(runMock).toHaveReturned();
|
||||||
|
|
||||||
// Verify that all of the functions were called correctly
|
// Verify that all of the functions were called correctly
|
||||||
@ -134,16 +98,19 @@ describe("run", () => {
|
|||||||
'inputs: {"composeFiles":["docker-compose.yml"],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
'inputs: {"composeFiles":["docker-compose.yml"],"services":[],"composeFlags":[],"upFlags":[],"downFlags":[],"cwd":"/current/working/dir"}'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(downMock).toHaveBeenCalledWith({
|
expect(callbackMock).toHaveBeenCalledWith(
|
||||||
composeFiles: ["docker-compose.yml"],
|
{
|
||||||
services: [],
|
composeFiles: ["docker-compose.yml"],
|
||||||
composeFlags: [],
|
services: [],
|
||||||
upFlags: [],
|
composeFlags: [],
|
||||||
downFlags: [],
|
upFlags: [],
|
||||||
cwd: "/current/working/dir",
|
downFlags: [],
|
||||||
});
|
cwd: "/current/working/dir",
|
||||||
|
},
|
||||||
|
expect.any(LoggerService),
|
||||||
|
expect.any(DockerComposeService)
|
||||||
|
);
|
||||||
|
|
||||||
expect(setFailedMock).not.toHaveBeenCalled();
|
expect(setFailedMock).not.toHaveBeenCalled();
|
||||||
expect(infoMock).toHaveBeenCalledWith("compose removed");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
34
src/runner.ts
Normal file
34
src/runner.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { setFailed } from "@actions/core";
|
||||||
|
import { InputService, Inputs } from "./services/input.service";
|
||||||
|
import { LoggerService } from "./services/logger.service";
|
||||||
|
import { DockerComposeService } from "./services/docker-compose.service";
|
||||||
|
|
||||||
|
export type RunCallback = (
|
||||||
|
inputs: Inputs,
|
||||||
|
loggerService: LoggerService,
|
||||||
|
dockerComposeService: DockerComposeService
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The run function for the action.
|
||||||
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
|
*/
|
||||||
|
export async function run(callback: RunCallback): Promise<void> {
|
||||||
|
try {
|
||||||
|
const loggerService = new LoggerService();
|
||||||
|
const inputService = new InputService(loggerService);
|
||||||
|
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)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,12 +9,14 @@ describe("DockerComposeService", () => {
|
|||||||
let upAllMock: jest.SpiedFunction<typeof v2.upAll>;
|
let upAllMock: jest.SpiedFunction<typeof v2.upAll>;
|
||||||
let upManyMock: jest.SpiedFunction<typeof v2.upMany>;
|
let upManyMock: jest.SpiedFunction<typeof v2.upMany>;
|
||||||
let downMock: jest.SpiedFunction<typeof v2.down>;
|
let downMock: jest.SpiedFunction<typeof v2.down>;
|
||||||
|
let logsMock: jest.SpiedFunction<typeof v2.logs>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
service = new DockerComposeService();
|
service = new DockerComposeService();
|
||||||
upAllMock = jest.spyOn(v2, "upAll").mockImplementation();
|
upAllMock = jest.spyOn(v2, "upAll").mockImplementation();
|
||||||
upManyMock = jest.spyOn(v2, "upMany").mockImplementation();
|
upManyMock = jest.spyOn(v2, "upMany").mockImplementation();
|
||||||
downMock = jest.spyOn(v2, "down").mockImplementation();
|
downMock = jest.spyOn(v2, "down").mockImplementation();
|
||||||
|
logsMock = jest.spyOn(v2, "logs").mockImplementation();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
@ -87,4 +89,29 @@ describe("DockerComposeService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("logs", () => {
|
||||||
|
it("should call logs with correct options", async () => {
|
||||||
|
const inputs: Inputs = {
|
||||||
|
composeFiles: ["docker-compose.yml"],
|
||||||
|
services: ["helloworld2", "helloworld3"],
|
||||||
|
composeFlags: [],
|
||||||
|
upFlags: [],
|
||||||
|
downFlags: [],
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
};
|
||||||
|
|
||||||
|
logsMock.mockResolvedValue({ exitCode: 0, err: "", out: "logs" });
|
||||||
|
|
||||||
|
await service.logs(inputs);
|
||||||
|
|
||||||
|
expect(v2.logs).toHaveBeenCalledWith(["helloworld2", "helloworld3"], {
|
||||||
|
composeOptions: [],
|
||||||
|
config: ["docker-compose.yml"],
|
||||||
|
log: true,
|
||||||
|
cwd: "/current/working/dir",
|
||||||
|
follow: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { IDockerComposeOptions, v2 } from "docker-compose";
|
import { IDockerComposeLogOptions, IDockerComposeOptions, v2 } from "docker-compose";
|
||||||
import { Inputs } from "./input.service";
|
import { Inputs } from "./input.service";
|
||||||
|
|
||||||
export class DockerComposeService {
|
export class DockerComposeService {
|
||||||
async up(inputs: Inputs): Promise<void> {
|
async up(inputs: Inputs): Promise<void> {
|
||||||
const options = {
|
const options: IDockerComposeOptions = {
|
||||||
...this.getCommonOptions(inputs),
|
...this.getCommonOptions(inputs),
|
||||||
commandOptions: inputs.upFlags,
|
commandOptions: inputs.upFlags,
|
||||||
};
|
};
|
||||||
@ -17,7 +17,7 @@ export class DockerComposeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async down(inputs: Inputs): Promise<void> {
|
async down(inputs: Inputs): Promise<void> {
|
||||||
const options = {
|
const options: IDockerComposeOptions = {
|
||||||
...this.getCommonOptions(inputs),
|
...this.getCommonOptions(inputs),
|
||||||
commandOptions: inputs.downFlags,
|
commandOptions: inputs.downFlags,
|
||||||
};
|
};
|
||||||
@ -25,6 +25,20 @@ export class DockerComposeService {
|
|||||||
await v2.down(options);
|
await v2.down(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async logs(inputs: Inputs): Promise<{ error: string; output: string }> {
|
||||||
|
const options: IDockerComposeLogOptions = {
|
||||||
|
...this.getCommonOptions(inputs),
|
||||||
|
follow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { err, out } = await v2.logs(inputs.services, options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
error: err,
|
||||||
|
output: out,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private getCommonOptions(inputs: Inputs): IDockerComposeOptions {
|
private getCommonOptions(inputs: Inputs): IDockerComposeOptions {
|
||||||
return {
|
return {
|
||||||
config: inputs.composeFiles,
|
config: inputs.composeFiles,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { info, warning } from "@actions/core";
|
import { debug, info, warning } from "@actions/core";
|
||||||
|
|
||||||
export class LoggerService {
|
export class LoggerService {
|
||||||
warn(message: string): void {
|
warn(message: string): void {
|
||||||
@ -8,4 +8,8 @@ export class LoggerService {
|
|||||||
info(message: string): void {
|
info(message: string): void {
|
||||||
info(message);
|
info(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug(message: string) {
|
||||||
|
debug(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user