20 Commits
v1 ... 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
Webber
9f17963cae update readme to reflect v1.1 2020-01-21 22:07:53 +01:00
Webber
8414ce0554 Add contribution docs 2020-01-21 22:03:59 +01:00
Webber
caf297b116 Use hardcoded license for allowing workflow in external PRs 2020-01-21 22:03:59 +01:00
Webber
7358ec3716 propagate changes from builder 2020-01-21 22:03:59 +01:00
Webber
5e03b210c2 Add pull requests as trigger for workflow 2019-12-07 16:03:17 +01:00
Webber
6ef27b7927 Cleanup unnecessary parts 2019-12-07 13:37:19 +01:00
Webber
a6b928dd48 Debug pro, by checkout output of license 2019-12-03 23:03:14 +01:00
Webber
3036261b08 Remove verified comment 2019-12-03 22:33:18 +01:00
Webber
661dd4a025 Fix typo in README.md 2019-12-03 22:33:18 +01:00
Webber Takken
45b67581ab Update urls in readme 2019-12-01 03:29:15 +01:00
Webber Takken
939b7241d2 Add documentation reference 2019-11-30 18:32:19 +01:00
Webber
9d6cebb666 Fix typo in README.md 2019-11-30 15:23:24 +01:00
31 changed files with 6671 additions and 126 deletions

21
.editorconfig Normal file
View File

@@ -0,0 +1,21 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
max_line_length = 100
tab_width = 2
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
[*.{yml,yaml}]
max_line_length = off
[COMMIT_EDITMSG]
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

@@ -1,17 +1,45 @@
name: Actions 😎
on: [push]
on:
pull_request: {}
push: { branches: [master] }
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: ./
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
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

76
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at webber@takken.io. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

39
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,39 @@
# Contributing
## How to Contribute
#### Code of Conduct
This repository has adopted the Contributor Covenant as it's
Code of Conduct. It is expected that participants adhere to it.
#### Proposing a Change
If you are unsure about whether or not a change is desired,
you can create an issue. This is useful because it creates
the possibility for a discussion that's visible to everyone.
When fixing a bug it is fine to submit a pull request right away.
#### Sending a Pull Request
Steps to be performed to submit a 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
By contributing to this repository, you agree that your contributions will be licensed under its MIT license.

View File

