8 Commits
v1.1 ... v1.2

Author SHA1 Message Date
Webber
2a04635f7a Update docs 2020-01-29 21:12:59 +01:00
Webber
cd76fed14c Add activation variables 2020-01-29 21:12:59 +01:00
Webber
271ac6eac9 Add tests to pipeline 2020-01-29 21:12:59 +01:00
Webber
d786d61c77 Make image variable 2020-01-29 21:12:59 +01:00
Webber
02967cea9e Add action logic 2020-01-29 21:12:59 +01:00
Webber
8269c18142 Move dockerfile and entrypoint to action folder 2020-01-29 21:12:59 +01:00
Webber
29197ce88c Add meta files 2020-01-29 21:12:59 +01:00
Webber
6854c930fe Add workflow strategy for multiple versions 2020-01-29 21:12:59 +01:00
29 changed files with 6428 additions and 31 deletions

View File

@@ -11,11 +11,11 @@ tab_width = 2
trim_trailing_whitespace = true
[*.md]
max_line_length = 0
max_line_length = off
trim_trailing_whitespace = false
[*.yml]
max_line_length = 0
[*.{yml,yaml}]
max_line_length = off
[COMMIT_EDITMSG]
max_line_length = 0
max_line_length = off

2
.eslintignore Normal file
View File

