Run docker from javascript

This commit is contained in:
Webber
2019-12-22 15:05:15 +01:00
committed by Webber Takken
parent 9a639e97e3
commit 2ab738c083
19 changed files with 1013 additions and 181 deletions

View File

@@ -1,38 +1,26 @@
import Action from './model/action';
import Docker from './model/docker';
import ImageTag from './model/image';
import Input from './model/input';
const core = require('@actions/core');
const path = require('path');
const { exec } = require('@actions/exec');
async function action() {
// Explicitly notify about platform support
if (process.platform !== 'linux') {
throw new Error('Currently only Linux-based platforms are supported');
}
Action.checkCompatibility();
// Input variables specified in workflows using "with" prop.
const projectPath = core.getInput('projectPath', { default: './' });
const targetPlatform = core.getInput('targetPlatform', { default: 'WebGL' });
const unityVersion = core.getInput('unityVersion', { default: '2019.2.11f1' });
const buildName = core.getInput('buildName', { default: 'TestBuild' });
const buildsPath = core.getInput('buildsPath', { default: 'build' });
const buildMethod = core.getInput('buildMethod', { default: '' });
// Determine image
const IMAGE_UNITY_VERSION = unityVersion;
const IMAGE_TARGET_PLATFORM = targetPlatform.toLowerCase();
// Run appropriate docker image with given args
const bootstrapper = path.join(__dirname, 'run-unity-builder.sh');
await exec(`ls ${bootstrapper}`);
await exec(`chmod +x ${bootstrapper}`);
await exec(bootstrapper, [
IMAGE_UNITY_VERSION,
IMAGE_TARGET_PLATFORM,
projectPath,
const {
unityVersion,
targetPlatform,
projectPath,
buildName,
buildsPath,
buildMethod,
]);
} = Input.getFromUser();
const { dockerfile, workspace } = Action;
const baseImage = new ImageTag({ unityVersion, targetPlatform });
const builtImage = await Docker.build({ path: workspace, dockerfile, image: baseImage });
await Docker.run(builtImage, { projectPath, buildName, buildsPath, buildMethod });
}
action().catch(error => {

30
src/model/action.js Normal file
View File

@@ -0,0 +1,30 @@
import path from 'path';
export default class Action {
static get supportedPlatforms() {
return ['linux'];
}
static get name() {
return 'unity-builder';
}
static get rootFolder() {
return path.dirname(path.dirname(__dirname));
}
static get dockerfile() {
return `${Action.rootFolder}/Dockerfile`;
}
static get workspace() {
return process.env.GITHUB_WORKSPACE;
}
static checkCompatibility() {
const currentPlatform = process.platform;
if (!Action.supportedPlatforms.includes(currentPlatform)) {
throw new Error(`Currently ${currentPlatform}-platform is not supported`);
}
}
}

20
src/model/action.test.js Normal file
View File

@@ -0,0 +1,20 @@
import path from 'path';
import Action from './action';
describe('Action', () => {
describe('compatibility check', () => {
it('throws for anything other than linux', () => {
if (process.platform !== 'linux') {
expect(() => Action.checkCompatibility()).toThrow();
} else {
expect(() => Action.checkCompatibility()).not.toThrow();
}
});
});
it('returns the root folder of the action', () => {
const { rootFolder, name } = Action;
expect(path.basename(rootFolder)).toStrictEqual(name);
});
});

57
src/model/docker.js Normal file
View File

@@ -0,0 +1,57 @@
import { exec } from '@actions/exec';
export default class Docker {
static async build(buildParameters) {
const { path = './', dockerfile, image } = buildParameters;
const tag = `unity-builder:${image.tag}`;
await exec('pwd');
await exec('ls -alh');
await exec(`ls -alh ${path}`);
await exec(`
docker build ${path}
--file ${dockerfile}
--build-arg IMAGE=${image}
--tag ${tag}
`);
return tag;
}
static async run(image, parameters) {
const { GITHUB_WORKSPACE } = process.env;
const { projectPath, buildName, buildsPath, buildMethod } = parameters;
await exec(`
docker run \
--workdir /github/workspace \
--rm \
--env PROJECT_PATH=${projectPath} \
--env BUILD_TARGET=${image.targetPlatform} \
--env BUILD_NAME=${buildName} \
--env BUILDS_PATH=${buildsPath} \
--env BUILD_METHOD=${buildMethod} \
--env HOME=/github/home \
--env GITHUB_REF \
--env GITHUB_SHA \
--env GITHUB_REPOSITORY \
--env GITHUB_ACTOR \
--env GITHUB_WORKFLOW \
--env GITHUB_HEAD_REF \
--env GITHUB_BASE_REF \
--env GITHUB_EVENT_NAME \
--env GITHUB_WORKSPACE=/github/workspace \
--env GITHUB_ACTION \
--env GITHUB_EVENT_PATH \
--env RUNNER_OS \
--env RUNNER_TOOL_CACHE \
--env RUNNER_TEMP \
--env RUNNER_WORKSPACE \
--volume "/var/run/docker.sock":"/var/run/docker.sock" \
--volume "/home/runner/work/_temp/_github_home":"/github/home" \
--volume "/home/runner/work/_temp/_github_workflow":"/github/workflow" \
--volume "${GITHUB_WORKSPACE}":"/github/workspace" \
${image}
`);
}
}

15
src/model/docker.test.js Normal file
View File

@@ -0,0 +1,15 @@
import Action from './action';
import Docker from './docker';
import Image from './image';
describe('Docker', () => {
it('builds', async () => {
const tag = await Docker.build({
// path: Action.rootFolder,
dockerfile: `${Action.rootFolder}/Dockerfile`,
image: new Image({ version: '2019.2.11f1', targetPlatform: 'WebGL' }),
});
expect(tag).toStrictEqual('unity-builder:2019.2.11f1-webgl');
});
});

76
src/model/image.js Normal file
View File

@@ -0,0 +1,76 @@
import { has, get, trimEnd } from 'lodash-es';
export default class Image {
constructor(imageProperties) {
const {
repository = 'gableroux',
name = 'unity3d',
version = '2019.2.11f1',
targetPlatform,
} = imageProperties;
if (!Image.versionPattern.test(version)) {
throw new Error(`Invalid version "${version}".`);
}
if (!has(Image.targetPlatformToBuilderPlatformMap, targetPlatform)) {
throw new Error(`Platform "${targetPlatform}" is currently not supported.`);
}
const builderPlatform = get(
Image.targetPlatformToBuilderPlatformMap,
targetPlatform,
Image.builderPlatforms.generic,
);
Object.assign(this, { repository, name, version, targetPlatform, builderPlatform });
}
static get versionPattern() {
return /^20\d{2}\.\d\.\w{4}$/;
}
static get builderPlatforms() {
return {
generic: '',
webgl: 'webgl',
mac: 'mac',
windows: 'windows',
android: 'android',
ios: 'ios',
};
}
static get targetPlatformToBuilderPlatformMap() {
const { generic, webgl, mac, windows, android, ios } = Image.builderPlatforms;
return {
WebGL: webgl,
StandaloneOSX: mac,
StandaloneWindows: windows,
StandaloneWindows64: windows,
StandaloneLinux64: generic,
PS4: generic,
XboxOne: generic,
Switch: generic,
Android: android,
iOS: ios,
tvOS: generic,
Lumin: generic,
BJM: generic,
Stadia: generic,
WSAPlayer: generic,
Facebook: generic,
};
}
get tag() {
return trimEnd(`${this.version}-${this.builderPlatform}`, '-');
}
toString() {
const { repository, name, tag } = this;
return `${repository}/${name}:${tag}`;
}
}

66
src/model/image.test.js Normal file
View File

@@ -0,0 +1,66 @@
import Image from './image';
describe('UnityImageVersion', () => {
const some = {
repository: 'test1',
name: 'test2',
version: '2099.9.f9f9',
targetPlatform: 'Stadia',
builderPlatform: '',
};
const defaults = {
repository: 'gableroux',
name: 'unity3d',
image: 'gableroux/unity3d',
};
describe('constructor', () => {
it('can be called', () => {
expect(() => new Image({ targetPlatform: some.targetPlatform })).not.toThrow();
});
it('accepts parameters and sets the right properties', () => {
const image = new Image(some);
expect(image.repository).toStrictEqual(some.repository);
expect(image.name).toStrictEqual(some.name);
expect(image.version).toStrictEqual(some.version);
expect(image.targetPlatform).toStrictEqual(some.targetPlatform);
expect(image.builderPlatform).toStrictEqual(some.builderPlatform);
});
it('throws for incorrect versions', () => {
const { targetPlatform } = some;
expect(() => new Image({ version: 'some version', targetPlatform })).toThrow();
expect(() => new Image({ version: '', targetPlatform })).toThrow();
expect(() => new Image({ version: 1, targetPlatform })).toThrow();
expect(() => new Image({ version: null, targetPlatform })).toThrow();
});
it('throws for incorrect or unsupported targets', () => {
expect(() => new Image({ targetPlatform: undefined })).toThrow();
expect(() => new Image({ targetPlatform: 'nonExisting' })).toThrow();
});
});
describe('toString', () => {
it('returns the correct version', () => {
const image = new Image({ version: '2099.1.1111', targetPlatform: some.targetPlatform });
expect(image.toString()).toStrictEqual(`${defaults.image}:2099.1.1111`);
});
it('returns the specific build platform', () => {
const image = new Image({ version: '2019.2.11f1', targetPlatform: 'WebGL' });
expect(image.toString()).toStrictEqual(`${defaults.image}:2019.2.11f1-webgl`);
});
it('returns no specific build platform for generic targetPlatforms', () => {
const image = new Image({ targetPlatform: 'Stadia' });
expect(image.toString()).toStrictEqual(`${defaults.image}:2019.2.11f1`);
});
});
});

22
src/model/input.js Normal file
View File

@@ -0,0 +1,22 @@
const core = require('@actions/core');
export default class Input {
static getFromUser() {
// Input variables specified in workflows using "with" prop.
const unityVersion = core.getInput('unityVersion');
const targetPlatform = core.getInput('targetPlatform');
const projectPath = core.getInput('projectPath');
const buildName = core.getInput('buildName');
const buildsPath = core.getInput('buildsPath');
const buildMethod = core.getInput('buildMethod');
return {
unityVersion,
targetPlatform,
projectPath,
buildName,
buildsPath,
buildMethod,
};
}
}

View File

@@ -60,6 +60,7 @@ echo ""
#
# Build image
#
echo "some test"
echo "Building docker image for $IMAGE_UNITY_VERSION-$IMAGE_TARGET_PLATFORM"
docker build $GITHUB_WORKSPACE \