feat: ensure cleanup of docker containers (#198)
Cancelled or timeouted workflow would keep the docker container running. Closes game-ci/unity-test-runner#197 This has two parts: Part one. The entrypoints. `runs.post`: GitHub Action metadata allow running something after the action (regardless of a failure, crash, timeout, ...). https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runspost However, it needs to be a `.js` file and it can't be configured to pass any arguments. There already was `index.js` used as the main entrypoint. The build process of this file uses typescript compiler and ncc to pack all dependencies into one .js file. And ncc has no way of generating multiple files in one go, so the only solution would be to run ncc twice and generate two independent files. That would be quite unfortunate, wasting time and storage. So I rather came up with a new entrypoint that symlinked from two locations. And this new entrypoint understands how it was executed, so it can run the correct behaviour. This makes it easy to add `runs.pre` if needed. This new entrypoint is in `index.ts`. The original `index.ts` is now in `main.ts`. Part two. The signals. I've tried: * try/catch/finally around the `await Docker.run`. Catch and finally are not executed when process receives SIGINT. See the discussion in: https://github.com/nodejs/node/discussions/29480 * New AbortController and AbortSignal. Great concept, but the action.exec does not support it. So it can't be aborted. * Doing cleanup on `process.on('exit')`. Unfortunately you can't really do async stuff from there, so can't really run the docker rm command to delete the container. * Using `process.on('SIGINT')`. For some reason that wasn't really executing for me. I'd not put my hand in fire for this, but I assume because it was in the signal handler it does something special, or would heed to be scheduled for later with `setTimeout(0)`. Evaluating all these I came to a conclusion that it is fragile and just relying on a `runs.post` is much better and safer. `pull/199/head
parent
5263cf0ab1
commit
698c08cf4e
|
@ -62,4 +62,5 @@ branding:
|
|||
color: 'gray-dark'
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/index.js'
|
||||
main: 'dist/main.js'
|
||||
post: 'dist/post.js'
|
||||
|
|
|
@ -6,6 +6,54 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
|
|||
|
||||
"use strict";
|
||||
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
const path_1 = __nccwpck_require__(1017);
|
||||
const main_1 = __nccwpck_require__(3109);
|
||||
const post_1 = __nccwpck_require__(95);
|
||||
/*
|
||||
* GitHub Action can provide multiple executable entrypoints (pre, main, post),
|
||||
* but it is complicated process to generate multiple `.js` files with `ncc`.
|
||||
* So we rather generate just one entrypoint, that is symlinked to multiple locations (main.js and post.js).
|
||||
* Then when GitHub Action Runner executes it as `node path/to/main.js` and `node path/to/post.js`,
|
||||
* it can read arguments it was executed with and decide which file to execute.
|
||||
* The argv[0] is going to be a full path to `node` executable and
|
||||
* the argv[1] is going to be the full path to the script.
|
||||
* In case index.js would be marked executable and executed directly without the argv[1] it defaults to "main.js".
|
||||
*/
|
||||
function run([_, name = 'main.js']) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const script = (0, path_1.basename)(name);
|
||||
switch (script) {
|
||||
case 'main.js':
|
||||
yield (0, main_1.run)();
|
||||
break;
|
||||
case 'post.js':
|
||||
yield (0, post_1.run)();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown script argument: '${script}'`);
|
||||
}
|
||||
});
|
||||
}
|
||||
run(process.argv);
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3109:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
|
@ -35,6 +83,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.run = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const model_1 = __nccwpck_require__(1359);
|
||||
function run() {
|
||||
|
@ -44,10 +93,9 @@ function run() {
|
|||
const { workspace, actionFolder } = model_1.Action;
|
||||
const { editorVersion, customImage, projectPath, customParameters, testMode, coverageOptions, artifactsPath, useHostNetwork, sshAgent, gitPrivateToken, githubToken, checkName, chownFilesTo, } = model_1.Input.getFromUser();
|
||||
const baseImage = new model_1.ImageTag({ editorVersion, customImage });
|
||||
const runnerTemporaryPath = process.env.RUNNER_TEMP;
|
||||
const runnerContext = model_1.Action.runnerContext();
|
||||
try {
|
||||
yield model_1.Docker.run(baseImage, {
|
||||
actionFolder,
|
||||
yield model_1.Docker.run(baseImage, Object.assign({ actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
|
@ -59,9 +107,7 @@ function run() {
|
|||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
runnerTemporaryPath,
|
||||
chownFilesTo,
|
||||
});
|
||||
chownFilesTo }, runnerContext));
|
||||
}
|
||||
finally {
|
||||
yield model_1.Output.setArtifactsPath(artifactsPath);
|
||||
|
@ -79,7 +125,7 @@ function run() {
|
|||
}
|
||||
});
|
||||
}
|
||||
run();
|
||||
exports.run = run;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -119,6 +165,15 @@ const Action = {
|
|||
get workspace() {
|
||||
return process.env.GITHUB_WORKSPACE;
|
||||
},
|
||||
runnerContext() {
|
||||
var _a, _b;
|
||||
const runnerTemporaryPath = (_a = process.env.RUNNER_TEMP) !== null && _a !== void 0 ? _a : process.cwd();
|
||||
const githubAction = (_b = process.env.GITHUB_ACTION) !== null && _b !== void 0 ? _b : process.pid.toString();
|
||||
return {
|
||||
runnerTemporaryPath,
|
||||
githubAction,
|
||||
};
|
||||
},
|
||||
checkCompatibility() {
|
||||
const currentPlatform = process.platform;
|
||||
if (!Action.supportedPlatforms.includes(currentPlatform)) {
|
||||
|
@ -152,7 +207,30 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|||
const fs_1 = __nccwpck_require__(7147);
|
||||
const exec_1 = __nccwpck_require__(1514);
|
||||
const path_1 = __importDefault(__nccwpck_require__(1017));
|
||||
/**
|
||||
* Build a path for a docker --cidfile parameter. Docker will store the the created container.
|
||||
* This path is stable for the whole execution of the action, so it can be executed with the same parameters
|
||||
* multiple times and get the same result.
|
||||
*/
|
||||
const containerIdFilePath = parameters => {
|
||||
const { runnerTemporaryPath, githubAction } = parameters;
|
||||
return path_1.default.join(runnerTemporaryPath, `container_${githubAction}`);
|
||||
};
|
||||
const Docker = {
|
||||
/**
|
||||
* Remove a possible leftover container created by `Docker.run`.
|
||||
*/
|
||||
ensureContainerRemoval(parameters) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
if (!(0, fs_1.existsSync)(cidfile)) {
|
||||
return;
|
||||
}
|
||||
const container = (0, fs_1.readFileSync)(cidfile, 'ascii').trim();
|
||||
yield (0, exec_1.exec)(`docker`, ['rm', '--force', '--volumes', container], { silent: true });
|
||||
(0, fs_1.rmSync)(cidfile);
|
||||
});
|
||||
},
|
||||
run(image, parameters, silent = false) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let runCommand = '';
|
||||
|
@ -177,9 +255,11 @@ const Docker = {
|
|||
const githubWorkflow = path_1.default.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!(0, fs_1.existsSync)(githubWorkflow))
|
||||
(0, fs_1.mkdirSync)(githubWorkflow);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const testPlatforms = (testMode === 'all' ? ['playmode', 'editmode', 'COMBINE_RESULTS'] : [testMode]).join(';');
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
|
@ -228,12 +308,14 @@ const Docker = {
|
|||
const githubHome = path_1.default.join(runnerTemporaryPath, '_github_home');
|
||||
if (!(0, fs_1.existsSync)(githubHome))
|
||||
(0, fs_1.mkdirSync)(githubHome);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const githubWorkflow = path_1.default.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!(0, fs_1.existsSync)(githubWorkflow))
|
||||
(0, fs_1.mkdirSync)(githubWorkflow);
|
||||
const testPlatforms = (testMode === 'all' ? ['playmode', 'editmode', 'COMBINE_RESULTS'] : [testMode]).join(';');
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
|
@ -1098,6 +1180,63 @@ const UnityVersionParser = {
|
|||
exports["default"] = UnityVersionParser;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 95:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.run = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const action_1 = __importDefault(__nccwpck_require__(9088));
|
||||
const model_1 = __nccwpck_require__(1359);
|
||||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const parameters = action_1.default.runnerContext();
|
||||
yield model_1.Docker.ensureContainerRemoval(parameters);
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.run = run;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 7351:
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
index.js
|
|
@ -0,0 +1 @@
|
|||
index.js
|
|
@ -8,7 +8,7 @@
|
|||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prebuild": "yarn",
|
||||
"build": "tsc && ncc build lib --source-map --license licenses.txt",
|
||||
"build": "tsc && ncc build lib/index.js --source-map --license licenses.txt",
|
||||
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts",
|
||||
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
||||
"test": "jest",
|
||||
|
|
79
src/index.ts
79
src/index.ts
|
@ -1,60 +1,31 @@
|
|||
import * as core from '@actions/core';
|
||||
import { Action, Docker, ImageTag, Input, Output, ResultsCheck } from './model';
|
||||
import { basename } from 'path';
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
Action.checkCompatibility();
|
||||
import { run as main } from './main';
|
||||
import { run as post } from './post';
|
||||
|
||||
const { workspace, actionFolder } = Action;
|
||||
const {
|
||||
editorVersion,
|
||||
customImage,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
checkName,
|
||||
chownFilesTo,
|
||||
} = Input.getFromUser();
|
||||
const baseImage = new ImageTag({ editorVersion, customImage });
|
||||
const runnerTemporaryPath = process.env.RUNNER_TEMP;
|
||||
/*
|
||||
* GitHub Action can provide multiple executable entrypoints (pre, main, post),
|
||||
* but it is complicated process to generate multiple `.js` files with `ncc`.
|
||||
* So we rather generate just one entrypoint, that is symlinked to multiple locations (main.js and post.js).
|
||||
* Then when GitHub Action Runner executes it as `node path/to/main.js` and `node path/to/post.js`,
|
||||
* it can read arguments it was executed with and decide which file to execute.
|
||||
* The argv[0] is going to be a full path to `node` executable and
|
||||
* the argv[1] is going to be the full path to the script.
|
||||
* In case index.js would be marked executable and executed directly without the argv[1] it defaults to "main.js".
|
||||
*/
|
||||
async function run([_, name = 'main.js']: string[]) {
|
||||
const script = basename(name);
|
||||
|
||||
try {
|
||||
await Docker.run(baseImage, {
|
||||
actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
runnerTemporaryPath,
|
||||
chownFilesTo,
|
||||
});
|
||||
} finally {
|
||||
await Output.setArtifactsPath(artifactsPath);
|
||||
await Output.setCoveragePath('CodeCoverage');
|
||||
}
|
||||
|
||||
if (githubToken) {
|
||||
const failedTestCount = await ResultsCheck.createCheck(artifactsPath, githubToken, checkName);
|
||||
if (failedTestCount >= 1) {
|
||||
core.setFailed(`Test(s) Failed! Check '${checkName}' for details.`);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
core.setFailed(error.message);
|
||||
switch (script) {
|
||||
case 'main.js':
|
||||
await main();
|
||||
break;
|
||||
case 'post.js':
|
||||
await post();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown script argument: '${script}'`);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
run(process.argv);
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import * as core from '@actions/core';
|
||||
import { Action, Docker, ImageTag, Input, Output, ResultsCheck } from './model';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
Action.checkCompatibility();
|
||||
|
||||
const { workspace, actionFolder } = Action;
|
||||
const {
|
||||
editorVersion,
|
||||
customImage,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
checkName,
|
||||
chownFilesTo,
|
||||
} = Input.getFromUser();
|
||||
const baseImage = new ImageTag({ editorVersion, customImage });
|
||||
const runnerContext = Action.runnerContext();
|
||||
|
||||
try {
|
||||
await Docker.run(baseImage, {
|
||||
actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
chownFilesTo,
|
||||
...runnerContext,
|
||||
});
|
||||
} finally {
|
||||
await Output.setArtifactsPath(artifactsPath);
|
||||
await Output.setCoveragePath('CodeCoverage');
|
||||
}
|
||||
|
||||
if (githubToken) {
|
||||
const failedTestCount = await ResultsCheck.createCheck(artifactsPath, githubToken, checkName);
|
||||
if (failedTestCount >= 1) {
|
||||
core.setFailed(`Test(s) Failed! Check '${checkName}' for details.`);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
import path from 'path';
|
||||
|
||||
export interface RunnerContext {
|
||||
runnerTemporaryPath: string;
|
||||
githubAction: string;
|
||||
}
|
||||
|
||||
const Action = {
|
||||
get supportedPlatforms() {
|
||||
return ['linux', 'win32'];
|
||||
|
@ -33,6 +38,16 @@ const Action = {
|
|||
return process.env.GITHUB_WORKSPACE;
|
||||
},
|
||||
|
||||
runnerContext(): RunnerContext {
|
||||
const runnerTemporaryPath = process.env.RUNNER_TEMP ?? process.cwd();
|
||||
const githubAction = process.env.GITHUB_ACTION ?? process.pid.toString();
|
||||
|
||||
return {
|
||||
runnerTemporaryPath,
|
||||
githubAction,
|
||||
};
|
||||
},
|
||||
|
||||
checkCompatibility() {
|
||||
const currentPlatform = process.platform;
|
||||
if (!Action.supportedPlatforms.includes(currentPlatform)) {
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
import { existsSync, mkdirSync } from 'fs';
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs';
|
||||
import type { RunnerContext } from './action';
|
||||
import { exec } from '@actions/exec';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Build a path for a docker --cidfile parameter. Docker will store the the created container.
|
||||
* This path is stable for the whole execution of the action, so it can be executed with the same parameters
|
||||
* multiple times and get the same result.
|
||||
*/
|
||||
const containerIdFilePath = parameters => {
|
||||
const { runnerTemporaryPath, githubAction } = parameters;
|
||||
|
||||
return path.join(runnerTemporaryPath, `container_${githubAction}`);
|
||||
};
|
||||
|
||||
const Docker = {
|
||||
/**
|
||||
* Remove a possible leftover container created by `Docker.run`.
|
||||
*/
|
||||
async ensureContainerRemoval(parameters: RunnerContext) {
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
if (!existsSync(cidfile)) {
|
||||
return;
|
||||
}
|
||||
const container = readFileSync(cidfile, 'ascii').trim();
|
||||
await exec(`docker`, ['rm', '--force', '--volumes', container], { silent: true });
|
||||
rmSync(cidfile);
|
||||
},
|
||||
|
||||
async run(image, parameters, silent = false) {
|
||||
let runCommand = '';
|
||||
switch (process.platform) {
|
||||
|
@ -15,6 +40,7 @@ const Docker = {
|
|||
default:
|
||||
throw new Error(`Operation system, ${process.platform}, is not supported yet.`);
|
||||
}
|
||||
|
||||
await exec(runCommand, undefined, { silent });
|
||||
},
|
||||
|
||||
|
@ -40,12 +66,14 @@ const Docker = {
|
|||
if (!existsSync(githubHome)) mkdirSync(githubHome);
|
||||
const githubWorkflow = path.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!existsSync(githubWorkflow)) mkdirSync(githubWorkflow);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const testPlatforms = (
|
||||
testMode === 'all' ? ['playmode', 'editmode', 'COMBINE_RESULTS'] : [testMode]
|
||||
).join(';');
|
||||
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
|
@ -112,6 +140,7 @@ const Docker = {
|
|||
|
||||
const githubHome = path.join(runnerTemporaryPath, '_github_home');
|
||||
if (!existsSync(githubHome)) mkdirSync(githubHome);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const githubWorkflow = path.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!existsSync(githubWorkflow)) mkdirSync(githubWorkflow);
|
||||
const testPlatforms = (
|
||||
|
@ -120,6 +149,7 @@ const Docker = {
|
|||
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import * as core from '@actions/core';
|
||||
import Action from './model/action';
|
||||
import { Docker } from './model';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
const parameters = Action.runnerContext();
|
||||
await Docker.ensureContainerRemoval(parameters);
|
||||
} catch (error: any) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue