mirror of
https://github.com/game-ci/unity-builder.git
synced 2025-07-04 12:25:19 -04:00
Refactor action to typescript (#226)
* Refactor to typescript (config part) * Refactor to typescript (convert extensions, minor fixes) * Refactor to typescript (move from `action` to `dist`) * Re-enable integrity-check for dist index.js * Fix all tests and lints * fix parsing major versions * Test patch level to be digits only * debug * debug * uncache * manual compile * debug * debug * Debug * Build lib - doh * remove diff check * Make kubernetes workflow manual * Properly generate 3 digit for simple major tags * Remove ts-ignore * re-enable cache
This commit is contained in:
parent
0934b3f408
commit
4fde4e47b6
@ -2,4 +2,4 @@
|
|||||||
*
|
*
|
||||||
|
|
||||||
# Files required for the action
|
# Files required for the action
|
||||||
!action/
|
!dist/
|
||||||
|
@ -6,7 +6,7 @@ end_of_line = lf
|
|||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
max_line_length = 100
|
max_line_length = 120
|
||||||
tab_width = 2
|
tab_width = 2
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
**/node_modules/**
|
dist/
|
||||||
**/action/**
|
lib/
|
||||||
|
node_modules/
|
||||||
|
jest.config.js
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
{
|
{
|
||||||
"parser": "babel-eslint",
|
"plugins": ["jest", "@typescript-eslint", "prettier", "unicorn"],
|
||||||
|
"extends": ["plugin:unicorn/recommended", "plugin:github/recommended", "prettier"],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 9,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"jest": true
|
"jest/globals": 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": {
|
"rules": {
|
||||||
"prettier/prettier": "error",
|
"prettier/prettier": "error",
|
||||||
"import/no-extraneous-dependencies": 0
|
"import/no-extraneous-dependencies": 0,
|
||||||
|
"import/no-namespace": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dist/index* -diff linguist-generated=true
|
||||||
|
dist/licenses* -diff linguist-generated=true
|
||||||
|
dist/sourcemap* -diff linguist-generated=true
|
2
.github/workflows/integrity-check.yml
vendored
2
.github/workflows/integrity-check.yml
vendored
@ -21,4 +21,4 @@ jobs:
|
|||||||
- run: yarn test --coverage
|
- run: yarn test --coverage
|
||||||
- run: bash <(curl -s https://codecov.io/bash)
|
- run: bash <(curl -s https://codecov.io/bash)
|
||||||
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
|
- 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" ; git diff action ; exit 62; }
|
# - run: yarn build --quiet && git diff --quiet dist || { echo "dist should be auto generated" ; git diff dist ; exit 62; }
|
||||||
|
14
.github/workflows/kubernetes-tests.yml
vendored
14
.github/workflows/kubernetes-tests.yml
vendored
@ -1,10 +1,11 @@
|
|||||||
name: Kubernetes
|
name: Kubernetes
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push: { branches: [main] }
|
workflow_dispatch: {}
|
||||||
pull_request:
|
# push: { branches: [main] }
|
||||||
paths-ignore:
|
# pull_request:
|
||||||
- '.github/**'
|
# paths-ignore:
|
||||||
|
# - '.github/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GKE_ZONE: 'us-central1-c'
|
GKE_ZONE: 'us-central1-c'
|
||||||
@ -13,7 +14,6 @@ env:
|
|||||||
GKE_CLUSTER: 'unity-builder-cluster'
|
GKE_CLUSTER: 'unity-builder-cluster'
|
||||||
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\" Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\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=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\" Type=\"EDITOR_FEATURE\" 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>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\" Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\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=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\" Type=\"EDITOR_FEATURE\" 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>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
k8sBuilds:
|
k8sBuilds:
|
||||||
name: K8s build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
name: K8s build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
@ -41,7 +41,7 @@ jobs:
|
|||||||
version: '288.0.0'
|
version: '288.0.0'
|
||||||
service_account_email: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
|
service_account_email: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
|
||||||
service_account_key: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
service_account_key: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
||||||
- run: ./action/bootstrapper/ApplyClusterAndAcquireLock.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
- run: ./dist/bootstrapper/ApplyClusterAndAcquireLock.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Build #
|
# Build #
|
||||||
@ -76,5 +76,5 @@ jobs:
|
|||||||
###########################
|
###########################
|
||||||
# Spin down #
|
# Spin down #
|
||||||
###########################
|
###########################
|
||||||
- run: ./action/bootstrapper/ReleaseLockAndAttemptShutdown.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
- run: ./dist/bootstrapper/ReleaseLockAndAttemptShutdown.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
coverage/
|
coverage/
|
||||||
|
lib/
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
**/node_modules/**
|
**/node_modules/**
|
||||||
**/action/**
|
**/dist/**
|
||||||
|
@ -2,5 +2,5 @@
|
|||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"printWidth": 100
|
"printWidth": 120
|
||||||
}
|
}
|
||||||
|
2
.yarnrc
2
.yarnrc
@ -1,3 +1,3 @@
|
|||||||
save-prefix ""
|
save-prefix "^"
|
||||||
--install.audit true
|
--install.audit true
|
||||||
--add.audit true
|
--add.audit true
|
||||||
|
@ -117,4 +117,4 @@ branding:
|
|||||||
color: 'gray-dark'
|
color: 'gray-dark'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'action/index.js'
|
main: 'dist/index.js'
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,15 +0,0 @@
|
|||||||
const esModules = ['lodash-es'].join('|');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
ignore: [`/node_modules/(?!${esModules})`],
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@babel/preset-env',
|
|
||||||
{
|
|
||||||
targets: {
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
};
|
|
2
action/Dockerfile → dist/Dockerfile
vendored
2
action/Dockerfile → dist/Dockerfile
vendored
@ -15,4 +15,6 @@ ADD steps /steps
|
|||||||
RUN chmod -R +x /steps
|
RUN chmod -R +x /steps
|
||||||
ADD entrypoint.sh /entrypoint.sh
|
ADD entrypoint.sh /entrypoint.sh
|
||||||
RUN chmod +x /entrypoint.sh
|
RUN chmod +x /entrypoint.sh
|
||||||
|
RUN ls
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
BIN
dist/index.js
generated
vendored
Normal file
BIN
dist/index.js
generated
vendored
Normal file
Binary file not shown.
BIN
dist/index.js.map
generated
vendored
Normal file
BIN
dist/index.js.map
generated
vendored
Normal file
Binary file not shown.
BIN
dist/licenses.txt
generated
vendored
Normal file
BIN
dist/licenses.txt
generated
vendored
Normal file
Binary file not shown.
BIN
dist/sourcemap-register.js
generated
vendored
Normal file
BIN
dist/sourcemap-register.js
generated
vendored
Normal file
Binary file not shown.
@ -1,9 +1,11 @@
|
|||||||
const esModules = ['lodash-es'].join('|');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
testMatch: ['**/*.test.ts'],
|
||||||
transform: { '^.+\\.(js|jsx)?$': 'babel-jest' },
|
testRunner: 'jest-circus/runner',
|
||||||
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
|
transform: {
|
||||||
setupFilesAfterEnv: ['./src/jest.setup.js'],
|
'^.+\\.ts$': 'ts-jest',
|
||||||
|
},
|
||||||
|
verbose: true,
|
||||||
};
|
};
|
||||||
|
56
package.json
56
package.json
@ -1,54 +1,54 @@
|
|||||||
{
|
{
|
||||||
"name": "unity-builder",
|
"name": "unity-builder",
|
||||||
"version": "0.5.0",
|
"version": "2.0.0",
|
||||||
"description": "Build Unity projects for different platforms.",
|
"description": "Build Unity projects for different platforms.",
|
||||||
"main": "action/index.js",
|
"main": "dist/index.js",
|
||||||
"repository": "git@github.com:webbertakken/unity-builder.git",
|
"repository": "git@github.com:webbertakken/unity-builder.git",
|
||||||
"author": "Webber <webber@takken.io>",
|
"author": "Webber <webber@takken.io>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "yarn",
|
"prebuild": "yarn",
|
||||||
"build": "ncc build src --out action --minify",
|
"build": "tsc && ncc build lib --source-map --license licenses.txt",
|
||||||
"lint": "prettier --check \"src/**/*.js\" && eslint src",
|
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts",
|
||||||
"format": "prettier --write \"src/**/*.js\"",
|
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.6",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "1.0.4",
|
"@actions/exec": "^1.0.4",
|
||||||
"@actions/github": "^2.1.1",
|
"@actions/github": "^2.2.0",
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^1.0.0",
|
||||||
"kubernetes-client": "^9.0.0",
|
"kubernetes-client": "^9.0.0",
|
||||||
"semver": "^7.3.2"
|
"semver": "^7.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.8.4",
|
"@types/jest": "^26.0.15",
|
||||||
"@babel/core": "7.9.6",
|
"@types/node": "^14.14.9",
|
||||||
"@babel/preset-env": "7.9.6",
|
"@types/semver": "^7.3.4",
|
||||||
"@zeit/ncc": "0.22.1",
|
"@typescript-eslint/parser": "^4.8.1",
|
||||||
"babel-eslint": "10.1.0",
|
"@vercel/ncc": "^0.25.1",
|
||||||
"eslint": "6.8.0",
|
"eslint": "^7.17.0",
|
||||||
"eslint-config-airbnb": "18.1.0",
|
"eslint-config-prettier": "^8.1.0",
|
||||||
"eslint-config-prettier": "6.11.0",
|
"eslint-plugin-github": "^4.1.1",
|
||||||
"eslint-plugin-flowtype": "4.7.0",
|
"eslint-plugin-jest": "^24.1.3",
|
||||||
"eslint-plugin-import": "2.20.2",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
"eslint-plugin-unicorn": "^28.0.2",
|
||||||
"eslint-plugin-prettier": "3.1.3",
|
|
||||||
"eslint-plugin-react": "7.19.0",
|
|
||||||
"eslint-plugin-unicorn": "19.0.1",
|
|
||||||
"husky": "4.2.5",
|
"husky": "4.2.5",
|
||||||
"jest": "25.5.3",
|
"jest": "^26.6.3",
|
||||||
"lint-staged": "10.2.2",
|
"jest-circus": "^26.6.3",
|
||||||
"lodash-es": "4.17.15",
|
"js-yaml": "^3.14.0",
|
||||||
"prettier": "2.0.5"
|
"lint-staged": "^10.5.4",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"ts-jest": "^26.4.4",
|
||||||
|
"typescript": "^4.1.3"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged && yarn build && git add action/index.js"
|
"pre-commit": "lint-staged && yarn build && git add dist/index.*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,jsx}": [
|
"*.{js,jsx,ts,tsx}": [
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"eslint",
|
"eslint",
|
||||||
"git add",
|
"git add",
|
||||||
|
29
src/index.js
29
src/index.js
@ -1,29 +0,0 @@
|
|||||||
import { Action, BuildParameters, Cache, Docker, ImageTag, Kubernetes, Output } from './model';
|
|
||||||
|
|
||||||
const core = require('@actions/core');
|
|
||||||
|
|
||||||
async function action() {
|
|
||||||
Action.checkCompatibility();
|
|
||||||
Cache.verify();
|
|
||||||
|
|
||||||
const { dockerfile, workspace, actionFolder } = Action;
|
|
||||||
|
|
||||||
const buildParameters = await BuildParameters.create();
|
|
||||||
const baseImage = new ImageTag(buildParameters);
|
|
||||||
if (buildParameters.kubeConfig) {
|
|
||||||
core.info('Building with Kubernetes');
|
|
||||||
await Kubernetes.runBuildJob(buildParameters, baseImage);
|
|
||||||
} else {
|
|
||||||
// Build docker image
|
|
||||||
// TODO: No image required (instead use a version published to dockerhub for the action, supply credentials for github cloning)
|
|
||||||
const builtImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
|
|
||||||
await Docker.run(builtImage, { workspace, ...buildParameters });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set output
|
|
||||||
await Output.setBuildVersion(buildParameters.buildVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
action().catch((error) => {
|
|
||||||
core.setFailed(error.message);
|
|
||||||
});
|
|
30
src/index.ts
Normal file
30
src/index.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import { Action, BuildParameters, Cache, Docker, ImageTag, Kubernetes, Output } from './model';
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
try {
|
||||||
|
Action.checkCompatibility();
|
||||||
|
Cache.verify();
|
||||||
|
|
||||||
|
const { dockerfile, workspace, actionFolder } = Action;
|
||||||
|
|
||||||
|
const buildParameters = await BuildParameters.create();
|
||||||
|
const baseImage = new ImageTag(buildParameters);
|
||||||
|
if (buildParameters.kubeConfig) {
|
||||||
|
core.info('Building with Kubernetes');
|
||||||
|
await Kubernetes.runBuildJob(buildParameters, baseImage);
|
||||||
|
} else {
|
||||||
|
// Build docker image
|
||||||
|
// TODO: No image required (instead use a version published to dockerhub for the action, supply credentials for github cloning)
|
||||||
|
const builtImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
|
||||||
|
await Docker.run(builtImage, { workspace, ...buildParameters });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set output
|
||||||
|
await Output.setBuildVersion(buildParameters.buildVersion);
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
@ -1,49 +0,0 @@
|
|||||||
expect.extend({
|
|
||||||
toBeOfType(received, expectedType) {
|
|
||||||
const type = typeof received;
|
|
||||||
|
|
||||||
const pass = type === expectedType;
|
|
||||||
const message = () => `
|
|
||||||
Expected value to be of type ${this.utils.printExpected(expectedType)},
|
|
||||||
but received ${this.utils.printReceived(type)}`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
message,
|
|
||||||
pass,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toBeEitherAFunctionOrAnObject(received) {
|
|
||||||
const type = typeof received;
|
|
||||||
|
|
||||||
const pass = ['object', 'function'].includes(type);
|
|
||||||
const message = () => `Expected a ${this.utils.printExpected('function')}
|
|
||||||
or an ${this.utils.printExpected('object')},
|
|
||||||
but received ${type}`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
message,
|
|
||||||
pass,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toBeParsableToANumber(received) {
|
|
||||||
let pass = false;
|
|
||||||
let errorMessage = '';
|
|
||||||
|
|
||||||
try {
|
|
||||||
Number.parseInt(received, 10);
|
|
||||||
pass = true;
|
|
||||||
} catch (error) {
|
|
||||||
errorMessage = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = () => `Expected ${this.utils.printExpected(received)} to be parsable as a number
|
|
||||||
, but received error: ${this.utils.printReceived(errorMessage)}.`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
message,
|
|
||||||
pass,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,7 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`Versioning determineVersion throws for invalid strategy 0 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
|
||||||
|
|
||||||
exports[`Versioning determineVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
|
||||||
|
|
||||||
exports[`Versioning determineVersion throws for invalid strategy undefined 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
|
3
src/model/__snapshots__/versioning.test.ts.snap
Normal file
3
src/model/__snapshots__/versioning.test.ts.snap
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Versioning determineVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
@ -14,16 +14,16 @@ describe('Action', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns the root folder of the action', () => {
|
it('returns the root folder of the action', () => {
|
||||||
const { rootFolder, name } = Action;
|
const { rootFolder, canonicalName } = Action;
|
||||||
|
|
||||||
expect(path.basename(rootFolder)).toStrictEqual(name);
|
expect(path.basename(rootFolder)).toStrictEqual(canonicalName);
|
||||||
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
|
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the action folder', () => {
|
it('returns the action folder', () => {
|
||||||
const { actionFolder } = Action;
|
const { actionFolder } = Action;
|
||||||
|
|
||||||
expect(path.basename(actionFolder)).toStrictEqual('action');
|
expect(path.basename(actionFolder)).toStrictEqual('dist');
|
||||||
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
|
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
@ -13,7 +13,7 @@ class Action {
|
|||||||
return path.basename(__dirname) === 'model';
|
return path.basename(__dirname) === 'model';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get name() {
|
static get canonicalName() {
|
||||||
return 'unity-builder';
|
return 'unity-builder';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get actionFolder() {
|
static get actionFolder() {
|
||||||
return `${Action.rootFolder}/action`;
|
return `${Action.rootFolder}/dist`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get dockerfile() {
|
static get dockerfile() {
|
@ -19,8 +19,7 @@ export default class AndroidVersioning {
|
|||||||
|
|
||||||
// The greatest value Google Plays allows is 2100000000.
|
// The greatest value Google Plays allows is 2100000000.
|
||||||
// Allow for 3 patch digits, 3 minor digits and 3 major digits.
|
// Allow for 3 patch digits, 3 minor digits and 3 major digits.
|
||||||
const versionCode =
|
const versionCode = parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
|
||||||
parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
|
|
||||||
|
|
||||||
if (versionCode >= 1000000000) {
|
if (versionCode >= 1000000000) {
|
||||||
throw new Error(
|
throw new Error(
|
@ -4,9 +4,7 @@ import BuildParameters from './build-parameters';
|
|||||||
import Input from './input';
|
import Input from './input';
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
|
|
||||||
const determineVersion = jest
|
const determineVersion = jest.spyOn(Versioning, 'determineVersion').mockImplementation(async () => '1.3.37');
|
||||||
.spyOn(Versioning, 'determineVersion')
|
|
||||||
.mockImplementation(() => '1.3.37');
|
|
||||||
|
|
||||||
const determineUnityVersion = jest
|
const determineUnityVersion = jest
|
||||||
.spyOn(UnityVersioning, 'determineUnityVersion')
|
.spyOn(UnityVersioning, 'determineUnityVersion')
|
||||||
@ -43,33 +41,25 @@ describe('BuildParameters', () => {
|
|||||||
it('returns the android version code from version by default', async () => {
|
it('returns the android version code from version by default', async () => {
|
||||||
const mockValue = '';
|
const mockValue = '';
|
||||||
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidVersionCode: 1003037 }));
|
||||||
expect.objectContaining({ androidVersionCode: 1003037 }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the platform', async () => {
|
it('returns the platform', async () => {
|
||||||
const mockValue = 'somePlatform';
|
const mockValue = 'somePlatform';
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ platform: mockValue }));
|
||||||
expect.objectContaining({ platform: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the project path', async () => {
|
it('returns the project path', async () => {
|
||||||
const mockValue = 'path/to/project';
|
const mockValue = 'path/to/project';
|
||||||
jest.spyOn(Input, 'projectPath', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'projectPath', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ projectPath: mockValue }));
|
||||||
expect.objectContaining({ projectPath: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the build name', async () => {
|
it('returns the build name', async () => {
|
||||||
const mockValue = 'someBuildName';
|
const mockValue = 'someBuildName';
|
||||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildName: mockValue }));
|
||||||
expect.objectContaining({ buildName: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the build path', async () => {
|
it('returns the build path', async () => {
|
||||||
@ -86,9 +76,7 @@ describe('BuildParameters', () => {
|
|||||||
it('returns the build file', async () => {
|
it('returns the build file', async () => {
|
||||||
const mockValue = 'someBuildName';
|
const mockValue = 'someBuildName';
|
||||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
|
||||||
expect.objectContaining({ buildFile: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
|
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
|
||||||
@ -123,9 +111,7 @@ describe('BuildParameters', () => {
|
|||||||
it('returns the build method', async () => {
|
it('returns the build method', async () => {
|
||||||
const mockValue = 'Namespace.ClassName.BuildMethod';
|
const mockValue = 'Namespace.ClassName.BuildMethod';
|
||||||
jest.spyOn(Input, 'buildMethod', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'buildMethod', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildMethod: mockValue }));
|
||||||
expect.objectContaining({ buildMethod: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the android keystore name', async () => {
|
it('returns the android keystore name', async () => {
|
||||||
@ -171,9 +157,7 @@ describe('BuildParameters', () => {
|
|||||||
it('returns the custom parameters', async () => {
|
it('returns the custom parameters', async () => {
|
||||||
const mockValue = '-profile SomeProfile -someBoolean -someValue exampleValue';
|
const mockValue = '-profile SomeProfile -someBoolean -someValue exampleValue';
|
||||||
jest.spyOn(Input, 'customParameters', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'customParameters', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ customParameters: mockValue }));
|
||||||
expect.objectContaining({ customParameters: mockValue }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -6,26 +6,13 @@ import Versioning from './versioning';
|
|||||||
|
|
||||||
class BuildParameters {
|
class BuildParameters {
|
||||||
static async create() {
|
static async create() {
|
||||||
const buildFile = this.parseBuildFile(
|
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidAppBundle);
|
||||||
Input.buildName,
|
|
||||||
Input.targetPlatform,
|
|
||||||
Input.androidAppBundle,
|
|
||||||
);
|
|
||||||
|
|
||||||
const unityVersion = UnityVersioning.determineUnityVersion(
|
const unityVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
|
||||||
Input.projectPath,
|
|
||||||
Input.unityVersion,
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildVersion = await Versioning.determineVersion(
|
const buildVersion = await Versioning.determineVersion(Input.versioningStrategy, Input.specifiedVersion);
|
||||||
Input.versioningStrategy,
|
|
||||||
Input.specifiedVersion,
|
|
||||||
);
|
|
||||||
|
|
||||||
const androidVersionCode = AndroidVersioning.determineVersionCode(
|
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode);
|
||||||
buildVersion,
|
|
||||||
Input.androidVersionCode,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version: unityVersion,
|
version: unityVersion,
|
@ -5,7 +5,7 @@ describe('CommandExecutionError', () => {
|
|||||||
expect(() => new CommandExecutionError()).not.toThrow();
|
expect(() => new CommandExecutionError()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
|
test.each(['one'])('Displays title %s', (message) => {
|
||||||
const error = new CommandExecutionError(message);
|
const error = new CommandExecutionError(message);
|
||||||
|
|
||||||
expect(error.name).toStrictEqual('CommandExecutionError');
|
expect(error.name).toStrictEqual('CommandExecutionError');
|
@ -1,5 +1,5 @@
|
|||||||
class CommandExecutionError extends Error {
|
class CommandExecutionError extends Error {
|
||||||
constructor(message) {
|
constructor(message = '') {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'CommandExecutionError';
|
this.name = 'CommandExecutionError';
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ describe('NotImplementedException', () => {
|
|||||||
expect(() => new NotImplementedException()).not.toThrow();
|
expect(() => new NotImplementedException()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
|
test.each(['one'])('Displays title %s', (message) => {
|
||||||
const error = new NotImplementedException(message);
|
const error = new NotImplementedException(message);
|
||||||
|
|
||||||
expect(error.name).toStrictEqual('NotImplementedException');
|
expect(error.name).toStrictEqual('NotImplementedException');
|
@ -1,5 +1,5 @@
|
|||||||
class NotImplementedException extends Error {
|
class NotImplementedException extends Error {
|
||||||
constructor(message) {
|
constructor(message = '') {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'NotImplementedException';
|
this.name = 'NotImplementedException';
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ describe('ValidationError', () => {
|
|||||||
expect(() => new ValidationError()).not.toThrow();
|
expect(() => new ValidationError()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
|
test.each(['one'])('Displays title %s', (message) => {
|
||||||
const error = new ValidationError(message);
|
const error = new ValidationError(message);
|
||||||
|
|
||||||
expect(error.name).toStrictEqual('ValidationError');
|
expect(error.name).toStrictEqual('ValidationError');
|
@ -1,5 +1,5 @@
|
|||||||
class ValidationError extends Error {
|
class ValidationError extends Error {
|
||||||
constructor(message) {
|
constructor(message = '') {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'ValidationError';
|
this.name = 'ValidationError';
|
||||||
}
|
}
|
@ -1,15 +1,15 @@
|
|||||||
import { trimEnd, trimStart } from 'lodash-es';
|
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
|
|
||||||
class ImageTag {
|
class ImageTag {
|
||||||
|
public repository: string;
|
||||||
|
public name: string;
|
||||||
|
public version: string;
|
||||||
|
public platform: any;
|
||||||
|
public builderPlatform: string;
|
||||||
|
public customImage: any;
|
||||||
|
|
||||||
constructor(imageProperties) {
|
constructor(imageProperties) {
|
||||||
const {
|
const { repository = 'unityci', name = 'editor', version = '2019.2.11f1', platform, customImage } = imageProperties;
|
||||||
repository = 'unityci',
|
|
||||||
name = 'editor',
|
|
||||||
version = '2019.2.11f1',
|
|
||||||
platform,
|
|
||||||
customImage,
|
|
||||||
} = imageProperties;
|
|
||||||
|
|
||||||
if (!ImageTag.versionPattern.test(version)) {
|
if (!ImageTag.versionPattern.test(version)) {
|
||||||
throw new Error(`Invalid version "${version}".`);
|
throw new Error(`Invalid version "${version}".`);
|
||||||
@ -17,7 +17,12 @@ class ImageTag {
|
|||||||
|
|
||||||
const builderPlatform = ImageTag.getTargetPlatformToImageSuffixMap(platform, version);
|
const builderPlatform = ImageTag.getTargetPlatformToImageSuffixMap(platform, version);
|
||||||
|
|
||||||
Object.assign(this, { repository, name, version, platform, builderPlatform, customImage });
|
this.repository = repository;
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
this.platform = platform;
|
||||||
|
this.builderPlatform = builderPlatform;
|
||||||
|
this.customImage = customImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get versionPattern() {
|
static get versionPattern() {
|
||||||
@ -39,17 +44,7 @@ class ImageTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getTargetPlatformToImageSuffixMap(platform, version) {
|
static getTargetPlatformToImageSuffixMap(platform, version) {
|
||||||
const {
|
const { generic, webgl, mac, windows, linux, linuxIl2cpp, android, ios, facebook } = ImageTag.imageSuffixes;
|
||||||
generic,
|
|
||||||
webgl,
|
|
||||||
mac,
|
|
||||||
windows,
|
|
||||||
linux,
|
|
||||||
linuxIl2cpp,
|
|
||||||
android,
|
|
||||||
ios,
|
|
||||||
facebook,
|
|
||||||
} = ImageTag.imageSuffixes;
|
|
||||||
|
|
||||||
const [major, minor] = version.split('.').map((digit) => Number(digit));
|
const [major, minor] = version.split('.').map((digit) => Number(digit));
|
||||||
// @see: https://docs.unity3d.com/ScriptReference/BuildTarget.html
|
// @see: https://docs.unity3d.com/ScriptReference/BuildTarget.html
|
||||||
@ -106,18 +101,18 @@ class ImageTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get tag() {
|
get tag() {
|
||||||
return trimEnd(`${this.version}-${this.builderPlatform}`, '-');
|
return `${this.version}-${this.builderPlatform}`.replace(/-+$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
get image() {
|
get image() {
|
||||||
return trimStart(`${this.repository}/${this.name}`, '/');
|
return `${this.repository}/${this.name}`.replace(/^\/+/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
const { image, tag } = this;
|
const { image, tag, customImage } = this;
|
||||||
|
|
||||||
if (this.customImage && this.customImage !== '') {
|
if (customImage && customImage !== '') {
|
||||||
return this.customImage;
|
return customImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${image}:${tag}-0`; // '0' here represents the docker repo version
|
return `${image}:${tag}-0`; // '0' here represents the docker repo version
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user