Allow builds for all targets

This commit is contained in:
Webber 2019-12-22 18:07:55 +01:00 committed by Webber Takken
parent 2ab738c083
commit bafc8e806b
11 changed files with 159 additions and 201 deletions

View File

@ -9,29 +9,33 @@ env:
PROJECT_PATH: test-project PROJECT_PATH: test-project
jobs: jobs:
strategy:
matrix:
unityVersion:
- 2019.2.11f1
targetPlatform:
- WebGL
# - StandaloneOSX
# - StandaloneWindows
# - StandaloneWindows64
# - StandaloneLinux64
# - PS4
# - XboxOne
# - Switch
- Android
- iOS
# - tvOS
# - Lumin
# - BJM
# - WSAPlayer
buildForAllPlatforms: buildForAllPlatforms:
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }} name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
unityVersion:
- 2019.2.11f1
targetPlatform:
- WebGL
- StandaloneOSX
- StandaloneWindows
- StandaloneWindows64
- StandaloneLinux64
- PS4
- XboxOne
- Switch
- Android
- iOS
- tvOS
- Lumin
- BJM
- Stadia
- WSAPlayer
- Facebook
- NoTarget
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- uses: webbertakken/unity-activate@v1 - uses: webbertakken/unity-activate@v1
@ -40,8 +44,8 @@ jobs:
projectPath: test-project projectPath: test-project
targetPlatform: ${{ matrix.targetPlatform }} targetPlatform: ${{ matrix.targetPlatform }}
unityVersion: ${{ matrix.unityVersion }} unityVersion: ${{ matrix.unityVersion }}
- uses: webbertakken/unity-return-license@v1 # - uses: webbertakken/unity-return-license@v1
if: always() # if: always()
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:
name: Build name: Build

BIN
dist/index.js vendored

Binary file not shown.

View File