@@ -0,0 +1,2 @@
**/node_modules/**
**/action/**

21
.eslintrc.json Normal file
View File

@@ -0,0 +1,21 @@
{
"parser": "babel-eslint",
"env": {
"node": true,
"es6": true,
"jest": true
},
"parserOptions": {
"ecmaVersion": 2020,
"ecmaFeatures": {
"impliedStrict": true
}
},
"extends": ["airbnb", "plugin:unicorn/recommended", "prettier"],
"plugins": ["react", "jsx-a11y", "import", "prettier", "flowtype", "unicorn"],
"settings": { "react": { "version": "latest" } },
"rules": {
"prettier/prettier": "error",
"import/no-extraneous-dependencies": 0
}
}

View File

@@ -7,14 +7,39 @@ env:
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n <Binding Key=\"2\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n </MachineBindings>\n <MachineID Value=\"Xxo1ZKbdPu/IATrc0mPBYANJFF0=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\n <Features>\n <Feature Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature Value=\"62\"/>\n </Features>\n <DeveloperData Value=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2019-11-25T18:23:38\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.2.11f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>JHdOBFmBNq2H8BrGFzir/StLoYo=</DigestValue></Reference></SignedInfo><SignatureValue>aENLHd37a51RtP2/g7YU0Pexf5mx0/ENXYGtrPzqwZ8NQt2AsSdxGnl0CUB45/GuNXfJVDt2HWot\ncNYZB2OylVBn1WHQbKZlPmm8gEAMz0MYbr4Isb5i5buryBrZlmbEOjnRI+pEg1CBwlgMo6xdtjjE\n/d7cC293QIUO91kdzRXftYou1dNaUyuPL9ZH65vdB2pDXGRNxgUVD+GnnqZA7b5L2HXqNQclcWAK\n5Yd1BeF3VzR1iLw9G/SmH5oOhnpXSmqbL4qk7LVP2/mgXpFk5kP4X8VC3z47obNhBIGq40dwWyEe\nUYk5/nRAOkZawDT+tcu96e06gPC9Cxk5PdbRbA==</SignatureValue></Signature></root>"
jobs:
requestActivation:
name: Request activation ✔
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1.1.2
with:
node-version: 12.x
- run: yarn
- run: yarn lint
- run: yarn test
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
- run: yarn build --quiet && git diff --quiet action || { echo "action should be auto generated" ; exit 62; }
requestActivation:
name: Activate ${{ matrix.unityVersion }} ✔
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
unityVersion:
# Note: Major version differences may require different activation files.
- 2018.4.15f1
- 2019.2.11f1
- 2019.2.14f1
- 2019.2.17f1
steps:
# Checkout repository (required to test local actions)
- name: Checkout repository
uses: actions/checkout@v1
uses: actions/checkout@v2
# Activate Unity
- name: Activate Unity
uses: ./
with:
unityVersion: ${{ matrix.unityVersion }}

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.idea
node_modules

2
.prettierignore Normal file
View File

@@ -0,0 +1,2 @@
**/node_modules/**
**/action/**

6
.prettierrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100
}

3
.yarnrc Normal file
View File

@@ -0,0 +1,3 @@
save-prefix ""
--install.audit true
--add.audit true

View File

@@ -19,8 +19,20 @@ When fixing a bug it is fine to submit a pull request right away.
Steps to be performed to submit a pull request:
1. Fork the repository and create your branch from `master`
2. Fill out the description, link any related issues and submit your pull request.
1. Fork the repository and create your branch from `master`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Fill out the description, link any related issues and submit your pull request.
#### Pull Request Prerequisites
You have [Node](https://nodejs.org/) installed at v12.2.0+ and [Yarn](https://yarnpkg.com/) at v1.18.0+.
Please note that commit hooks will run automatically to perform some tasks;
- format your code
- run tests
- build distributable files
#### License

View File

@@ -1,32 +1,33 @@
# Unity - Activate
[![Actions status](https://github.com/webbertakken/unity-activate/workflows/Actions%20%F0%9F%98%8E/badge.svg)](https://github.com/webbertakken/unity-activate/actions?query=branch%3Amaster+workflow%3A"Actions+😎")
---
GitHub Action to [activate Unity](https://github.com/marketplace/actions/unity-activate).
GitHub Action to [activate Unity](https://github.com/marketplace/actions/unity-activate).
Part of the [Unity Actions](https://github.com/webbertakken/unity-actions) collection.
---
Use this action to activate Unity using credentials or a license file. Both
Use this action to activate Unity using credentials or a license file. Both
**personal** and **professional** licenses are supported.
When successfully activated, you will be able to run the
Note that the latest versions of
[Test](https://github.com/webbertakken/unity-actions#test) and
[Build](https://github.com/webbertakken/unity-actions#build)
actions.
contain standalone activation and no longer require this action.
### Documentation
See the
See the
[Unity Actions](https://github.com/webbertakken/unity-actions)
collection repository for workflow documentation and reference implementation.
## Usage
Create or edit the file called `.github/workflows/activation.yml` and add a job to it.
Create or edit the file called `.github/workflows/main.yml` and add a job to it.
```yaml
name: Activate Unity
on: [push]
@@ -46,7 +47,7 @@ Continue to either the personal license or professional license section below.
```yaml
- name: Activate Unity
uses: webbertakken/unity-activate@v1.1
uses: webbertakken/unity-activate@v1.2
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
```
@@ -55,28 +56,65 @@ Continue to either the personal license or professional license section below.
1. Goto `Repository` > `Settings` > `Secrets`
2. Set the following secrets:
- `UNITY_EMAIL`: &lt;your_unity_login_email_address&gt;
- `UNITY_PASSWORD`: &lt;your_unity_login_password&gt;
- `UNITY_SERIAL`: &lt;your_unity_serial&gt;
- `UNITY_EMAIL`: &lt;your_unity_login_email_address&gt;
- `UNITY_PASSWORD`: &lt;your_unity_login_password&gt;
- `UNITY_SERIAL`: &lt;your_unity_serial&gt;
3. Use the action as follows:
```yaml
- name: Activate Unity
uses: webbertakken/unity-activate@v1.1
uses: webbertakken/unity-activate@v1.2
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
```
#### Specifying version
Major version differences may require different activation files.
To activate this job's environment for a specific version of unity
```yaml
- name: Activate Unity
uses: webbertakken/unity-activate@v1.2
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
unityVersion: 2019.2.11f1
```
#### Returning licenses
When using Pro licenses, free spots are being used up by activating licenses.
In order to keep continuity you need to return the license at the end of your workflow.
Example:
```yaml
- name: Return license
uses: webbertakken/unity-return-license@v1
if: always()
```
For specific information about returning the license, visit
the [return license](https://github.com/marketplace/actions/unity-return-license)
docs.
#### Save your workflow
Commit and push your workflow definition.
## More actions
Visit
[Unity Actions](https://github.com/webbertakken/unity-actions)
Visit
[Unity Actions](https://github.com/webbertakken/unity-actions)
to find related actions for Unity.
Feel free to contribute.
## Licence
## Licence
[MIT](./LICENSE)

View File

@@ -1,11 +1,15 @@
name: 'Unity - Activate'
author: Webber Takken <webber@takken.io>
description: 'Activate Unity using credentials or a license file. Both personal and professional licenses are supported.'
inputs: {}
inputs:
unityVersion:
required: false
default: '2019.2.11f1'
description: 'Version of unity to use for building the project.'
outputs: {}
runs:
using: 'docker'
image: 'Dockerfile'
branding:
icon: 'box'
color: 'gray-dark'
runs:
using: 'node12'
main: 'action/index.js'

View File

@@ -1,4 +1,5 @@
FROM gableroux/unity3d:2019.2.11f1
ARG IMAGE
FROM $IMAGE
LABEL "com.github.actions.name"="Unity - Activate"
LABEL "com.github.actions.description"="Activate Unity using credentials or a license file. Both personal and professional licenses are supported."

View File

@@ -1,5 +1,11 @@
#!/usr/bin/env bash
#
# Display the unity version
#
echo "Activating Unity version \"$UNITY_VERSION\"."
if [[ -n "$UNITY_LICENSE" ]]; then
#
# PERSONAL LICENSE MODE

1
action/index.js Normal file

File diff suppressed because one or more lines are too long

15
babel.config.js Normal file
View File

@@ -0,0 +1,15 @@
const esModules = ['lodash-es'].join('|');
module.exports = {
ignore: [`/node_modules/(?!${esModules})`],
presets: [
[
'@babel/preset-env',
{
targets: {
node: true,
},
},
],
],
};

8
jest.config.js Normal file
View File

@@ -0,0 +1,8 @@
const esModules = ['lodash-es'].join('|');
module.exports = {
testEnvironment: 'node',
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: { '^.+\\.(js|jsx)?$': 'babel-jest' },
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
};

57
package.json Normal file
View File

@@ -0,0 +1,57 @@
{
"name": "unity-activate",
"version": "0.0.0",
"description": "Activate Unity using credentials or a license file. Both personal and professional licenses are supported.",
"main": "action/index.js",
"repository": "git@github.com:webbertakken/unity-activate.git",
"author": "Webber <webber@takken.io>",
"license": "MIT",
"scripts": {
"build": "ncc build src --out action --minify",
"lint": "prettier --check \"src/**/*.js\" && eslint src",
"test": "jest"
},
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/exec": "1.0.2",
"@actions/github": "^2.0.0"
},
"devDependencies": {
"@babel/cli": "7.7.5",
"@babel/core": "7.7.5",
"@babel/preset-env": "7.7.7",
"@zeit/ncc": "0.20.5",
"babel-eslint": "10.0.3",
"eslint": "6.7.2",
"eslint-config-airbnb": "18.0.1",
"eslint-config-prettier": "6.7.0",
"eslint-plugin-flowtype": "4.5.2",
"eslint-plugin-import": "2.19.1",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.2",
"eslint-plugin-react": "7.17.0",
"eslint-plugin-unicorn": "14.0.1",
"husky": "4.0.0-beta.5",
"jest": "24.9.0",
"lint-staged": "9.5.0",
"lodash-es": "4.17.15",
"prettier": "1.19.1"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged && yarn build && git add action/index.js"
}
},
"lint-staged": {
"*.{js,jsx}": [
"prettier --write",
"eslint",
"git add",
"jest --findRelatedTests"
],
"*.{json,md,yaml,yml}": [
"prettier --write",
"git add"
]
}
}