@@ -1,25 +1,35 @@
# 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/workflows/Actions%20%F0%9F%98%8E/badge.svg)
[Github Action](https://github.com/features/actions)
to activate Unity using credentials or a license file. Both **personal** and
**professional** licenses are supported.
[![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+😎")
Use this action to verify whether your license file is correctly configured. If
so, you will be able to run the
---
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
**personal** and **professional** licenses are supported.
Note that the latest versions of
[Test](https://github.com/webbertakken/unity-actions#test) and
[Build](https://github.com/webbertakken/unity-actions#build)
actions from the
[Unity Actions](https://github.com/webbertakken/unity-actions)
collection too.
contain standalone activation and no longer require this action.
### Documentation
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: Acquire activation file
name: Activate Unity
on: [push]
jobs:
requestActivation:
@@ -37,7 +47,7 @@ Continue to either the personal license or professional license section below.
```yaml
- name: Activate Unity
uses: webbertakken/unity-activate@v1
uses: webbertakken/unity-activate@v1.2
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
```
@@ -46,27 +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
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 }}
```
_**Note:** I was not able to verify these steps as i don't have a pro license. Feel free
to give
[feedback](https://github.com/webbertakken/unity-activate/issues/new) or
[contribute](https://github.com/webbertakken/unity-activate)._
#### 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
[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."

107
action/entrypoint.sh Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env bash
#
# Display the unity version
#
echo "Activating Unity version \"$UNITY_VERSION\"."
if [[ -n "$UNITY_LICENSE" ]]; then
#
# PERSONAL LICENSE MODE
#
# This will activate Unity, using a license file
#
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
#
# The license file can be acquired using `webbertakken/request-manual-activation-file` action.
echo "Requesting activation (personal license)"
# Set the license file path
FILE_PATH=UnityLicenseFile.ulf
# Copy license file from Github variables
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
# Activate license
ACTIVATION_OUTPUT=$(xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit \
-manualLicenseFile $FILE_PATH)
# Store the exit code from the verify command
UNITY_EXIT_CODE=$?
# The exit code for personal activation is always 1;
# Determine whether activation was successful.
#
# Successful output should include the following:
#
# "LICENSE SYSTEM [2020120 18:51:20] Next license update check is after 2019-11-25T18:23:38"
#
ACTIVATION_SUCCESSFUL=$(echo $ACTIVATION_OUTPUT | grep 'Next license update check is after' | wc -l)
# Set exit code to 0 if activation was successful
if [[ $ACTIVATION_SUCCESSFUL -eq 1 ]]; then
UNITY_EXIT_CODE=0
fi;
# Remove license file
rm -f $FILE_PATH
elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
#
# PROFESSIONAL (SERIAL) LICENSE MODE
#
# This will activate unity, using the activating process.
#
# Note: This is the preferred way for PROFESSIONAL LICENSES.
#
echo "Requesting activation (professional license)"
# Activate license
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit \
-serial "$UNITY_SERIAL" \
-username "$UNITY_EMAIL" \
-password "$UNITY_PASSWORD"
# Store the exit code from the verify command
UNITY_EXIT_CODE=$?
else
#
# NO LICENSE ACTIVATION STRATEGY MATCHED
#
# This will exit since no activation strategies could be matched.
#
echo "License activation strategy could not be determined."
echo ""
echo "Visit https://github.com/webbertakken/unity-builder#usage for more"
echo "details on how to set up one of the possible activation strategies."
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
exit 1;
fi
#
# Display information about the result
#
if [ $UNITY_EXIT_CODE -eq 0 ]; then
# Activation was a success
echo "Activation complete."
else
# Activation failed so exit with the code from the license verification step
echo "Unclassified error occured while trying to activate license."
echo "Exit code was: $UNITY_EXIT_CODE"
exit $UNITY_EXIT_CODE
fi

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,
},
},
],
],
};

View File

@@ -1,90 +0,0 @@
#!/usr/bin/env bash
if [[ -n "$UNITY_LICENSE" ]]; then
#
# PERSONAL LICENSE MODE
#
# This will activate Unity, using a license file
#
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2019.
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
#
# The license file can be acquired in two possible ways:
# * Utilize `webbertakken/unity-actions/request-manual-activation-file`
# * Copy from your local machine (may be unstable due to different server specs)
# - Windows: C:/ProgramData/Unity/Unity_lic.ulf
# - MacOS: /Library/Application Support/Unity/Unity_lic.ulf
# - Linux: -
#
# CLI arguments reference: https://docs.unity3d.com/Manual/CommandLineArguments.html
# Set the license file path
FILE_PATH=UnityLicenseFile.ulf
# Copy license file from Github variables
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
echo "$UNITY_LICENSE" | tr -d '\r' > /root/.local/share/unity3d/Unity/Unity_lic.ulf
##
## Activate license
##
echo "Requesting activation"
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit \
-manualLicenseFile $FILE_PATH
# This is expected to always exit with code 1 (both success and failure).
# Convert to exit code 0 by echoing the current exit code.
echo $?
# Exit code is now 0
##
## Verify activated license
##
echo "Verifying activation"
# Run any command that requires activation to verify
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit
# Store the exit code from the verify command
UNITY_EXIT_CODE=$?
# Display information about the result
if [ $UNITY_EXIT_CODE -eq 0 ]; then
echo "Activation complete"
else
echo "Unclassified error occured while trying to activate license"
echo "Exit code was: $UNITY_EXIT_CODE"
fi
# Exit with the code from the license verification step
exit $UNITY_EXIT_CODE
else
#
# PROFESSIONAL (SERIAL) LICENSE MODE
#
# This will activate unity, using the activating process.
#
# Note: This is the preferred way for PROFESSIONAL LICENSES.
#
# TODO - Verify this using some pro license
#
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit \
-serial "$UNITY_SERIAL" \
-username "$UNITY_EMAIL" \
-password "$UNITY_PASSWORD"
fi

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