@ -1,6 +1,6 @@
import Action from './model/action'; import Action from './model/action';
import Docker from './model/docker'; import Docker from './model/docker';
import ImageTag from './model/image'; import ImageTag from './model/image-tag';
import Input from './model/input'; import Input from './model/input';
const core = require('@actions/core'); const core = require('@actions/core');
@ -8,19 +8,15 @@ const core = require('@actions/core');
async function action() { async function action() {
Action.checkCompatibility(); Action.checkCompatibility();
const {
unityVersion,
targetPlatform,
projectPath,
buildName,
buildsPath,
buildMethod,
} = Input.getFromUser();
const { dockerfile, workspace } = Action; const { dockerfile, workspace } = Action;
const baseImage = new ImageTag({ unityVersion, targetPlatform }); const { version, platform, projectPath, buildName, buildsPath, method } = Input.getFromUser();
const builtImage = await Docker.build({ path: workspace, dockerfile, image: baseImage });
await Docker.run(builtImage, { projectPath, buildName, buildsPath, buildMethod }); console.log({ version, platform, projectPath, buildName, buildsPath, method });
const baseImage = new ImageTag({ version, platform });
const builtImage = await Docker.build({ path: workspace, dockerfile, baseImage });
await Docker.run(builtImage, { workspace, platform, projectPath, buildName, buildsPath, method });
} }
action().catch(error => { action().catch(error => {

View File

@ -5,12 +5,29 @@ export default class Action {
return ['linux']; return ['linux'];
} }
static get isRunningLocally() {
return process.env.RUNNER_WORKSPACE === undefined;
}
static get isRunningFromSource() {
return __dirname !== 'dist';
}
static get name() { static get name() {
return 'unity-builder'; return 'unity-builder';
} }
static get rootFolder() { static get rootFolder() {
return path.dirname(path.dirname(__dirname)); if (!Action.isRunningLocally) {
const workspace = process.env.RUNNER_WORKSPACE;
return `${workspace}/${path.basename(workspace)}`;
}
if (Action.isRunningFromSource) {
return path.dirname(path.dirname(path.dirname(__filename)));
}
return path.dirname(path.dirname(__filename));
} }
static get dockerfile() { static get dockerfile() {

View File

@ -1,36 +1,44 @@
import { exec } from '@actions/exec'; import { exec } from '@actions/exec';
import ImageTag from './image-tag';
export default class Docker { export default class Docker {
static async build(buildParameters) { static async build(buildParameters, silent = false) {
const { path = './', dockerfile, image } = buildParameters; const { path, dockerfile, baseImage } = buildParameters;
const tag = `unity-builder:${image.tag}`; const { version, platform } = baseImage;
await exec('pwd'); const tag = new ImageTag({ repository: '', name: 'unity-builder', version, platform });
await exec('ls -alh'); const command = `docker build ${path} \
await exec(`ls -alh ${path}`); --file ${dockerfile} \
await exec(` --build-arg IMAGE=${baseImage} \
docker build ${path} --tag ${tag}`;
--file ${dockerfile}
--build-arg IMAGE=${image} await exec(command, null, { silent });
--tag ${tag}
`);
return tag; return tag;
} }
static async run(image, parameters) { static async run(image, parameters) {
const { GITHUB_WORKSPACE } = process.env; const { workspace, platform, projectPath, buildName, buildsPath, method } = parameters;
const { projectPath, buildName, buildsPath, buildMethod } = parameters;
await exec(` console.log('running with parameters: ');
console.log({
workspace,
platform,
projectPath,
buildName,
buildsPath,
method,
});
await exec(`\
docker run \ docker run \
--workdir /github/workspace \ --workdir /github/workspace \
--rm \ --rm \
--env PROJECT_PATH=${projectPath} \ --env PROJECT_PATH=${projectPath} \
--env BUILD_TARGET=${image.targetPlatform} \ --env BUILD_TARGET=${platform} \
--env BUILD_NAME=${buildName} \ --env BUILD_NAME=${buildName} \
--env BUILDS_PATH=${buildsPath} \ --env BUILDS_PATH=${buildsPath} \
--env BUILD_METHOD=${buildMethod} \ --env BUILD_METHOD=${method} \
--env HOME=/github/home \ --env HOME=/github/home \
--env GITHUB_REF \ --env GITHUB_REF \
--env GITHUB_SHA \ --env GITHUB_SHA \
@ -50,8 +58,8 @@ export default class Docker {
--volume "/var/run/docker.sock":"/var/run/docker.sock" \ --volume "/var/run/docker.sock":"/var/run/docker.sock" \
--volume "/home/runner/work/_temp/_github_home":"/github/home" \ --volume "/home/runner/work/_temp/_github_home":"/github/home" \
--volume "/home/runner/work/_temp/_github_workflow":"/github/workflow" \ --volume "/home/runner/work/_temp/_github_workflow":"/github/workflow" \
--volume "${GITHUB_WORKSPACE}":"/github/workspace" \ --volume "${workspace}":"/github/workspace" \
${image} ${image} \
`); `);
} }
} }

View File

@ -1,15 +1,35 @@
import Action from './action'; import Action from './action';
import Docker from './docker'; import Docker from './docker';
import Image from './image'; import ImageTag from './image-tag';
describe('Docker', () => { describe('Docker', () => {
it('builds', async () => { it('builds', async () => {
const tag = await Docker.build({ const path = Action.rootFolder;
// path: Action.rootFolder, const dockerfile = `${path}/Dockerfile`;
dockerfile: `${Action.rootFolder}/Dockerfile`, const baseImage = new ImageTag({
image: new Image({ version: '2019.2.11f1', targetPlatform: 'WebGL' }), repository: '',
name: 'alpine',
version: '3',
platform: 'Test',
}); });
expect(tag).toStrictEqual('unity-builder:2019.2.11f1-webgl'); const tag = await Docker.build({ path, dockerfile, baseImage }, true);
expect(tag).toBeInstanceOf(ImageTag);
expect(tag.toString()).toStrictEqual('unity-builder:3');
}, 240000);
it.skip('runs', async () => {
const image = 'unity-builder:2019.2.11f1-webgl';
const parameters = {
workspace: Action.rootFolder,
projectPath: `${Action.rootFolder}/test-project`,
buildName: 'someBulidName',
buildsPath: 'build',
method: '',
};
await Docker.run(image, parameters);
}); });
}); });

View File

@ -1,33 +1,33 @@
import { has, get, trimEnd } from 'lodash-es'; import { has, get, trimEnd, trimStart } from 'lodash-es';
export default class Image { export default class ImageTag {
constructor(imageProperties) { constructor(imageProperties) {
const { const {
repository = 'gableroux', repository = 'gableroux',
name = 'unity3d', name = 'unity3d',
version = '2019.2.11f1', version = '2019.2.11f1',
targetPlatform, platform,
} = imageProperties; } = imageProperties;
if (!Image.versionPattern.test(version)) { if (!ImageTag.versionPattern.test(version)) {
throw new Error(`Invalid version "${version}".`); throw new Error(`Invalid version "${version}".`);
} }
if (!has(Image.targetPlatformToBuilderPlatformMap, targetPlatform)) { if (!has(ImageTag.targetPlatformToBuilderPlatformMap, platform)) {
throw new Error(`Platform "${targetPlatform}" is currently not supported.`); throw new Error(`Platform "${platform}" is currently not supported.`);
} }
const builderPlatform = get( const builderPlatform = get(
Image.targetPlatformToBuilderPlatformMap, ImageTag.targetPlatformToBuilderPlatformMap,
targetPlatform, platform,
Image.builderPlatforms.generic, ImageTag.builderPlatforms.generic,
); );
Object.assign(this, { repository, name, version, targetPlatform, builderPlatform }); Object.assign(this, { repository, name, version, platform, builderPlatform });
} }
static get versionPattern() { static get versionPattern() {
return /^20\d{2}\.\d\.\w{4}$/; return /^20\d{2}\.\d\.\w{4}|3$/;
} }
static get builderPlatforms() { static get builderPlatforms() {
@ -42,9 +42,11 @@ export default class Image {
} }
static get targetPlatformToBuilderPlatformMap() { static get targetPlatformToBuilderPlatformMap() {
const { generic, webgl, mac, windows, android, ios } = Image.builderPlatforms; const { generic, webgl, mac, windows, android, ios } = ImageTag.builderPlatforms;
// @see: https://github.com/Unity-Technologies/UnityCsReference/blob/9034442437e6b5efe28c51d02e978a96a3ce5439/Editor/Mono/BuildTarget.cs
return { return {
Test: generic,
WebGL: webgl, WebGL: webgl,
StandaloneOSX: mac, StandaloneOSX: mac,
StandaloneWindows: windows, StandaloneWindows: windows,
@ -61,6 +63,8 @@ export default class Image {
Stadia: generic, Stadia: generic,
WSAPlayer: generic, WSAPlayer: generic,
Facebook: generic, Facebook: generic,
// *undocumented*
NoTarget: generic,
}; };
} }
@ -68,9 +72,13 @@ export default class Image {
return trimEnd(`${this.version}-${this.builderPlatform}`, '-'); return trimEnd(`${this.version}-${this.builderPlatform}`, '-');
} }
toString() { get image() {
const { repository, name, tag } = this; return trimStart(`${this.repository}/${this.name}`, '/');
}
return `${repository}/${name}:${tag}`; toString() {
const { image, tag } = this;
return `${image}:${tag}`;
} }
} }

View File

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

View File

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

9
src/model/input.test.js Normal file
View File

@ -0,0 +1,9 @@
import Input from './input';
describe('Input', () => {
describe('getFromUser', () => {
it('does not throw', () => {
expect(() => Input.getFromUser()).not.toThrow();
});
});
});

View File

@ -1,105 +0,0 @@
#!/bin/sh
#
# Input variables
#
IMAGE_UNITY_VERSION=$1
IMAGE_TARGET_PLATFORM=$2
PROJECT_PATH=$3
TARGET_PLATFORM=$4
BUILD_NAME=$5
BUILDS_PATH=$6
BUILD_METHOD=$7
#
# Default variables
#
# PROJECT_PATH = test-project
# BUILD_TARGET =
# BUILD_NAME =
# BUILDS_PATH =
# BUILD_METHOD =
# HOME = /home/runner
# GITHUB_REF = refs/pull/8/merge
# GITHUB_SHA = 0e697e1f2d80e0e8505c0e0dcff76d24bc7a4f36
# GITHUB_REPOSITORY = webbertakken/unity-builder
# GITHUB_ACTOR = webbertakken
# GITHUB_WORKFLOW = Actions 😎
# GITHUB_HEAD_REF = prepare-for-multi-target
# GITHUB_BASE_REF = master
# GITHUB_EVENT_NAME = pull_request
# GITHUB_WORKSPACE = /home/runner/work/unity-builder/unity-builder
# GITHUB_ACTION = self
# GITHUB_EVENT_PATH = /home/runner/work/_temp/_github_workflow/event.json
# RUNNER_OS = Linux
# RUNNER_TOOL_CACHE = /opt/hostedtoolcache
# RUNNER_TEMP = /home/runner/work/_temp
# RUNNER_WORKSPACE = /home/runner/work/unity-builder
#
# Internal variables
#
ACTION_ROOT=$(dirname $(dirname $(readlink -fm "$0")))
DOCKER_IMAGE_TAG=unity-builder:$IMAGE_UNITY_VERSION-$IMAGE_TARGET_PLATFORM
# TODO - Remove debug statements (after it is proven to work)
echo "Listing ACTION_ROOT"
ls $ACTION_ROOT
echo ""
echo "Listing GITHUB_WORKSPACE"
ls $GITHUB_WORKSPACE
echo ""
echo "Listing RUNNER_WORKSPACE"
ls $RUNNER_WORKSPACE
echo ""
#
# Build image
#
echo "some test"
echo "Building docker image for $IMAGE_UNITY_VERSION-$IMAGE_TARGET_PLATFORM"
docker build $GITHUB_WORKSPACE \
--file $ACTION_ROOT/Dockerfile \
--build-arg IMAGE_REPOSITORY=gableroux \
--build-arg IMAGE_NAME=unity3d \
--build-arg IMAGE_VERSION=$IMAGE_UNITY_VERSION-$IMAGE_TARGET_PLATFORM \
--tag $DOCKER_IMAGE_TAG
#
# Run specified container
#
docker run \
--workdir /github/workspace \
--rm \
--env PROJECT_PATH \
--env BUILD_TARGET=$TARGET_PLATFORM \
--env BUILD_NAME \
--env BUILDS_PATH \
--env BUILD_METHOD \
--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 "${PWD}":"/github/workspace" \
$DOCKER_IMAGE_TAG