21
src/index.js Normal file
View File

@@ -0,0 +1,21 @@
import { Action, Docker, Input, ImageTag } from './model';
const core = require('@actions/core');
async function action() {
Action.checkCompatibility();
const { dockerfile, workspace, actionFolder } = Action;
const { unityVersion } = Input.getFromUser();
const baseImage = ImageTag.createForBase(unityVersion);
// Build docker image
const actionImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
// Run docker image
await Docker.run(actionImage, { workspace, unityVersion });
}
action().catch(error => {
core.setFailed(error.message);
});

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

@@ -0,0 +1,48 @@
import path from 'path';
class Action {
static get supportedPlatforms() {
return ['linux'];
}
static get isRunningLocally() {
return process.env.RUNNER_WORKSPACE === undefined;
}
static get isRunningFromSource() {
return path.basename(__dirname) === 'model';
}
static get name() {
return 'unity-activate';
}
static get rootFolder() {
if (Action.isRunningFromSource) {
return path.dirname(path.dirname(path.dirname(__filename)));
}
return path.dirname(path.dirname(__filename));
}
static get actionFolder() {
return `${Action.rootFolder}/action`;
}
static get dockerfile() {
return `${Action.actionFolder}/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`);
}
}
}
export default Action;

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

@@ -0,0 +1,36 @@
import path from 'path';
import fs from 'fs';
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);
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
});
it('returns the action folder', () => {
const { actionFolder } = Action;
expect(path.basename(actionFolder)).toStrictEqual('action');
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
});
it('returns the docker file', () => {
const { dockerfile } = Action;
expect(path.basename(dockerfile)).toStrictEqual('Dockerfile');
expect(fs.existsSync(dockerfile)).toStrictEqual(true);
});
});

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

@@ -0,0 +1,57 @@
import { exec } from '@actions/exec';
import ImageTag from './image-tag';
class Docker {
static async build(buildParameters, silent = false) {
const { path, dockerfile, baseImage } = buildParameters;
const { version } = baseImage;
const tag = ImageTag.createForAction(version);
const command = `docker build ${path} \
--file ${dockerfile} \
--build-arg IMAGE=${baseImage} \
--tag ${tag}`;
await exec(command, null, { silent });
return tag;
}
static async run(image, parameters, silent = false) {
const { unityVersion, workspace } = parameters;
const command = `docker run \
--workdir /github/workspace \
--rm \
--env UNITY_LICENSE \
--env UNITY_EMAIL \
--env UNITY_PASSWORD \
--env UNITY_SERIAL \
--env UNITY_VERSION=${unityVersion} \
--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 "${workspace}":"/github/workspace" \
${image}`;
await exec(command, null, { silent });
}
}
export default Docker;

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

@@ -0,0 +1,20 @@
import Action from './action';
import Docker from './docker';
import ImageTag from './image-tag';
describe('Docker', () => {
it('builds', async () => {
const path = Action.actionFolder;
const dockerfile = `${path}/Dockerfile`;
const baseImage = new ImageTag({
repository: '',
name: 'alpine',
version: '3',
});
const tag = await Docker.build({ path, dockerfile, baseImage }, true);
expect(tag).toBeInstanceOf(ImageTag);
expect(tag.toString()).toStrictEqual('unity-action:3');
}, 240000);
});

41
src/model/image-tag.js Normal file
View File

@@ -0,0 +1,41 @@
import { trimStart } from 'lodash-es';
class ImageTag {
static createForBase(version) {
const repository = 'gableroux';
const name = 'unity3d';
return new this({ repository, name, version });
}
static createForAction(version) {
const repository = '';
const name = 'unity-action';
return new this({ repository, name, version });
}
constructor({ repository = '', name, version }) {
if (!ImageTag.versionPattern.test(version)) {
throw new Error(`Invalid version "${version}".`);
}
Object.assign(this, { repository, name, version });
}
static get versionPattern() {
return /^20\d{2}\.\d\.\w{3,4}|3$/;
}
get tag() {
return this.version;
}
get image() {
return trimStart(`${this.repository}/${this.name}`, '/');
}
toString() {
return `${this.image}:${this.tag}`;
}
}
export default ImageTag;

View File

@@ -0,0 +1,38 @@
import ImageTag from './image-tag';
describe('UnityImageVersion', () => {
describe('constructor', () => {
const some = {
name: 'someName',
version: '2020.0.00f0',
};
it('can be called', () => {
expect(() => new ImageTag(some)).not.toThrow();
});
it('accepts parameters and sets the right properties', () => {
const image = new ImageTag(some);
expect(image.repository).toStrictEqual('');
expect(image.name).toStrictEqual(some.name);
expect(image.version).toStrictEqual(some.version);
});
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', version => {
expect(() => new ImageTag({ version })).not.toThrow();
});
test.each(['some version', '', 1, null])('throws for incorrect versions %p', version => {
expect(() => new ImageTag({ version })).toThrow();
});
});
describe('toString', () => {
it('returns the correct version', () => {
const image = ImageTag.createForBase('2099.1.1111');
expect(image.toString()).toStrictEqual(`gableroux/unity3d:2099.1.1111`);
});
});
});

6
src/model/index.js Normal file
View File

@@ -0,0 +1,6 @@
import Action from './action';
import Docker from './docker';
import Input from './input';
import ImageTag from './image-tag';
export { Action, Docker, Input, ImageTag };

7
src/model/index.test.js Normal file
View File

@@ -0,0 +1,7 @@
import * as Index from '.';
describe('Index', () => {
test.each(['Action', 'Docker', 'ImageTag', 'Input'])('exports %s', exportedModule => {
expect(typeof Index[exportedModule]).toStrictEqual('function');
});
});

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

@@ -0,0 +1,15 @@
const core = require('@actions/core');
class Input {
static getFromUser() {
// Input variables specified in workflow using "with" prop.
const unityVersion = core.getInput('unityVersion') || '2019.2.11f1';
// Return sanitised input
return {
unityVersion,
};
}
}
export default Input;

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

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

5893
yarn.lock Normal file

File diff suppressed because it is too large Load Diff