mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-06-01 06:16:14 -07:00
Compare commits
64 Commits
v3
...
linux-exte
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a38ec6caef | ||
|
|
2240bedf08 | ||
|
|
37ce35f1a5 | ||
|
|
9d20e0b607 | ||
|
|
16c5c20793 | ||
|
|
821ba97789 | ||
|
|
365bdb5e12 | ||
|
|
c7a43cde4d | ||
|
|
d10fd10a95 | ||
|
|
2321712bb4 | ||
|
|
ef0555fb0d | ||
|
|
4a7fc08e63 | ||
|
|
ce7ce7a416 | ||
|
|
9d475434d3 | ||
|
|
f3849ee1c9 | ||
|
|
0c82a58873 | ||
|
|
1d4ee0697f | ||
|
|
3a2abf9037 | ||
|
|
cfdebb67c1 | ||
|
|
ab64768ceb | ||
|
|
00fa0d3772 | ||
|
|
d587557287 | ||
|
|
6e0bf17345 | ||
|
|
2822af505e | ||
|
|
8ec161b981 | ||
|
|
88a89c94a0 | ||
|
|
f7f3f70c57 | ||
|
|
c6c8236152 | ||
|
|
9e91ca9749 | ||
|
|
9cd9f7e0e7 | ||
|
|
0b822c28fb | ||
|
|
65607f9ebb | ||
|
|
a1ebdb7abd | ||
|
|
3b26780ddf | ||
|
|
819c2511e0 | ||
|
|
81ed299e10 | ||
|
|
9d6bdcbdc5 | ||
|
|
3ae9ec8536 | ||
|
|
83c85328dd | ||
|
|
b11b6a6f2c | ||
|
|
461ecf7cea | ||
|
|
f2250e958e | ||
|
|
dd427466ce | ||
|
|
0c16aab353 | ||
|
|
fc0a52b805 | ||
|
|
e820c9ce7b | ||
|
|
f4d2cceeb5 | ||
|
|
4ae184ca89 | ||
|
|
082ea39498 | ||
|
|
e73b48fb38 | ||
|
|
2800d14403 | ||
|
|
5ba81971e2 | ||
|
|
ff23166e30 | ||
|
|
9406bce875 | ||
|
|
bbd713b05a | ||
|
|
96cfb845ae | ||
|
|
8ca1282c9e | ||
|
|
8da77ace98 | ||
|
|
2afd9cd86f | ||
|
|
caa0a81b47 | ||
|
|
7afabe74da | ||
|
|
4c4611c021 | ||
|
|
6419c8742b | ||
|
|
a13443a746 |
@@ -1,4 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
jest.config.js
|
|
||||||
100
.eslintrc.json
100
.eslintrc.json
@@ -1,100 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"jest",
|
|
||||||
"@typescript-eslint",
|
|
||||||
"prettier",
|
|
||||||
"unicorn"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:unicorn/recommended",
|
|
||||||
"plugin:github/recommended",
|
|
||||||
"plugin:prettier/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2020,
|
|
||||||
"sourceType": "module",
|
|
||||||
"extraFileExtensions": [
|
|
||||||
".mjs"
|
|
||||||
],
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"impliedStrict": true
|
|
||||||
},
|
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"node": true,
|
|
||||||
"es6": true,
|
|
||||||
"jest/globals": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
// Error out for code formatting errors
|
|
||||||
"prettier/prettier": "error",
|
|
||||||
// Namespaces or sometimes needed
|
|
||||||
"import/no-namespace": "off",
|
|
||||||
// Properly format comments
|
|
||||||
"spaced-comment": [
|
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"lines-around-comment": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"beforeBlockComment": true,
|
|
||||||
"beforeLineComment": true,
|
|
||||||
"allowBlockStart": true,
|
|
||||||
"allowObjectStart": true,
|
|
||||||
"allowArrayStart": true,
|
|
||||||
"allowClassStart": true,
|
|
||||||
"ignorePattern": "pragma|ts-ignore"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// Mandatory spacing
|
|
||||||
"padding-line-between-statements": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"blankLine": "always",
|
|
||||||
"prev": "*",
|
|
||||||
"next": "return"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blankLine": "always",
|
|
||||||
"prev": "directive",
|
|
||||||
"next": "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blankLine": "any",
|
|
||||||
"prev": "directive",
|
|
||||||
"next": "directive"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// Enforce camelCase
|
|
||||||
"camelcase": "error",
|
|
||||||
// Allow forOfStatements
|
|
||||||
"no-restricted-syntax": [
|
|
||||||
"error",
|
|
||||||
"ForInStatement",
|
|
||||||
"LabeledStatement",
|
|
||||||
"WithStatement"
|
|
||||||
],
|
|
||||||
// Continue is viable in forOf loops in generators
|
|
||||||
"no-continue": "off",
|
|
||||||
// From experience, named exports are almost always desired. I got tired of this rule
|
|
||||||
"import/prefer-default-export": "off",
|
|
||||||
// Unused vars are useful to keep method signatures consistent and documented
|
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
|
||||||
// For this project only use kebab-case
|
|
||||||
"unicorn/filename-case": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"cases": {
|
|
||||||
"kebabCase": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// Allow Array.from(set) mitigate TS2569 which would require '--downlevelIteration'
|
|
||||||
"unicorn/prefer-spread": "off",
|
|
||||||
// Temp disable to prevent mixing changes with other PRs
|
|
||||||
"i18n-text/no-en": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -14,9 +14,7 @@ assignees: ''
|
|||||||
|
|
||||||
<!--Steps to reproduce the behavior:-->
|
<!--Steps to reproduce the behavior:-->
|
||||||
|
|
||||||
-
|
- **Expected behavior**
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
|
|
||||||
<!--A clear and concise description of what you expected to happen.-->
|
<!--A clear and concise description of what you expected to happen.-->
|
||||||
|
|
||||||
|
|||||||
19
.github/pull_request_template.md
vendored
19
.github/pull_request_template.md
vendored
@@ -2,13 +2,28 @@
|
|||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
#### Related Issues
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
|
#### Related PRs
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
|
#### Successful Workflow Run Link
|
||||||
|
|
||||||
|
PRs don't have access to secrets so you will need to provide a link to a successful run of the workflows from your own
|
||||||
|
repo.
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
#### Checklist
|
#### Checklist
|
||||||
|
|
||||||
<!-- please check all items and add your own -->
|
<!-- please check all items and add your own -->
|
||||||
|
|
||||||
- [x] Read the contribution [guide](https://github.com/game-ci/unity-builder/blob/main/CONTRIBUTING.md) and accept the
|
- [x] Read the contribution [guide](https://github.com/game-ci/unity-builder/blob/main/CONTRIBUTING.md) and accept the
|
||||||
[code](https://github.com/game-ci/unity-builder/blob/main/CODE_OF_CONDUCT.md) of conduct
|
[code](https://github.com/game-ci/unity-builder/blob/main/CODE_OF_CONDUCT.md) of conduct
|
||||||
- [ ] Docs (If new inputs or outputs have been added or changes to behavior that should be documented. Please make
|
- [ ] Docs (If new inputs or outputs have been added or changes to behavior that should be documented. Please make a PR
|
||||||
a PR in the [documentation repo](https://github.com/game-ci/documentation))
|
in the [documentation repo](https://github.com/game-ci/documentation))
|
||||||
- [ ] Readme (updated or not needed)
|
- [ ] Readme (updated or not needed)
|
||||||
- [ ] Tests (added, updated or not needed)
|
- [ ] Tests (added, updated or not needed)
|
||||||
|
|||||||
2
.github/workflows/activation.yml
vendored
2
.github/workflows/activation.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
id: requestActivationFile
|
id: requestActivationFile
|
||||||
uses: game-ci/unity-request-activation-file@v2.0-alpha-1
|
uses: game-ci/unity-request-activation-file@v2.0-alpha-1
|
||||||
- name: Upload activation file
|
- name: Upload activation file
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.requestActivationFile.outputs.filePath }}
|
name: ${{ steps.requestActivationFile.outputs.filePath }}
|
||||||
path: ${{ steps.requestActivationFile.outputs.filePath }}
|
path: ${{ steps.requestActivationFile.outputs.filePath }}
|
||||||
|
|||||||
31
.github/workflows/build-tests-mac.yml
vendored
31
.github/workflows/build-tests-mac.yml
vendored
@@ -3,15 +3,13 @@ name: Builds - MacOS
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
buildForAllPlatformsWindows:
|
buildForAllPlatformsMacOS:
|
||||||
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
strategy:
|
strategy:
|
||||||
@@ -20,26 +18,32 @@ jobs:
|
|||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.29f1
|
- 2021.3.45f2
|
||||||
- 2022.1.24f1
|
- 2022.3.62f3
|
||||||
- 2022.2.21f1
|
- 2023.2.22f1
|
||||||
- 2022.3.7f1
|
|
||||||
- 2023.1.8f1
|
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
- StandaloneOSX # Build a MacOS executable
|
- StandaloneOSX # Build a MacOS executable
|
||||||
|
- iOS # Build an iOS executable
|
||||||
|
include:
|
||||||
|
# Additionally test enableGpu build for a standalone windows target
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: StandaloneOSX
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: StandaloneOSX
|
||||||
|
buildProfile: 'Assets/Settings/Build Profiles/Sample macOS Build Profile.asset'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
###########################
|
###########################
|
||||||
# Checkout #
|
# Checkout #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Cache #
|
# Cache #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ matrix.projectPath }}/Library
|
path: ${{ matrix.projectPath }}/Library
|
||||||
key: Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
|
key: Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
|
||||||
@@ -62,10 +66,13 @@ jobs:
|
|||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
with:
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
buildProfile: ${{ matrix.buildProfile }}
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
@@ -73,8 +80,8 @@ jobs:
|
|||||||
###########################
|
###########################
|
||||||
# Upload #
|
# Upload #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Build MacOS (${{ matrix.unityVersion }})
|
name: Build ${{ matrix.targetPlatform }} on MacOS (${{ matrix.unityVersion }})${{ matrix.buildProfile && ' With Build Profile' || '' }}
|
||||||
path: build
|
path: build
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|||||||
147
.github/workflows/build-tests-ubuntu.yml
vendored
147
.github/workflows/build-tests-ubuntu.yml
vendored
@@ -3,19 +3,13 @@ name: Builds - Ubuntu
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
paths-ignore:
|
|
||||||
- '.github/**'
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE:
|
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License
|
||||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License
|
|
||||||
id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\"
|
id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\"
|
||||||
Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\"
|
Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\"
|
||||||
Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID
|
Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID
|
||||||
@@ -41,7 +35,7 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
buildForAllPlatformsUbuntu:
|
buildForAllPlatformsUbuntu:
|
||||||
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
name: "${{ matrix.targetPlatform }} on ${{ matrix.unityVersion}}${{startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }}"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -52,36 +46,73 @@ jobs:
|
|||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.29f1
|
- 2021.3.45f2
|
||||||
- 2022.1.24f1
|
- 2022.3.62f3
|
||||||
- 2022.2.21f1
|
- 2023.2.22f1
|
||||||
- 2022.3.7f1
|
|
||||||
- 2023.1.8f1
|
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit) with mono backend.
|
- StandaloneOSX # Build a macOS standalone (Intel 64-bit) with mono backend.
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone with mono backend.
|
- StandaloneWindows64 # Build a Windows 64-bit standalone with mono backend.
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone with mono backend.
|
- StandaloneLinux64 # Build a Linux 64-bit standalone with mono/il2cpp backend.
|
||||||
- iOS # Build an iOS player.
|
- iOS # Build an iOS project.
|
||||||
- Android # Build an Android .apk.
|
- Android # Build an Android .apk.
|
||||||
- WebGL # WebGL.
|
- WebGL # WebGL.
|
||||||
# - StandaloneWindows # Build a Windows standalone.
|
buildWithIl2cpp:
|
||||||
# - WSAPlayer # Build an Windows Store Apps player.
|
- false
|
||||||
# - PS4 # Build a PS4 Standalone.
|
- true
|
||||||
# - XboxOne # Build a Xbox One Standalone.
|
additionalParameters:
|
||||||
# - tvOS # Build to Apple's tvOS platform.
|
- -param value
|
||||||
# - Switch # Build a Nintendo Switch player
|
- -standaloneBuildSubtarget Server
|
||||||
|
# Skipping configurations that are not supported
|
||||||
|
exclude:
|
||||||
|
# No il2cpp support on Linux Host
|
||||||
|
- targetPlatform: StandaloneOSX
|
||||||
|
buildWithIl2cpp: true
|
||||||
|
- targetPlatform: StandaloneWindows64
|
||||||
|
buildWithIl2cpp: true
|
||||||
|
# Only builds with Il2cpp
|
||||||
|
- targetPlatform: iOS
|
||||||
|
buildWithIl2cpp: false
|
||||||
|
- targetPlatform: Android
|
||||||
|
buildWithIl2cpp: false
|
||||||
|
- targetPlatform: WebGL
|
||||||
|
buildWithIl2cpp: false
|
||||||
|
# No dedicated server support
|
||||||
|
- targetPlatform: WebGL
|
||||||
|
additionalParameters: -standaloneBuildSubtarget Server
|
||||||
|
- targetPlatform: Android
|
||||||
|
additionalParameters: -standaloneBuildSubtarget Server
|
||||||
|
- targetPlatform: iOS
|
||||||
|
additionalParameters: -standaloneBuildSubtarget Server
|
||||||
|
# No dedicated server support on Linux Host
|
||||||
|
- targetPlatform: StandaloneOSX
|
||||||
|
additionalParameters: -standaloneBuildSubtarget Server
|
||||||
|
# No il2cpp dedicated server support on Linux Host
|
||||||
|
- targetPlatform: StandaloneWindows64
|
||||||
|
additionalParameters: -standaloneBuildSubtarget Server
|
||||||
|
buildWithIl2cpp: true
|
||||||
|
include:
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: WebGL
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: WebGL
|
||||||
|
buildProfile: 'Assets/Settings/Build Profiles/Sample WebGL Build Profile.asset'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Clear Space for Android Build
|
||||||
|
if: matrix.targetPlatform == 'Android'
|
||||||
|
uses: jlumbroso/free-disk-space@v1.3.1
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Checkout #
|
# Checkout #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Cache #
|
# Cache #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ matrix.projectPath }}/Library
|
path: ${{ matrix.projectPath }}/Library
|
||||||
key: Library-${{ matrix.projectPath }}-ubuntu-${{ matrix.targetPlatform }}
|
key: Library-${{ matrix.projectPath }}-ubuntu-${{ matrix.targetPlatform }}
|
||||||
@@ -89,22 +120,84 @@ jobs:
|
|||||||
Library-${{ matrix.projectPath }}-ubuntu-
|
Library-${{ matrix.projectPath }}-ubuntu-
|
||||||
Library-
|
Library-
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Set Scripting Backend #
|
||||||
|
###########################
|
||||||
|
- name: Set Scripting Backend To il2cpp
|
||||||
|
if: matrix.buildWithIl2cpp == true
|
||||||
|
run: |
|
||||||
|
mv -f "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" "./test-project/ProjectSettings/ProjectSettings.asset"
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Build #
|
# Build #
|
||||||
###########################
|
###########################
|
||||||
- uses: ./
|
- name: Build
|
||||||
|
uses: ./
|
||||||
|
id: build-1
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
with:
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
|
buildProfile: ${{ matrix.buildProfile }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }}
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
providerStrategy: ${{ matrix.providerStrategy }}
|
||||||
|
allowDirtyBuild: true
|
||||||
|
|
||||||
|
- name: Sleep for Retry
|
||||||
|
if: ${{ steps.build-1.outcome == 'failure' }}
|
||||||
|
run: |
|
||||||
|
sleep 60
|
||||||
|
|
||||||
|
- name: Build (Retry 1)
|
||||||
|
uses: ./
|
||||||
|
id: build-2
|
||||||
|
if: ${{ steps.build-1.outcome == 'failure' }}
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
|
projectPath: ${{ matrix.projectPath }}
|
||||||
|
buildProfile: ${{ matrix.buildProfile }}
|
||||||
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }}
|
||||||
|
providerStrategy: ${{ matrix.providerStrategy }}
|
||||||
|
allowDirtyBuild: true
|
||||||
|
|
||||||
|
- name: Sleep for Retry
|
||||||
|
if: ${{ steps.build-2.outcome == 'failure' }}
|
||||||
|
run: |
|
||||||
|
sleep 240
|
||||||
|
|
||||||
|
- name: Build (Retry 2)
|
||||||
|
uses: ./
|
||||||
|
id: build-3
|
||||||
|
if: ${{ steps.build-2.outcome == 'failure' }}
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
|
projectPath: ${{ matrix.projectPath }}
|
||||||
|
buildProfile: ${{ matrix.buildProfile }}
|
||||||
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue ${{ matrix.additionalParameters }}
|
||||||
|
providerStrategy: ${{ matrix.providerStrategy }}
|
||||||
|
allowDirtyBuild: true
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Upload #
|
# Upload #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Build Ubuntu (${{ matrix.unityVersion }})
|
name: "Build ${{ matrix.targetPlatform }}${{ startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }} on Ubuntu (${{ matrix.unityVersion }}_il2cpp_${{ matrix.buildWithIl2cpp }}_params_${{ matrix.additionalParameters }})"
|
||||||
path: build
|
path: build
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|||||||
75
.github/workflows/build-tests-windows.yml
vendored
75
.github/workflows/build-tests-windows.yml
vendored
@@ -3,8 +3,6 @@ name: Builds - Windows
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
@@ -13,36 +11,47 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
buildForAllPlatformsWindows:
|
buildForAllPlatformsWindows:
|
||||||
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
||||||
runs-on: windows-2019
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.29f1
|
- 2021.3.45f2
|
||||||
- 2022.1.24f1
|
- 2022.3.62f3
|
||||||
- 2022.2.21f1
|
- 2023.2.22f1
|
||||||
- 2022.3.7f1
|
|
||||||
- 2023.1.8f1
|
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
|
- Android # Build an Android apk.
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||||
- StandaloneWindows # Build a Windows 32-bit standalone.
|
|
||||||
- WSAPlayer # Build a UWP App
|
- WSAPlayer # Build a UWP App
|
||||||
- tvOS # Build an Apple TV XCode project
|
- tvOS # Build an Apple TV XCode project
|
||||||
|
enableGpu:
|
||||||
|
- false
|
||||||
|
include:
|
||||||
|
# Additionally test enableGpu build for a standalone windows target
|
||||||
|
- projectPath: test-project
|
||||||
|
unityVersion: 2023.2.2f1
|
||||||
|
targetPlatform: StandaloneWindows64
|
||||||
|
enableGpu: true
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: StandaloneWindows64
|
||||||
|
- unityVersion: 6000.0.36f1
|
||||||
|
targetPlatform: StandaloneWindows64
|
||||||
|
buildProfile: 'Assets/Settings/Build Profiles/Sample Windows Build Profile.asset'
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
###########################
|
###########################
|
||||||
# Checkout #
|
# Checkout #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Cache #
|
# Cache #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ matrix.projectPath }}/Library
|
path: ${{ matrix.projectPath }}/Library
|
||||||
key: Library-${{ matrix.projectPath }}-windows-${{ matrix.targetPlatform }}
|
key: Library-${{ matrix.projectPath }}-windows-${{ matrix.targetPlatform }}
|
||||||
@@ -57,6 +66,34 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
Move-Item -Path "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" -Destination "./test-project/ProjectSettings/ProjectSettings.asset" -Force
|
Move-Item -Path "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" -Destination "./test-project/ProjectSettings/ProjectSettings.asset" -Force
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Docker Readiness #
|
||||||
|
###########################
|
||||||
|
- name: Ensure Docker daemon is ready
|
||||||
|
timeout-minutes: 2
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
$maxRetries = 10
|
||||||
|
$retryDelay = 6
|
||||||
|
for ($i = 0; $i -lt $maxRetries; $i++) {
|
||||||
|
$svc = Get-Service docker -ErrorAction SilentlyContinue
|
||||||
|
if ($svc -and $svc.Status -eq 'Running') {
|
||||||
|
docker version 2>$null
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Host "Docker is ready."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($svc -and $svc.Status -eq 'Stopped') {
|
||||||
|
Write-Host "Docker service stopped, attempting to start..."
|
||||||
|
Start-Service docker -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
Write-Host "Waiting for Docker daemon (attempt $($i+1)/$maxRetries)..."
|
||||||
|
Start-Sleep -Seconds $retryDelay
|
||||||
|
}
|
||||||
|
Write-Error "Docker daemon did not start within $($maxRetries * $retryDelay) seconds"
|
||||||
|
exit 1
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Build #
|
# Build #
|
||||||
###########################
|
###########################
|
||||||
@@ -69,10 +106,14 @@ jobs:
|
|||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
with:
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
buildProfile: ${{ matrix.buildProfile }}
|
||||||
|
enableGpu: ${{ matrix.enableGpu }}
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
@@ -92,10 +133,13 @@ jobs:
|
|||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
with:
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
enableGpu: ${{ matrix.enableGpu }}
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
@@ -114,10 +158,13 @@ jobs:
|
|||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
with:
|
with:
|
||||||
|
buildName: 'GameCI Test Build'
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
enableGpu: ${{ matrix.enableGpu }}
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
@@ -125,8 +172,10 @@ jobs:
|
|||||||
###########################
|
###########################
|
||||||
# Upload #
|
# Upload #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Build Windows (${{ matrix.unityVersion }})
|
name:
|
||||||
|
Build ${{ matrix.targetPlatform }} on Windows (${{ matrix.unityVersion }})${{ matrix.enableGpu && ' With
|
||||||
|
GPU' || '' }}${{ matrix.buildProfile && ' With Build Profile' || '' }}
|
||||||
path: build
|
path: build
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|||||||
37
.github/workflows/cleanup.yml
vendored
37
.github/workflows/cleanup.yml
vendored
@@ -1,37 +0,0 @@
|
|||||||
name: Cleanup (cron)
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '30 10 * * SUN' # every sunday at 10:30
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deleteArtifacts:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Delete old artifacts
|
|
||||||
uses: kolpav/purge-artifacts-action@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
expire-in: 21 days
|
|
||||||
cleanupCloudRunner:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
if: github.event.event_type != 'pull_request_target'
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '18'
|
|
||||||
- run: yarn
|
|
||||||
- run: yarn run cli --help
|
|
||||||
env:
|
|
||||||
AWS_REGION: eu-west-2
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_DEFAULT_REGION: eu-west-2
|
|
||||||
- run: yarn run cli -m list-resources
|
|
||||||
env:
|
|
||||||
AWS_REGION: eu-west-2
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_DEFAULT_REGION: eu-west-2
|
|
||||||
59
.github/workflows/cloud-runner-async-checks.yml
vendored
59
.github/workflows/cloud-runner-async-checks.yml
vendored
@@ -1,59 +0,0 @@
|
|||||||
name: Async Checks API
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
checksObject:
|
|
||||||
description: ''
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
checks: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GKE_ZONE: 'us-central1'
|
|
||||||
GKE_REGION: 'us-central1'
|
|
||||||
GKE_PROJECT: 'unitykubernetesbuilder'
|
|
||||||
GKE_CLUSTER: 'game-ci-github-pipelines'
|
|
||||||
GCP_LOGGING: true
|
|
||||||
GCP_PROJECT: unitykubernetesbuilder
|
|
||||||
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
|
||||||
AWS_REGION: eu-west-2
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_DEFAULT_REGION: eu-west-2
|
|
||||||
AWS_STACK_NAME: game-ci-github-pipelines
|
|
||||||
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
|
||||||
CLOUD_RUNNER_DEBUG: true
|
|
||||||
CLOUD_RUNNER_DEBUG_TREE: true
|
|
||||||
DEBUG: true
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
UNITY_VERSION: 2019.3.15f1
|
|
||||||
USE_IL2CPP: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
asyncChecks:
|
|
||||||
name: Async Checks
|
|
||||||
if: github.event.event_type != 'pull_request_target'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- timeout-minutes: 180
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GIT_PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
|
||||||
cloudRunnerTests: true
|
|
||||||
versioning: None
|
|
||||||
CLOUD_RUNNER_CLUSTER: local-docker
|
|
||||||
AWS_STACK_NAME: game-ci-github-pipelines
|
|
||||||
CHECKS_UPDATE: ${{ github.event.inputs.checksObject }}
|
|
||||||
run: |
|
|
||||||
git clone -b cloud-runner-develop https://github.com/game-ci/unity-builder
|
|
||||||
cd unity-builder
|
|
||||||
yarn
|
|
||||||
ls
|
|
||||||
yarn run cli -m checks-update
|
|
||||||
190
.github/workflows/cloud-runner-ci-pipeline.yml
vendored
190
.github/workflows/cloud-runner-ci-pipeline.yml
vendored
@@ -1,190 +0,0 @@
|
|||||||
name: Cloud Runner CI Pipeline
|
|
||||||
|
|
||||||
on:
|
|
||||||
push: { branches: [cloud-runner-develop, cloud-runner-preview, main] }
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
checks: write
|
|
||||||
contents: read
|
|
||||||
actions: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GKE_ZONE: 'us-central1'
|
|
||||||
GKE_REGION: 'us-central1'
|
|
||||||
GKE_PROJECT: 'unitykubernetesbuilder'
|
|
||||||
GKE_CLUSTER: 'game-ci-github-pipelines'
|
|
||||||
GCP_LOGGING: true
|
|
||||||
GCP_PROJECT: unitykubernetesbuilder
|
|
||||||
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
|
||||||
AWS_REGION: eu-west-2
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
AWS_DEFAULT_REGION: eu-west-2
|
|
||||||
AWS_STACK_NAME: game-ci-team-pipelines
|
|
||||||
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
|
||||||
DEBUG: true
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
UNITY_VERSION: 2019.3.15f1
|
|
||||||
USE_IL2CPP: false
|
|
||||||
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
|
||||||
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
smokeTests:
|
|
||||||
name: Smoke Tests
|
|
||||||
if: github.event.event_type != 'pull_request_target'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test:
|
|
||||||
#- 'cloud-runner-async-workflow'
|
|
||||||
- 'cloud-runner-caching'
|
|
||||||
# - 'cloud-runner-end2end-caching'
|
|
||||||
# - 'cloud-runner-end2end-retaining'
|
|
||||||
- 'cloud-runner-environment'
|
|
||||||
- 'cloud-runner-hooks'
|
|
||||||
- 'cloud-runner-local-persistence'
|
|
||||||
- 'cloud-runner-locking-core'
|
|
||||||
- 'cloud-runner-locking-get-locked'
|
|
||||||
providerStrategy:
|
|
||||||
#- aws
|
|
||||||
- local-docker
|
|
||||||
#- k8s
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- name: Configure AWS Credentials
|
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
|
||||||
with:
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
aws-region: eu-west-2
|
|
||||||
- uses: google-github-actions/auth@v1
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
with:
|
|
||||||
credentials_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
|
||||||
- name: 'Set up Cloud SDK'
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
uses: 'google-github-actions/setup-gcloud@v1.1.0'
|
|
||||||
- name: Get GKE cluster credentials
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
run: |
|
|
||||||
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
|
|
||||||
gcloud components install gke-gcloud-auth-plugin
|
|
||||||
gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
|
|
||||||
- run: yarn
|
|
||||||
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
|
||||||
timeout-minutes: 35
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
|
||||||
cloudRunnerTests: true
|
|
||||||
versioning: None
|
|
||||||
CLOUD_RUNNER_CLUSTER: ${{ matrix.providerStrategy }}
|
|
||||||
tests:
|
|
||||||
# needs:
|
|
||||||
# - smokeTests
|
|
||||||
# - buildTargetTests
|
|
||||||
name: Integration Tests
|
|
||||||
if: github.event.event_type != 'pull_request_target'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
providerStrategy:
|
|
||||||
- aws
|
|
||||||
- local-docker
|
|
||||||
- k8s
|
|
||||||
test:
|
|
||||||
- 'cloud-runner-async-workflow'
|
|
||||||
#- 'cloud-runner-caching'
|
|
||||||
- 'cloud-runner-end2end-locking'
|
|
||||||
- 'cloud-runner-end2end-caching'
|
|
||||||
- 'cloud-runner-end2end-retaining'
|
|
||||||
- 'cloud-runner-environment'
|
|
||||||
#- 'cloud-runner-hooks'
|
|
||||||
- 'cloud-runner-s3-steps'
|
|
||||||
#- 'cloud-runner-local-persistence'
|
|
||||||
#- 'cloud-runner-locking-core'
|
|
||||||
#- 'cloud-runner-locking-get-locked'
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- name: Configure AWS Credentials
|
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
|
||||||
with:
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
aws-region: eu-west-2
|
|
||||||
- uses: google-github-actions/auth@v1
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
with:
|
|
||||||
credentials_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
|
||||||
- name: 'Set up Cloud SDK'
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
uses: 'google-github-actions/setup-gcloud@v1.1.0'
|
|
||||||
- name: Get GKE cluster credentials
|
|
||||||
if: matrix.providerStrategy == 'k8s'
|
|
||||||
run: |
|
|
||||||
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
|
|
||||||
gcloud components install gke-gcloud-auth-plugin
|
|
||||||
gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
|
|
||||||
- run: yarn
|
|
||||||
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
|
||||||
timeout-minutes: 60
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
|
||||||
cloudRunnerTests: true
|
|
||||||
versioning: None
|
|
||||||
PROVIDER_STRATEGY: ${{ matrix.providerStrategy }}
|
|
||||||
buildTargetTests:
|
|
||||||
name: Local Build Target Tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
providerStrategy:
|
|
||||||
#- aws
|
|
||||||
- local-docker
|
|
||||||
#- k8s
|
|
||||||
targetPlatform:
|
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
|
||||||
- WebGL # WebGL.
|
|
||||||
- iOS # Build an iOS player.
|
|
||||||
- Android # Build an Android .apk.
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- run: yarn
|
|
||||||
- uses: ./
|
|
||||||
id: unity-build
|
|
||||||
timeout-minutes: 30
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
cloudRunnerTests: true
|
|
||||||
versioning: None
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
|
||||||
- run: |
|
|
||||||
cp ./cloud-runner-cache/cache/${{ steps.unity-build.outputs.CACHE_KEY }}/build/${{ steps.unity-build.outputs.BUILD_ARTIFACT }} ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.providerStrategy }} Build (${{ matrix.targetPlatform }})
|
|
||||||
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
|
||||||
retention-days: 14
|
|
||||||
46
.github/workflows/integrity-check.yml
vendored
46
.github/workflows/integrity-check.yml
vendored
@@ -2,7 +2,13 @@ name: Integrity
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push: { branches: [main] }
|
push: { branches: [main] }
|
||||||
pull_request: {}
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, labeled]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
checks: write
|
||||||
|
statuses: write
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
|
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
|
||||||
@@ -16,13 +22,41 @@ jobs:
|
|||||||
name: Tests
|
name: Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- name: Install package manager (from package.json)
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack install
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
- run: yarn
|
- name: Resolve yarn cache folder
|
||||||
|
id: yarn-config
|
||||||
|
run: echo "cacheFolder=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Restore yarn install cache (node_modules + cacheFolder + install-state)
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{ steps.yarn-config.outputs.cacheFolder }}
|
||||||
|
.yarn/install-state.gz
|
||||||
|
key: yarn-v2-${{ runner.os }}-node-18-${{ hashFiles('yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
yarn-v2-${{ runner.os }}-node-18-
|
||||||
|
- name: Install deps
|
||||||
|
env:
|
||||||
|
YARN_ENABLE_HARDENED_MODE: 'false'
|
||||||
|
run: |
|
||||||
|
case "$(yarn --version)" in 1.*) echo 'expected up-to-date yarn version'; exit 1 ;; esac
|
||||||
|
yarn install --immutable
|
||||||
- run: yarn lint
|
- run: yarn lint
|
||||||
- run: yarn test --coverage
|
- run: yarn test:ci --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 dist || { echo "dist should be auto generated" ; git diff dist ; exit 62; }
|
# - run: yarn build --quiet && git diff --quiet dist || { echo "dist should be auto generated" ; git diff dist ; exit 62; }
|
||||||
|
|
||||||
|
orchestrator-integration:
|
||||||
|
name: Orchestrator Integration
|
||||||
|
if: >-
|
||||||
|
github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'run-integration')
|
||||||
|
uses: ./.github/workflows/validate-orchestrator-integration.yml
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
91
.github/workflows/sync-secrets.yml
vendored
Normal file
91
.github/workflows/sync-secrets.yml
vendored
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
name: Sync Secrets to Repositories
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
target_repo:
|
||||||
|
description: 'Target repository (org/repo format)'
|
||||||
|
required: true
|
||||||
|
default: 'game-ci/orchestrator'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- game-ci/orchestrator
|
||||||
|
- game-ci/cli
|
||||||
|
dry_run:
|
||||||
|
description: 'Dry run (list secrets to sync without writing)'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync-secrets:
|
||||||
|
name: Sync secrets to ${{ inputs.target_repo }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Sync secrets
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
|
TARGET_REPO: ${{ inputs.target_repo }}
|
||||||
|
DRY_RUN: ${{ inputs.dry_run }}
|
||||||
|
# Secrets to sync — values come from repo + org secrets available here
|
||||||
|
SECRET_UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
SECRET_UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
SECRET_UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
SECRET_GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
|
SECRET_GOOGLE_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
|
||||||
|
SECRET_GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
||||||
|
SECRET_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
SECRET_UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
SECRET_NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
run: |
|
||||||
|
SECRETS=(
|
||||||
|
"UNITY_EMAIL:SECRET_UNITY_EMAIL"
|
||||||
|
"UNITY_PASSWORD:SECRET_UNITY_PASSWORD"
|
||||||
|
"UNITY_SERIAL:SECRET_UNITY_SERIAL"
|
||||||
|
"UNITY_LICENSE:SECRET_UNITY_LICENSE"
|
||||||
|
"GIT_PRIVATE_TOKEN:SECRET_GIT_PRIVATE_TOKEN"
|
||||||
|
"GOOGLE_SERVICE_ACCOUNT_EMAIL:SECRET_GOOGLE_SERVICE_ACCOUNT_EMAIL"
|
||||||
|
"GOOGLE_SERVICE_ACCOUNT_KEY:SECRET_GOOGLE_SERVICE_ACCOUNT_KEY"
|
||||||
|
"CODECOV_TOKEN:SECRET_CODECOV_TOKEN"
|
||||||
|
"NPM_TOKEN:SECRET_NPM_TOKEN"
|
||||||
|
)
|
||||||
|
|
||||||
|
synced=0
|
||||||
|
skipped=0
|
||||||
|
|
||||||
|
for entry in "${SECRETS[@]}"; do
|
||||||
|
name="${entry%%:*}"
|
||||||
|
env_var="${entry##*:}"
|
||||||
|
value="${!env_var}"
|
||||||
|
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
echo "⏭ SKIP: $name (not available in this repo's context)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
echo "🔍 DRY RUN: would sync $name → $TARGET_REPO"
|
||||||
|
else
|
||||||
|
if echo "$value" | gh secret set "$name" -R "$TARGET_REPO" --body - 2>/dev/null; then
|
||||||
|
echo "✅ SYNCED: $name → $TARGET_REPO"
|
||||||
|
else
|
||||||
|
echo "⚠️ FAILED: $name → $TARGET_REPO (continuing)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
synced=$((synced - 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
synced=$((synced + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Summary ==="
|
||||||
|
echo "Synced: $synced"
|
||||||
|
echo "Skipped (not available): $skipped"
|
||||||
|
echo "Target: $TARGET_REPO"
|
||||||
|
if [ "$DRY_RUN" = "true" ]; then
|
||||||
|
echo "Mode: DRY RUN (no secrets were written)"
|
||||||
|
fi
|
||||||
205
.github/workflows/validate-community-plugins.yml
vendored
Normal file
205
.github/workflows/validate-community-plugins.yml
vendored
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
name: Validate Community Plugins
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Run weekly on Sunday at 02:00 UTC
|
||||||
|
- cron: '0 2 * * 0'
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
plugin_filter:
|
||||||
|
description: 'Filter plugins by name (regex pattern, empty = all)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
unity_version:
|
||||||
|
description: 'Override Unity version (empty = use plugin default)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
load-plugins:
|
||||||
|
name: Load Plugin Registry
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.parse.outputs.matrix }}
|
||||||
|
plugin_count: ${{ steps.parse.outputs.count }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Parse plugin registry
|
||||||
|
id: parse
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
|
const registry = yaml.load(fs.readFileSync('community-plugins.yml', 'utf8'));
|
||||||
|
let plugins = registry.plugins || [];
|
||||||
|
|
||||||
|
// Apply name filter if provided
|
||||||
|
const filter = '${{ github.event.inputs.plugin_filter }}';
|
||||||
|
if (filter) {
|
||||||
|
const regex = new RegExp(filter, 'i');
|
||||||
|
plugins = plugins.filter(p => regex.test(p.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand platform matrix
|
||||||
|
const matrix = [];
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const platforms = plugin.platforms || ['StandaloneLinux64'];
|
||||||
|
for (const platform of platforms) {
|
||||||
|
matrix.push({
|
||||||
|
name: plugin.name,
|
||||||
|
package: plugin.package,
|
||||||
|
source: plugin.source || 'git',
|
||||||
|
unity: '${{ github.event.inputs.unity_version }}' || plugin.unity || '2021.3',
|
||||||
|
platform: platform,
|
||||||
|
timeout: plugin.timeout || 30
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.setOutput('matrix', JSON.stringify({ include: matrix }));
|
||||||
|
core.setOutput('count', matrix.length);
|
||||||
|
console.log(`Found ${matrix.length} plugin-platform combinations to validate`);
|
||||||
|
|
||||||
|
validate:
|
||||||
|
name: '${{ matrix.name }} (${{ matrix.platform }})'
|
||||||
|
needs: load-plugins
|
||||||
|
if: needs.load-plugins.outputs.plugin_count > 0
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: ${{ fromJson(matrix.timeout) }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix: ${{ fromJson(needs.load-plugins.outputs.matrix) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create test project
|
||||||
|
run: |
|
||||||
|
mkdir -p test-project/Assets
|
||||||
|
mkdir -p test-project/Packages
|
||||||
|
mkdir -p test-project/ProjectSettings
|
||||||
|
|
||||||
|
# Create minimal manifest.json
|
||||||
|
if [ "${{ matrix.source }}" = "git" ]; then
|
||||||
|
cat > test-project/Packages/manifest.json << 'MANIFEST'
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"com.unity.modules.imgui": "1.0.0",
|
||||||
|
"com.unity.modules.jsonserialize": "1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# Add git package via manifest
|
||||||
|
cd test-project
|
||||||
|
python3 -c "
|
||||||
|
import sys, json
|
||||||
|
manifest = json.load(sys.stdin)
|
||||||
|
manifest['dependencies']['${{ matrix.name }}'] = '${{ matrix.package }}'
|
||||||
|
json.dump(manifest, sys.stdout, indent=2)
|
||||||
|
" < Packages/manifest.json > Packages/manifest.tmp && mv Packages/manifest.tmp Packages/manifest.json
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create minimal ProjectSettings
|
||||||
|
cat > test-project/ProjectSettings/ProjectVersion.txt << EOF
|
||||||
|
m_EditorVersion: ${{ matrix.unity }}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Build with unity-builder
|
||||||
|
uses: ./
|
||||||
|
id: build
|
||||||
|
with:
|
||||||
|
projectPath: test-project
|
||||||
|
targetPlatform: ${{ matrix.platform }}
|
||||||
|
unityVersion: ${{ matrix.unity }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Record result
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
STATUS="${{ steps.build.outcome }}"
|
||||||
|
{
|
||||||
|
echo "## ${{ matrix.name }} — ${{ matrix.platform }}"
|
||||||
|
echo ""
|
||||||
|
if [ "$STATUS" = "success" ]; then
|
||||||
|
echo "✅ **PASSED** — Compiled and built successfully"
|
||||||
|
else
|
||||||
|
echo "❌ **FAILED** — Build or compilation failed"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "- Unity: ${{ matrix.unity }}"
|
||||||
|
echo "- Platform: ${{ matrix.platform }}"
|
||||||
|
echo "- Source: ${{ matrix.source }}"
|
||||||
|
echo "- Package: \`${{ matrix.package }}\`"
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
report:
|
||||||
|
name: Validation Report
|
||||||
|
needs: [load-plugins, validate]
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Generate summary
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { data: run } = await github.rest.actions.listJobsForWorkflowRun({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
run_id: context.runId
|
||||||
|
});
|
||||||
|
|
||||||
|
const validateJobs = run.jobs.filter(j => j.name.startsWith('validate'));
|
||||||
|
const passed = validateJobs.filter(j => j.conclusion === 'success').length;
|
||||||
|
const failed = validateJobs.filter(j => j.conclusion === 'failure').length;
|
||||||
|
const total = validateJobs.length;
|
||||||
|
|
||||||
|
let summary = `# Community Plugin Validation Report\n\n`;
|
||||||
|
summary += `**${passed}/${total} passed** | ${failed} failed\n\n`;
|
||||||
|
summary += `| Plugin | Platform | Status |\n|--------|----------|--------|\n`;
|
||||||
|
|
||||||
|
for (const job of validateJobs) {
|
||||||
|
const icon = job.conclusion === 'success' ? '✅' : '❌';
|
||||||
|
summary += `| ${job.name} | | ${icon} ${job.conclusion} |\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
await core.summary.addRaw(summary).write();
|
||||||
|
|
||||||
|
// Create or update issue if there are failures
|
||||||
|
if (failed > 0) {
|
||||||
|
const title = `Community Plugin Validation: ${failed} failure(s) — ${new Date().toISOString().split('T')[0]}`;
|
||||||
|
const body = summary + `\n\n[Workflow Run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`;
|
||||||
|
|
||||||
|
const { data: issues } = await github.rest.issues.listForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
state: 'open',
|
||||||
|
labels: 'community-plugin-validation'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (issues.length > 0) {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issues[0].number,
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await github.rest.issues.create({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
title: title,
|
||||||
|
body: body,
|
||||||
|
labels: ['community-plugin-validation']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
1242
.github/workflows/validate-orchestrator-integration.yml
vendored
Normal file
1242
.github/workflows/validate-orchestrator-integration.yml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
255
.github/workflows/validate-orchestrator.yml
vendored
Normal file
255
.github/workflows/validate-orchestrator.yml
vendored
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
name: Validate Orchestrator Compatibility
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# Essential plugin health checks — runs on every PR and push.
|
||||||
|
# Fast (~5 min): compilation, unit tests, plugin interface, type declarations.
|
||||||
|
#
|
||||||
|
# For exhaustive integration tests (k8s, AWS, local-docker, rclone) see
|
||||||
|
# validate-orchestrator-integration.yml which runs on a daily cron.
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches: [main, 'release/**', 'feature/**', 'refactor/**']
|
||||||
|
paths:
|
||||||
|
- 'src/model/orchestrator-plugin.ts'
|
||||||
|
- 'src/model/build-parameters.ts'
|
||||||
|
- 'src/model/input.ts'
|
||||||
|
- 'src/model/github.ts'
|
||||||
|
- 'src/model/cli/cli.ts'
|
||||||
|
- 'src/model/input-readers/**'
|
||||||
|
- 'src/index.ts'
|
||||||
|
- 'src/types/game-ci-orchestrator.d.ts'
|
||||||
|
- 'action.yml'
|
||||||
|
- 'package.json'
|
||||||
|
- 'yarn.lock'
|
||||||
|
- '.github/workflows/validate-orchestrator.yml'
|
||||||
|
pull_request:
|
||||||
|
branches: [main, 'release/**']
|
||||||
|
paths:
|
||||||
|
- 'src/model/orchestrator-plugin.ts'
|
||||||
|
- 'src/model/build-parameters.ts'
|
||||||
|
- 'src/model/input.ts'
|
||||||
|
- 'src/model/github.ts'
|
||||||
|
- 'src/model/cli/cli.ts'
|
||||||
|
- 'src/model/input-readers/**'
|
||||||
|
- 'src/index.ts'
|
||||||
|
- 'src/types/game-ci-orchestrator.d.ts'
|
||||||
|
- 'action.yml'
|
||||||
|
- 'package.json'
|
||||||
|
- 'yarn.lock'
|
||||||
|
- '.github/workflows/validate-orchestrator.yml'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ============================================================================
|
||||||
|
# PLUGIN ARCHITECTURE HEALTH CHECK
|
||||||
|
# ============================================================================
|
||||||
|
# Validates that:
|
||||||
|
# 1. unity-builder compiles and its unit tests pass
|
||||||
|
# 2. Plugin loader degrades gracefully without orchestrator
|
||||||
|
# 3. Orchestrator compiles and its unit tests pass
|
||||||
|
# 4. Plugin loader loads all services when orchestrator is installed
|
||||||
|
# 5. Type declarations match actual exports
|
||||||
|
# ============================================================================
|
||||||
|
plugin-health:
|
||||||
|
name: Plugin Architecture Health
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout unity-builder
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Checkout orchestrator
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: game-ci/orchestrator
|
||||||
|
ref: ${{ github.head_ref || github.ref_name }}
|
||||||
|
path: orchestrator-standalone
|
||||||
|
continue-on-error: true
|
||||||
|
id: orchestrator-branch
|
||||||
|
|
||||||
|
- name: Fallback to orchestrator main branch
|
||||||
|
if: steps.orchestrator-branch.outcome == 'failure'
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: game-ci/orchestrator
|
||||||
|
path: orchestrator-standalone
|
||||||
|
|
||||||
|
- name: Install package manager (from package.json)
|
||||||
|
run: |
|
||||||
|
corepack enable
|
||||||
|
corepack install
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Resolve yarn cache folder
|
||||||
|
id: yarn-config
|
||||||
|
run: echo "cacheFolder=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Restore yarn install cache (node_modules + cacheFolder + install-state)
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
${{ steps.yarn-config.outputs.cacheFolder }}
|
||||||
|
.yarn/install-state.gz
|
||||||
|
key: yarn-v2-${{ runner.os }}-node-20-${{ hashFiles('yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
yarn-v2-${{ runner.os }}-node-20-
|
||||||
|
|
||||||
|
# --- unity-builder compilation and tests ---
|
||||||
|
- name: Install unity-builder dependencies
|
||||||
|
env:
|
||||||
|
YARN_ENABLE_HARDENED_MODE: 'false'
|
||||||
|
run: |
|
||||||
|
case "$(yarn --version)" in 1.*) echo 'expected up-to-date yarn version'; exit 1 ;; esac
|
||||||
|
yarn install --immutable
|
||||||
|
|
||||||
|
- name: Build unity-builder
|
||||||
|
run: |
|
||||||
|
echo "Building unity-builder TypeScript..."
|
||||||
|
npx tsc
|
||||||
|
echo "✓ unity-builder compiles successfully"
|
||||||
|
|
||||||
|
- name: Run orchestrator-plugin unit tests
|
||||||
|
run: |
|
||||||
|
echo "Running orchestrator-plugin unit tests..."
|
||||||
|
yarn vitest run orchestrator-plugin
|
||||||
|
|
||||||
|
# --- Plugin loader without orchestrator ---
|
||||||
|
- name: Verify plugin loader returns undefined without orchestrator
|
||||||
|
run: |
|
||||||
|
echo "Checking plugin loader handles missing @game-ci/orchestrator..."
|
||||||
|
node -e "
|
||||||
|
const { loadOrchestratorPlugin } = require('./lib/model/orchestrator-plugin');
|
||||||
|
(async () => {
|
||||||
|
const plugin = await loadOrchestratorPlugin();
|
||||||
|
if (plugin !== undefined) {
|
||||||
|
console.error('ERROR: loadOrchestratorPlugin should return undefined when package not installed');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log('✓ loadOrchestratorPlugin() returns undefined when package not installed');
|
||||||
|
})();
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Verify orchestrator type declarations exist
|
||||||
|
run: |
|
||||||
|
if [ -f "src/types/game-ci-orchestrator.d.ts" ]; then
|
||||||
|
echo "✓ Type declarations for @game-ci/orchestrator exist"
|
||||||
|
else
|
||||||
|
echo "::error::Missing type declarations: src/types/game-ci-orchestrator.d.ts"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Orchestrator compilation and tests ---
|
||||||
|
- name: Build and pack orchestrator
|
||||||
|
working-directory: orchestrator-standalone
|
||||||
|
run: |
|
||||||
|
yarn install --immutable
|
||||||
|
echo "Building orchestrator..."
|
||||||
|
npx tsc
|
||||||
|
echo "✓ orchestrator compiles successfully"
|
||||||
|
echo "Packing orchestrator as tarball..."
|
||||||
|
npm pack
|
||||||
|
|
||||||
|
- name: Run orchestrator unit tests
|
||||||
|
working-directory: orchestrator-standalone
|
||||||
|
run: |
|
||||||
|
echo "Running orchestrator unit tests..."
|
||||||
|
yarn vitest run 2>&1 | tail -30
|
||||||
|
|
||||||
|
# --- Plugin loader with orchestrator installed ---
|
||||||
|
- name: Install orchestrator into unity-builder
|
||||||
|
run: |
|
||||||
|
echo "Installing orchestrator into unity-builder workspace..."
|
||||||
|
npm install ./orchestrator-standalone/game-ci-orchestrator-*.tgz --no-save --legacy-peer-deps
|
||||||
|
|
||||||
|
- name: Verify plugin loader returns exports with orchestrator installed
|
||||||
|
run: |
|
||||||
|
echo "Checking plugin loader returns defined exports..."
|
||||||
|
node -e "
|
||||||
|
const { loadOrchestratorPlugin } = require('./lib/model/orchestrator-plugin');
|
||||||
|
(async () => {
|
||||||
|
const plugin = await loadOrchestratorPlugin();
|
||||||
|
if (plugin === undefined) {
|
||||||
|
console.error('ERROR: loadOrchestratorPlugin should return defined plugin when package is installed');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const lifecycleMethods = [
|
||||||
|
'initialize', 'canHandleBuild', 'handleBuild',
|
||||||
|
'beforeLocalBuild', 'afterLocalBuild', 'handlePostBuild',
|
||||||
|
];
|
||||||
|
for (const method of lifecycleMethods) {
|
||||||
|
if (typeof plugin[method] !== 'function') {
|
||||||
|
console.error('ERROR: plugin.' + method + ' should be a function, got ' + typeof plugin[method]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('✓ loadOrchestratorPlugin() returns plugin with all ' + lifecycleMethods.length + ' lifecycle methods');
|
||||||
|
})();
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Verify type declarations match orchestrator exports
|
||||||
|
run: |
|
||||||
|
echo "Checking type declarations align with orchestrator exports..."
|
||||||
|
node -e "
|
||||||
|
const orch = require('@game-ci/orchestrator');
|
||||||
|
const expectedExports = [
|
||||||
|
'Orchestrator', 'BuildReliabilityService', 'TestWorkflowService',
|
||||||
|
'HotRunnerService', 'OutputService', 'OutputTypeRegistry',
|
||||||
|
'ArtifactUploadHandler', 'IncrementalSyncService',
|
||||||
|
'ChildWorkspaceService', 'LocalCacheService', 'SubmoduleProfileService',
|
||||||
|
'LfsAgentService', 'GitHooksService',
|
||||||
|
];
|
||||||
|
const missing = expectedExports.filter(e => orch[e] === undefined);
|
||||||
|
if (missing.length > 0) {
|
||||||
|
console.error('ERROR: Missing exports from @game-ci/orchestrator:', missing.join(', '));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log('✓ All ' + expectedExports.length + ' declared exports present in orchestrator package');
|
||||||
|
"
|
||||||
|
|
||||||
|
- name: Smoke test orchestrator build wiring
|
||||||
|
run: |
|
||||||
|
echo "Verifying orchestrator build wiring end-to-end..."
|
||||||
|
node -e "
|
||||||
|
const { loadOrchestratorPlugin } = require('./lib/model/orchestrator-plugin');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
// Verify plugin loads successfully with orchestrator installed
|
||||||
|
const plugin = await loadOrchestratorPlugin();
|
||||||
|
if (plugin === undefined) {
|
||||||
|
console.error('ERROR: plugin should be defined when orchestrator is installed');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all lifecycle methods are callable
|
||||||
|
const lifecycleMethods = [
|
||||||
|
'initialize', 'canHandleBuild', 'handleBuild',
|
||||||
|
'beforeLocalBuild', 'afterLocalBuild', 'handlePostBuild',
|
||||||
|
];
|
||||||
|
for (const m of lifecycleMethods) {
|
||||||
|
if (typeof plugin[m] !== 'function') {
|
||||||
|
console.error('ERROR: plugin.' + m + ' should be a function, got ' + typeof plugin[m]);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('✓ Plugin has all ' + lifecycleMethods.length + ' lifecycle methods');
|
||||||
|
|
||||||
|
// Verify canHandleBuild returns a boolean
|
||||||
|
const canHandle = plugin.canHandleBuild();
|
||||||
|
if (typeof canHandle !== 'boolean') {
|
||||||
|
console.error('ERROR: canHandleBuild() should return a boolean, got ' + typeof canHandle);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log('✓ canHandleBuild() returns boolean');
|
||||||
|
|
||||||
|
console.log('✓ Plugin architecture wiring verified');
|
||||||
|
})();
|
||||||
|
"
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -5,3 +5,14 @@ lib/
|
|||||||
.vsconfig
|
.vsconfig
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
.orig
|
.orig
|
||||||
|
$LOG_FILE
|
||||||
|
temp/
|
||||||
|
|
||||||
|
# yarn 4 (berry)
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/sdks
|
||||||
|
!.yarn/versions
|
||||||
|
|||||||
7
.husky/pre-commit
Executable file
7
.husky/pre-commit
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
yarn lint-staged
|
||||||
|
yarn typecheck
|
||||||
|
|
||||||
|
if command -v gitleaks >/dev/null 2>&1; then
|
||||||
|
gitleaks protect --staged --no-banner --redact
|
||||||
|
fi
|
||||||
17
.oxfmtrc.json
Normal file
17
.oxfmtrc.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"sortPackageJson": false,
|
||||||
|
"ignorePatterns": [
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/dist/**",
|
||||||
|
"**/coverage/**",
|
||||||
|
"**/.yarn/**",
|
||||||
|
"default-build-script/**",
|
||||||
|
"test-runner/**",
|
||||||
|
"platforms/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
58
.oxlintrc.json
Normal file
58
.oxlintrc.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||||
|
"plugins": ["typescript", "vitest", "unicorn", "oxc"],
|
||||||
|
"categories": {
|
||||||
|
"correctness": "error",
|
||||||
|
"suspicious": "error",
|
||||||
|
"perf": "error"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"vitest/require-mock-type-parameters": "off",
|
||||||
|
"vitest/valid-title": "off",
|
||||||
|
"vitest/valid-describe-callback": "off",
|
||||||
|
"vitest/expect-expect": "off",
|
||||||
|
"vitest/no-conditional-tests": "off",
|
||||||
|
"vitest/no-conditional-expect": "off",
|
||||||
|
"vitest/require-to-throw-message": "off",
|
||||||
|
"vitest/no-disabled-tests": "warn",
|
||||||
|
"unicorn/prefer-array-flat-map": "warn",
|
||||||
|
"typescript/no-explicit-any": "warn",
|
||||||
|
"typescript/ban-ts-comment": "off",
|
||||||
|
"typescript/no-namespace": "off",
|
||||||
|
"typescript/no-extraneous-class": "off",
|
||||||
|
"no-bitwise": "off",
|
||||||
|
"no-shadow": "off",
|
||||||
|
"no-await-in-loop": "off",
|
||||||
|
"no-underscore-dangle": "off",
|
||||||
|
"unicorn/no-array-sort": "off",
|
||||||
|
"unicorn/prefer-set-has": "off",
|
||||||
|
"unicorn/consistent-function-scoping": "off",
|
||||||
|
"unicorn/no-useless-spread": "warn",
|
||||||
|
"eslint/preserve-caught-error": "warn",
|
||||||
|
"oxc/no-map-spread": "warn"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["**/*.test.ts", "**/*.spec.ts"],
|
||||||
|
"rules": {
|
||||||
|
"typescript/no-explicit-any": "off",
|
||||||
|
"no-unused-vars": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"browser": false,
|
||||||
|
"node": true,
|
||||||
|
"es2024": true,
|
||||||
|
"vitest/globals": true
|
||||||
|
},
|
||||||
|
"ignorePatterns": [
|
||||||
|
"**/node_modules/**",
|
||||||
|
"**/dist/**",
|
||||||
|
"**/coverage/**",
|
||||||
|
"**/.yarn/**",
|
||||||
|
"default-build-script/**",
|
||||||
|
"test-runner/**",
|
||||||
|
"platforms/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
**/node_modules/**
|
|
||||||
**/dist/**
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"printWidth": 120,
|
|
||||||
"proseWrap": "always"
|
|
||||||
}
|
|
||||||
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
@@ -1,5 +1,12 @@
|
|||||||
{
|
{
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "PowerShell Launch Current File",
|
||||||
|
"type": "PowerShell",
|
||||||
|
"request": "launch",
|
||||||
|
"script": "${file}",
|
||||||
|
"cwd": "${cwd}"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|||||||
10
.yarnrc.yml
Normal file
10
.yarnrc.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
approvedGitRepositories:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
compressionLevel: mixed
|
||||||
|
|
||||||
|
enableGlobalCache: false
|
||||||
|
|
||||||
|
enableHardenedMode: false
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
@@ -25,7 +25,7 @@ Steps to be performed to submit a pull request:
|
|||||||
|
|
||||||
#### Pull Request Prerequisites
|
#### Pull Request Prerequisites
|
||||||
|
|
||||||
You have [Node](https://nodejs.org/) installed at v12.2.0+ and [Yarn](https://yarnpkg.com/) at v1.18.0+.
|
You have [Node](https://nodejs.org/) installed at v18+ and [Yarn](https://yarnpkg.com/) at v1.22.0+.
|
||||||
|
|
||||||
Please note that commit hooks will run automatically to perform some tasks;
|
Please note that commit hooks will run automatically to perform some tasks;
|
||||||
|
|
||||||
@@ -36,7 +36,8 @@ Please note that commit hooks will run automatically to perform some tasks;
|
|||||||
#### Windows users
|
#### Windows users
|
||||||
|
|
||||||
Make sure your editor and terminal that run the tests are set to `Powershell 7` or above with
|
Make sure your editor and terminal that run the tests are set to `Powershell 7` or above with
|
||||||
`Git's Unix tools for Windows` installed. Some tests require you to be able to run `sh` and other unix commands.
|
`Git's Unix tools for Windows` installed. This is because some tests require you to be able to run `sh` and other
|
||||||
|
unix commands.
|
||||||
|
|
||||||
#### License
|
#### License
|
||||||
|
|
||||||
|
|||||||
165
action.yml
165
action.yml
@@ -9,8 +9,7 @@ inputs:
|
|||||||
unityVersion:
|
unityVersion:
|
||||||
required: false
|
required: false
|
||||||
default: 'auto'
|
default: 'auto'
|
||||||
description:
|
description: 'Version of unity to use for building the project. Use "auto" to get from your ProjectSettings/ProjectVersion.txt'
|
||||||
'Version of unity to use for building the project. Use "auto" to get from your ProjectSettings/ProjectVersion.txt'
|
|
||||||
customImage:
|
customImage:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@@ -18,7 +17,11 @@ inputs:
|
|||||||
projectPath:
|
projectPath:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Relative path to the project to be built.'
|
description: 'Path to the project to be built, relative to the repository root.'
|
||||||
|
buildProfile:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'Path to the build profile to activate, relative to the project root.'
|
||||||
buildName:
|
buildName:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@@ -31,10 +34,22 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
|
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
|
||||||
|
manualExit:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'Suppresses `-quit`. Exit your build method using `EditorApplication.Exit(0)` instead.'
|
||||||
|
enableGpu:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'Launches unity without specifying `-nographics`.'
|
||||||
customParameters:
|
customParameters:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Custom parameters to configure the build.'
|
description: 'Custom parameters to configure the build.'
|
||||||
|
useHostNetwork:
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
description: 'Initialises Docker using the host network. (Linux only)'
|
||||||
versioning:
|
versioning:
|
||||||
required: false
|
required: false
|
||||||
default: 'Semantic'
|
default: 'Semantic'
|
||||||
@@ -92,111 +107,53 @@ inputs:
|
|||||||
gitPrivateToken:
|
gitPrivateToken:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: '[CloudRunner] Github private token to pull from github'
|
description: 'Github private token to pull from github'
|
||||||
githubOwner:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description: '[CloudRunner] GitHub owner name or organization/team name'
|
|
||||||
chownFilesTo:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'User and optionally group (user or user:group or uid:gid) to give ownership of the resulting build artifacts'
|
|
||||||
allowDirtyBuild:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description: '[CloudRunner] Allows the branch of the build to be dirty, and still generate the build.'
|
|
||||||
postBuildSteps:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'[CloudRunner] run a post build job in yaml format with the keys image, secrets (name, value object array),
|
|
||||||
command string'
|
|
||||||
preBuildSteps:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'[CloudRunner] Run a pre build job after the repository setup but before the build job (in yaml format with the
|
|
||||||
keys image, secrets (name, value object array), command line string)'
|
|
||||||
containerHookFiles:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'[CloudRunner] Specify the names (by file name) of custom steps to run before or after cloud runner jobs, must
|
|
||||||
match a yaml step file inside your repo in the folder .game-ci/steps/'
|
|
||||||
customHookFiles:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'[CloudRunner] Specify the names (by file name) of custom hooks to run before or after cloud runner jobs, must
|
|
||||||
match a yaml step file inside your repo in the folder .game-ci/hooks/'
|
|
||||||
customCommandHooks:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description: '[CloudRunner] Specify custom commands and trigger hooks (injects commands into jobs)'
|
|
||||||
customJob:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description:
|
|
||||||
'[CloudRunner] Run a custom job instead of the standard build automation for cloud runner (in yaml format with the
|
|
||||||
keys image, secrets (name, value object array), command line string)'
|
|
||||||
awsStackName:
|
|
||||||
default: 'game-ci'
|
|
||||||
required: false
|
|
||||||
description: '[CloudRunner] The Cloud Formation stack name that must be setup before using this option.'
|
|
||||||
providerStrategy:
|
providerStrategy:
|
||||||
default: 'local'
|
default: 'local'
|
||||||
required: false
|
required: false
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must
|
'Build execution strategy. Use "local" for local Docker/Mac builds. For remote builds (aws, k8s, etc.), install
|
||||||
be configured.'
|
@game-ci/orchestrator and use the game-ci/orchestrator action which declares its own inputs.'
|
||||||
cloudRunnerCpu:
|
runAsHostUser:
|
||||||
default: ''
|
|
||||||
required: false
|
|
||||||
description: '[CloudRunner] Amount of CPU time to assign the remote build container'
|
|
||||||
cloudRunnerMemory:
|
|
||||||
default: ''
|
|
||||||
required: false
|
|
||||||
description: '[CloudRunner] Amount of memory to assign the remote build container'
|
|
||||||
readInputFromOverrideList:
|
|
||||||
default: ''
|
|
||||||
required: false
|
|
||||||
description: '[CloudRunner] Comma separated list of input value names to read from "input override command"'
|
|
||||||
readInputOverrideCommand:
|
|
||||||
default: ''
|
|
||||||
required: false
|
required: false
|
||||||
|
default: 'false'
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Extend game ci by specifying a command to execute to pull input from external source e.g cloud
|
'Whether to run as a user that matches the host system or the default root container user. Only applicable to
|
||||||
provider secret managers'
|
Linux hosts and containers. This is useful for fixing permission errors on Self-Hosted runners.'
|
||||||
kubeConfig:
|
chownFilesTo:
|
||||||
default: ''
|
|
||||||
required: false
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'User and optionally group (user or user:group or uid:gid) to give ownership of the resulting build artifacts'
|
||||||
|
dockerCpuLimit:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'Number of CPU cores to assign the docker container. Defaults to all available cores on all platforms.'
|
||||||
|
dockerMemoryLimit:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Supply a base64 encoded kubernetes config to run builds on kubernetes and stream logs until
|
'Amount of memory to assign the docker container. Defaults to 95% of total system memory rounded down to the
|
||||||
completion.'
|
nearest megabyte on Linux and 80% on Windows. On unrecognized platforms, defaults to 75% of total system memory.
|
||||||
kubeVolume:
|
To manually specify a value, use the format <number><unit>, where unit is either m or g. ie: 512m = 512 megabytes'
|
||||||
default: ''
|
dockerIsolationMode:
|
||||||
required: false
|
|
||||||
description: '[CloudRunner] Supply a Persistent Volume Claim name to use for the Unity build.'
|
|
||||||
kubeStorageClass:
|
|
||||||
default: ''
|
|
||||||
required: false
|
required: false
|
||||||
|
default: 'default'
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Kubernetes storage class to use for cloud runner jobs, leave empty to install rook cluster.'
|
'Isolation mode to use for the docker container. Can be one of process, hyperv, or default. Default will pick the
|
||||||
kubeVolumeSize:
|
default mode as described by Microsoft where server versions use process and desktop versions use hyperv. Only
|
||||||
default: '5Gi'
|
applicable on Windows'
|
||||||
|
containerRegistryRepository:
|
||||||
|
required: false
|
||||||
|
default: 'unityci/editor'
|
||||||
|
description: 'Container registry and repository to pull image from. Only applicable if customImage is not set.'
|
||||||
|
containerRegistryImageVersion:
|
||||||
|
required: false
|
||||||
|
default: '3'
|
||||||
|
description: 'Container registry image version. Only applicable if customImage is not set.'
|
||||||
|
allowDirtyBuild:
|
||||||
required: false
|
required: false
|
||||||
description: '[CloudRunner] Amount of disc space to assign the Kubernetes Persistent Volume'
|
|
||||||
cacheKey:
|
|
||||||
default: ''
|
default: ''
|
||||||
required: false
|
description: 'Allows the branch of the build to be dirty, and still generate the build.'
|
||||||
description: '[CloudRunner] Cache key to indicate bucket for cache'
|
|
||||||
watchToEnd:
|
|
||||||
default: 'true'
|
|
||||||
required: false
|
|
||||||
description:
|
|
||||||
'[CloudRunner] Whether or not to watch the build to the end. Can be used for especially long running jobs e.g
|
|
||||||
imports or self-hosted ephemeral runners.'
|
|
||||||
cacheUnityInstallationOnMac:
|
cacheUnityInstallationOnMac:
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
@@ -217,6 +174,15 @@ inputs:
|
|||||||
description:
|
description:
|
||||||
'The path to mount the workspace inside the docker container. For windows, leave out the drive letter. For example
|
'The path to mount the workspace inside the docker container. For windows, leave out the drive letter. For example
|
||||||
c:/github/workspace should be defined as /github/workspace'
|
c:/github/workspace should be defined as /github/workspace'
|
||||||
|
skipActivation:
|
||||||
|
default: 'false'
|
||||||
|
required: false
|
||||||
|
description: 'Skip the activation/deactivation of Unity. This assumes Unity is already activated.'
|
||||||
|
linux64RemoveExecutableExtension:
|
||||||
|
default: 'false'
|
||||||
|
required: false
|
||||||
|
description:
|
||||||
|
'When building for StandaloneLinux64, remove the default file extension of `.x86_64`. Set to true to restore the extensionless behavior from v4.'
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
volume:
|
volume:
|
||||||
@@ -225,9 +191,14 @@ outputs:
|
|||||||
description: 'The generated version used for the Unity build'
|
description: 'The generated version used for the Unity build'
|
||||||
androidVersionCode:
|
androidVersionCode:
|
||||||
description: 'The generated versionCode used for the Android Unity build'
|
description: 'The generated versionCode used for the Android Unity build'
|
||||||
|
engineExitCode:
|
||||||
|
description:
|
||||||
|
'Returns the exit code from the build scripts. This code is 0 if the build was successful. If there was an error
|
||||||
|
during activation, the code is from the activation step. If activation is successful, the code is from the project
|
||||||
|
build step.'
|
||||||
branding:
|
branding:
|
||||||
icon: 'box'
|
icon: 'box'
|
||||||
color: 'gray-dark'
|
color: 'gray-dark'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node24'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
27
community-plugins.yml
Normal file
27
community-plugins.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Community Plugin Validation Registry
|
||||||
|
# Packages listed here are automatically tested on a schedule
|
||||||
|
# to ensure compatibility with unity-builder.
|
||||||
|
#
|
||||||
|
# Format:
|
||||||
|
# - name: Human-readable name
|
||||||
|
# package: UPM package name or git URL
|
||||||
|
# source: upm | git | asset-store
|
||||||
|
# unity: Minimum Unity version (optional, defaults to 2021.3)
|
||||||
|
# platforms: List of platforms to test (optional, defaults to [StandaloneLinux64])
|
||||||
|
# timeout: Build timeout in minutes (optional, defaults to 30)
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
# Example entries — community members can submit PRs to add their packages
|
||||||
|
- name: UniTask
|
||||||
|
package: https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
|
||||||
|
source: git
|
||||||
|
platforms: [StandaloneLinux64, StandaloneWindows64]
|
||||||
|
|
||||||
|
- name: NaughtyAttributes
|
||||||
|
package: https://github.com/dbrizov/NaughtyAttributes.git?path=Assets/NaughtyAttributes
|
||||||
|
source: git
|
||||||
|
|
||||||
|
- name: Unity Atoms
|
||||||
|
package: https://github.com/unity-atoms/unity-atoms.git
|
||||||
|
source: git
|
||||||
|
platforms: [StandaloneLinux64]
|
||||||
BIN
dist/BlankProject/Packages/.DS_Store
vendored
BIN
dist/BlankProject/Packages/.DS_Store
vendored
Binary file not shown.
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"m_SettingKeys": [
|
|
||||||
"VR Device Disabled",
|
|
||||||
"VR Device User Alert"
|
|
||||||
],
|
|
||||||
"m_SettingValues": [
|
|
||||||
"False",
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,709 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package</_TargetFrameworkDirectories>
|
|
||||||
<_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package</_FullFrameworkReferenceAssemblyPaths>
|
|
||||||
<DisableHandlePackageFileConflicts>true</DisableHandlePackageFileConflicts>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProductVersion>10.0.20506</ProductVersion>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<RootNamespace></RootNamespace>
|
|
||||||
<ProjectGuid>{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<AssemblyName>Assembly-CSharp-Editor</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<BaseDirectory>.</BaseDirectory>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>Temp\bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE;UNITY_2019_2_11;UNITY_2019_2;UNITY_2019;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_WEBCAM;ENABLE_WWW;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;INCLUDE_DYNAMIC_GI;ENABLE_MONO_BDWGC;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITYWEBREQUEST;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_EVENT_QUEUE;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_VR;ENABLE_AR;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;ENABLE_PROFILER;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;NET_4_6;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<NoWarn>0169</NoWarn>
|
|
||||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>Temp\bin\Release\</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<NoWarn>0169</NoWarn>
|
|
||||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<NoConfig>true</NoConfig>
|
|
||||||
<NoStdLib>true</NoStdLib>
|
|
||||||
<AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
|
|
||||||
<ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>
|
|
||||||
<ImplicitlyExpandDesignTimeFacades>false</ImplicitlyExpandDesignTimeFacades>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="UnityEngine">
|
|
||||||
<HintPath>C:\Program Files\Unity\2019.2.11f1\Editor\Data\Managed/UnityEngine/UnityEngine.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor">
|
|
||||||
<HintPath>C:\Program Files\Unity\2019.2.11f1\Editor\Data\Managed/UnityEditor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Assets\Editor\Builder.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Input\ArgumentsParser.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Reporting\StdOutReporter.cs" />
|
|
||||||
<Compile Include="Assets\Editor\System\ProcessExtensions.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Versioning\VersionApplicator.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Versioning\Git.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Versioning\VersionGenerator.cs" />
|
|
||||||
<Compile Include="Assets\Editor\Versioning\GitException.cs" />
|
|
||||||
<Reference Include="UnityEditor.TestRunner">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.TestRunner.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TestRunner">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEngine.TestRunner.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Timeline.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.Timeline.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="com.unity.multiplayer-hlapi.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/com.unity.multiplayer-hlapi.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.VSCode.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.VSCode.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.TextMeshPro.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UI">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEngine.UI.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Timeline">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.Timeline.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.CollabProxy.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.CollabProxy.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="com.unity.multiplayer-weaver.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/com.unity.multiplayer-weaver.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.XR.LegacyInputHelpers">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEngine.XR.LegacyInputHelpers.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Rider.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.Rider.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.2D.Sprite.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.2D.Sprite.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.2D.Tilemap.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.2D.Tilemap.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.SpatialTracking">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.SpatialTracking.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SpatialTracking">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEngine.SpatialTracking.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.TextMeshPro">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.TextMeshPro.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Analytics.DataPrivacy">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/Unity.Analytics.DataPrivacy.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.XR.LegacyInputHelpers">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.XR.LegacyInputHelpers.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.UI">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.UI.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="com.unity.multiplayer-hlapi.Runtime">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/com.unity.multiplayer-hlapi.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AIModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ARModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ARModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AccessibilityModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AndroidJNIModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AnimationModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AnimationModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AssetBundleModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.AudioModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.AudioModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClothModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClothModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClusterInputModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ClusterRendererModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.CoreModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.CrashReportingModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.DSPGraphModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.DirectorModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.DirectorModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.FileSystemHttpModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.FileSystemHttpModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.GameCenterModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.GameCenterModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.GridModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.GridModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.HotReloadModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.HotReloadModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.IMGUIModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.IMGUIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ImageConversionModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.InputModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.InputLegacyModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.JSONSerializeModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.LocalizationModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.LocalizationModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ParticleSystemModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.PerformanceReportingModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.PhysicsModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.Physics2DModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.Physics2DModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ProfilerModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ProfilerModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.ScreenCaptureModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SharedInternalsModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SpriteMaskModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SpriteShapeModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.StreamingModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.StreamingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.SubstanceModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.SubstanceModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TLSModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TLSModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TerrainModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TerrainPhysicsModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TextCoreModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextCoreModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TextRenderingModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.TilemapModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.TilemapModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UIModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UIElementsModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UIElementsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UNETModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UNETModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UmbraModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UmbraModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityAnalyticsModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityConnectModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityTestProtocolModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VFXModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.VFXModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VRModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.VRModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VehiclesModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.VehiclesModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.VideoModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.VideoModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.WindModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.WindModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEngine.XRModule">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEngine/UnityEngine.XRModule.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.VR">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/UnityExtensions/Unity/UnityVR/Editor/UnityEditor.VR.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.Graphs">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/Managed/UnityEditor.Graphs.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.WindowsStandalone.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/PlaybackEngines/WindowsStandaloneSupport/UnityEditor.WindowsStandalone.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.WebGL.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.Android.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/PlaybackEngines/AndroidPlayer/UnityEditor.Android.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.UWP.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/PlaybackEngines/MetroSupport/UnityEditor.UWP.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.Advertisements">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.ads@2.0.8/Editor/UnityEditor.Advertisements.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Analytics.Editor">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.analytics@3.3.2/Unity.Analytics.Editor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Analytics.StandardEvents">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.analytics@3.3.2/Unity.Analytics.StandardEvents.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Unity.Analytics.Tracker">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.analytics@3.3.2/Unity.Analytics.Tracker.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityEditor.Purchasing">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.purchasing@2.0.6/Editor/UnityEditor.Purchasing.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="nunit.framework">
|
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/PackageCache/com.unity.ext.nunit@1.0.0/net35/unity-custom/nunit.framework.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="mscorlib">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/mscorlib.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Core">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Core.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Serialization">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Runtime.Serialization.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Xml.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.Linq">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Xml.Linq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Numerics">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Numerics.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Numerics.Vectors">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Numerics.Vectors.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Http">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Net.Http.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.CSharp">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Microsoft.CSharp.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Data">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/System.Data.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Win32.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/Microsoft.Win32.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="netstandard">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/netstandard.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.AppContext">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.AppContext.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Collections.Concurrent">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Collections.Concurrent.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Collections">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Collections.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Collections.NonGeneric">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Collections.NonGeneric.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Collections.Specialized">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Collections.Specialized.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ComponentModel.Annotations">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ComponentModel.Annotations.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ComponentModel">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ComponentModel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ComponentModel.EventBasedAsync">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ComponentModel.EventBasedAsync.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ComponentModel.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ComponentModel.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ComponentModel.TypeConverter">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ComponentModel.TypeConverter.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Console">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Console.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Data.Common">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Data.Common.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.Contracts">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.Contracts.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.Debug">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.Debug.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.FileVersionInfo">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.FileVersionInfo.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.Process">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.Process.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.StackTrace">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.StackTrace.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.TextWriterTraceListener">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.TextWriterTraceListener.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.Tools">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.Tools.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Diagnostics.TraceSource">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Diagnostics.TraceSource.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Drawing.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Drawing.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Dynamic.Runtime">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Dynamic.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Globalization.Calendars">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Globalization.Calendars.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Globalization">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Globalization.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Globalization.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Globalization.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.Compression.ZipFile">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.Compression.ZipFile.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.FileSystem">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.FileSystem.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.FileSystem.DriveInfo">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.FileSystem.DriveInfo.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.FileSystem.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.FileSystem.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.FileSystem.Watcher">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.FileSystem.Watcher.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.IsolatedStorage">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.IsolatedStorage.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.MemoryMappedFiles">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.MemoryMappedFiles.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.Pipes">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.Pipes.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.IO.UnmanagedMemoryStream">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.IO.UnmanagedMemoryStream.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Linq">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Linq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Linq.Expressions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Linq.Expressions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Linq.Parallel">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Linq.Parallel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Linq.Queryable">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Linq.Queryable.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Http.Rtc">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Http.Rtc.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.NameResolution">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.NameResolution.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.NetworkInformation">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.NetworkInformation.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Ping">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Ping.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Requests">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Requests.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Security">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Security.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.Sockets">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.Sockets.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.WebHeaderCollection">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.WebHeaderCollection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.WebSockets.Client">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.WebSockets.Client.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Net.WebSockets">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Net.WebSockets.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ObjectModel">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ObjectModel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Emit">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.Emit.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Emit.ILGeneration">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.Emit.ILGeneration.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Emit.Lightweight">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.Emit.Lightweight.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Reflection.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Resources.Reader">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Resources.Reader.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Resources.ResourceManager">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Resources.ResourceManager.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Resources.Writer">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Resources.Writer.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.CompilerServices.VisualC">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.CompilerServices.VisualC.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Handles">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Handles.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.InteropServices">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.InteropServices.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.InteropServices.WindowsRuntime">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Numerics">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Numerics.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Serialization.Formatters">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Serialization.Formatters.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Serialization.Json">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Serialization.Json.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Serialization.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Serialization.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.Serialization.Xml">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Runtime.Serialization.Xml.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Claims">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Claims.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Cryptography.Algorithms">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Cryptography.Algorithms.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Cryptography.Csp">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Cryptography.Csp.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Cryptography.Encoding">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Cryptography.Encoding.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Cryptography.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Cryptography.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Cryptography.X509Certificates">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Cryptography.X509Certificates.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Principal">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.Principal.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.SecureString">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Security.SecureString.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ServiceModel.Duplex">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ServiceModel.Duplex.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ServiceModel.Http">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ServiceModel.Http.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ServiceModel.NetTcp">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ServiceModel.NetTcp.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ServiceModel.Primitives">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ServiceModel.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ServiceModel.Security">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ServiceModel.Security.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Text.Encoding">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Text.Encoding.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Text.Encoding.Extensions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Text.Encoding.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Text.RegularExpressions">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Text.RegularExpressions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Overlapped">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.Overlapped.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Tasks">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.Tasks.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Tasks.Parallel">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.Tasks.Parallel.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Thread">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.Thread.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.ThreadPool">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.ThreadPool.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Timer">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Threading.Timer.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.ValueTuple">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.ValueTuple.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.ReaderWriter">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.ReaderWriter.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.XDocument">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.XDocument.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.XmlDocument">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.XmlDocument.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.XmlSerializer">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.XmlSerializer.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.XPath">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.XPath.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.XPath.XDocument">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/4.7.1-api/Facades/System.Xml.XPath.XDocument.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityScript">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/UnityScript.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="UnityScript.Lang">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/UnityScript.Lang.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Boo.Lang">
|
|
||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/Boo.Lang.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include=".editorconfig" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
|
||||||
@@ -6,6 +6,9 @@ using UnityBuilderAction.Reporting;
|
|||||||
using UnityBuilderAction.Versioning;
|
using UnityBuilderAction.Versioning;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Build.Reporting;
|
using UnityEditor.Build.Reporting;
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
using UnityEditor.Build.Profile;
|
||||||
|
#endif
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityBuilderAction
|
namespace UnityBuilderAction
|
||||||
@@ -17,47 +20,9 @@ namespace UnityBuilderAction
|
|||||||
// Gather values from args
|
// Gather values from args
|
||||||
var options = ArgumentsParser.GetValidatedOptions();
|
var options = ArgumentsParser.GetValidatedOptions();
|
||||||
|
|
||||||
// Gather values from project
|
|
||||||
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
|
|
||||||
|
|
||||||
// Get all buildOptions from options
|
|
||||||
BuildOptions buildOptions = BuildOptions.None;
|
|
||||||
foreach (string buildOptionString in Enum.GetNames(typeof(BuildOptions))) {
|
|
||||||
if (options.ContainsKey(buildOptionString)) {
|
|
||||||
BuildOptions buildOptionEnum = (BuildOptions) Enum.Parse(typeof(BuildOptions), buildOptionString);
|
|
||||||
buildOptions |= buildOptionEnum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
|
||||||
// Determine subtarget
|
|
||||||
StandaloneBuildSubtarget buildSubtarget;
|
|
||||||
if (!options.TryGetValue("standaloneBuildSubtarget", out var subtargetValue) || !Enum.TryParse(subtargetValue, out buildSubtarget)) {
|
|
||||||
buildSubtarget = default;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Define BuildPlayer Options
|
|
||||||
var buildPlayerOptions = new BuildPlayerOptions {
|
|
||||||
scenes = scenes,
|
|
||||||
locationPathName = options["customBuildPath"],
|
|
||||||
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
|
|
||||||
options = buildOptions,
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
|
||||||
subtarget = (int) buildSubtarget
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set version for this build
|
// Set version for this build
|
||||||
VersionApplicator.SetVersion(options["buildVersion"]);
|
VersionApplicator.SetVersion(options["buildVersion"]);
|
||||||
|
|
||||||
// Apply Android settings
|
|
||||||
if (buildPlayerOptions.target == BuildTarget.Android)
|
|
||||||
{
|
|
||||||
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
|
|
||||||
AndroidSettings.Apply(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute default AddressableAsset content build, if the package is installed.
|
// Execute default AddressableAsset content build, if the package is installed.
|
||||||
// Version defines would be the best solution here, but Unity 2018 doesn't support that,
|
// Version defines would be the best solution here, but Unity 2018 doesn't support that,
|
||||||
// so we fall back to using reflection instead.
|
// so we fall back to using reflection instead.
|
||||||
@@ -74,10 +39,85 @@ namespace UnityBuilderAction
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError($"Failed to run default addressables build:\n{e}");
|
Debug.LogError("Failed to run default addressables build:\n" + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all buildOptions from options
|
||||||
|
BuildOptions buildOptions = BuildOptions.None;
|
||||||
|
foreach (string buildOptionString in Enum.GetNames(typeof(BuildOptions))) {
|
||||||
|
if (options.ContainsKey(buildOptionString)) {
|
||||||
|
BuildOptions buildOptionEnum = (BuildOptions) Enum.Parse(typeof(BuildOptions), buildOptionString);
|
||||||
|
buildOptions |= buildOptionEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on whether the build is using a build profile, `buildPlayerOptions` will an instance
|
||||||
|
// of either `UnityEditor.BuildPlayerOptions` or `UnityEditor.BuildPlayerWithProfileOptions`
|
||||||
|
dynamic buildPlayerOptions;
|
||||||
|
|
||||||
|
if (options.TryGetValue("activeBuildProfile", out var buildProfilePath)) {
|
||||||
|
if (string.IsNullOrEmpty(buildProfilePath)) {
|
||||||
|
throw new Exception("`-activeBuildProfile` is set but with an empty value; this shouldn't happen");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
// Load build profile from Assets folder
|
||||||
|
var buildProfile = AssetDatabase.LoadAssetAtPath<BuildProfile>(buildProfilePath)
|
||||||
|
?? throw new Exception("Build profile file not found at path: " + buildProfilePath);
|
||||||
|
|
||||||
|
// no need to set active profile, as already set by `-activeBuildProfile` CLI argument
|
||||||
|
// BuildProfile.SetActiveBuildProfile(buildProfile);
|
||||||
|
Debug.Log($"build profile: {buildProfile.name}");
|
||||||
|
|
||||||
|
// Define BuildPlayerWithProfileOptions
|
||||||
|
buildPlayerOptions = new BuildPlayerWithProfileOptions {
|
||||||
|
buildProfile = buildProfile,
|
||||||
|
locationPathName = options["customBuildPath"],
|
||||||
|
options = buildOptions,
|
||||||
|
};
|
||||||
|
#else // UNITY_6000_0_OR_NEWER
|
||||||
|
throw new Exception("Build profiles are not supported by this version of Unity (" + Application.unityVersion +")");
|
||||||
|
#endif // UNITY_6000_0_OR_NEWER
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
#if BUILD_PROFILE_LOADED
|
||||||
|
throw new Exception("Build profile's define symbol present; shouldn't happen");
|
||||||
|
#endif // BUILD_PROFILE_LOADED
|
||||||
|
|
||||||
|
// Gather values from project
|
||||||
|
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
|
||||||
|
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
// Determine subtarget
|
||||||
|
StandaloneBuildSubtarget buildSubtarget;
|
||||||
|
if (!options.TryGetValue("standaloneBuildSubtarget", out var subtargetValue) || !Enum.TryParse(subtargetValue, out buildSubtarget)) {
|
||||||
|
buildSubtarget = default;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BuildTarget buildTarget = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]);
|
||||||
|
|
||||||
|
// Define BuildPlayerOptions
|
||||||
|
buildPlayerOptions = new BuildPlayerOptions {
|
||||||
|
scenes = scenes,
|
||||||
|
locationPathName = options["customBuildPath"],
|
||||||
|
target = buildTarget,
|
||||||
|
options = buildOptions,
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
subtarget = (int) buildSubtarget
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply Android settings
|
||||||
|
if (buildTarget == BuildTarget.Android) {
|
||||||
|
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
|
||||||
|
AndroidSettings.Apply(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Perform build
|
// Perform build
|
||||||
BuildReport buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
BuildReport buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||||
|
|
||||||
|
|||||||
@@ -56,17 +56,17 @@ namespace UnityBuilderAction.Input
|
|||||||
case "androidStudioProject":
|
case "androidStudioProject":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, false);
|
buildAppBundle.SetValue(null, false, null);
|
||||||
break;
|
break;
|
||||||
case "androidAppBundle":
|
case "androidAppBundle":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, true);
|
buildAppBundle.SetValue(null, true, null);
|
||||||
break;
|
break;
|
||||||
case "androidPackage":
|
case "androidPackage":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, false);
|
buildAppBundle.SetValue(null, false, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,20 @@ namespace UnityBuilderAction.Input
|
|||||||
string symbolType;
|
string symbolType;
|
||||||
if (options.TryGetValue("androidSymbolType", out symbolType) && !string.IsNullOrEmpty(symbolType))
|
if (options.TryGetValue("androidSymbolType", out symbolType) && !string.IsNullOrEmpty(symbolType))
|
||||||
{
|
{
|
||||||
#if UNITY_2021_1_OR_NEWER
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
switch (symbolType)
|
||||||
|
{
|
||||||
|
case "public":
|
||||||
|
SetDebugSymbols("SymbolTable");
|
||||||
|
break;
|
||||||
|
case "debugging":
|
||||||
|
SetDebugSymbols("Full");
|
||||||
|
break;
|
||||||
|
case "none":
|
||||||
|
SetDebugSymbols("None");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#elif UNITY_2021_1_OR_NEWER
|
||||||
switch (symbolType)
|
switch (symbolType)
|
||||||
{
|
{
|
||||||
case "public":
|
case "public":
|
||||||
@@ -101,5 +114,37 @@ namespace UnityBuilderAction.Input
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
private static void SetDebugSymbols(string enumValueName)
|
||||||
|
{
|
||||||
|
// UnityEditor.Android.UserBuildSettings and Unity.Android.Types.DebugSymbolLevel are part of the Unity Android module.
|
||||||
|
// Reflection is used here to ensure the code works even if the module is not installed.
|
||||||
|
|
||||||
|
var debugSymbolsType = Type.GetType("UnityEditor.Android.UserBuildSettings+DebugSymbols, UnityEditor.Android.Extensions");
|
||||||
|
if (debugSymbolsType == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var levelProp = debugSymbolsType.GetProperty("level", BindingFlags.Static | BindingFlags.Public);
|
||||||
|
if (levelProp == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enumType = Type.GetType("Unity.Android.Types.DebugSymbolLevel, Unity.Android.Types");
|
||||||
|
if (enumType == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Enum.TryParse(enumType, enumValueName, false , out var enumValue))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
levelProp.SetValue(null, enumValue);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,19 @@ namespace UnityBuilderAction.Input
|
|||||||
EditorApplication.Exit(110);
|
EditorApplication.Exit(110);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
var buildProfileSupport = true;
|
||||||
|
#else
|
||||||
|
var buildProfileSupport = false;
|
||||||
|
#endif // UNITY_6000_0_OR_NEWER
|
||||||
|
|
||||||
|
string buildProfile;
|
||||||
|
if (buildProfileSupport && validatedOptions.TryGetValue("activeBuildProfile", out buildProfile)) {
|
||||||
|
if (validatedOptions.ContainsKey("buildTarget")) {
|
||||||
|
Console.WriteLine("Extra argument -buildTarget");
|
||||||
|
EditorApplication.Exit(122);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
string buildTarget;
|
string buildTarget;
|
||||||
if (!validatedOptions.TryGetValue("buildTarget", out buildTarget)) {
|
if (!validatedOptions.TryGetValue("buildTarget", out buildTarget)) {
|
||||||
Console.WriteLine("Missing argument -buildTarget");
|
Console.WriteLine("Missing argument -buildTarget");
|
||||||
@@ -28,9 +41,10 @@ namespace UnityBuilderAction.Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
||||||
Console.WriteLine($"{buildTarget} is not a defined {nameof(BuildTarget)}");
|
Console.WriteLine(buildTarget + " is not a defined " + typeof(BuildTarget).Name);
|
||||||
EditorApplication.Exit(121);
|
EditorApplication.Exit(121);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string customBuildPath;
|
string customBuildPath;
|
||||||
if (!validatedOptions.TryGetValue("customBuildPath", out customBuildPath)) {
|
if (!validatedOptions.TryGetValue("customBuildPath", out customBuildPath)) {
|
||||||
@@ -41,10 +55,10 @@ namespace UnityBuilderAction.Input
|
|||||||
const string defaultCustomBuildName = "TestBuild";
|
const string defaultCustomBuildName = "TestBuild";
|
||||||
string customBuildName;
|
string customBuildName;
|
||||||
if (!validatedOptions.TryGetValue("customBuildName", out customBuildName)) {
|
if (!validatedOptions.TryGetValue("customBuildName", out customBuildName)) {
|
||||||
Console.WriteLine($"Missing argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
Console.WriteLine("Missing argument -customBuildName, defaulting to" + defaultCustomBuildName);
|
||||||
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
||||||
} else if (customBuildName == "") {
|
} else if (customBuildName == "") {
|
||||||
Console.WriteLine($"Invalid argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
Console.WriteLine("Invalid argument -customBuildName, defaulting to" + defaultCustomBuildName);
|
||||||
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,11 +71,11 @@ namespace UnityBuilderAction.Input
|
|||||||
string[] args = Environment.GetCommandLineArgs();
|
string[] args = Environment.GetCommandLineArgs();
|
||||||
|
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"{EOL}" +
|
EOL +
|
||||||
$"###########################{EOL}" +
|
"###########################" + EOL +
|
||||||
$"# Parsing settings #{EOL}" +
|
"# Parsing settings #" + EOL +
|
||||||
$"###########################{EOL}" +
|
"###########################" + EOL +
|
||||||
$"{EOL}"
|
EOL
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extract flags with optional values
|
// Extract flags with optional values
|
||||||
@@ -78,7 +92,7 @@ namespace UnityBuilderAction.Input
|
|||||||
string displayValue = secret ? "*HIDDEN*" : "\"" + value + "\"";
|
string displayValue = secret ? "*HIDDEN*" : "\"" + value + "\"";
|
||||||
|
|
||||||
// Assign
|
// Assign
|
||||||
Console.WriteLine($"Found flag \"{flag}\" with value {displayValue}.");
|
Console.WriteLine("Found flag \"" + flag + "\" with value " + displayValue);
|
||||||
providedArguments.Add(flag, value);
|
providedArguments.Add(flag, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
dist/default-build-script/Assets/Editor/UnityBuilderAction/Reporting/CompileListener.cs
vendored
Normal file
36
dist/default-build-script/Assets/Editor/UnityBuilderAction/Reporting/CompileListener.cs
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Reporting
|
||||||
|
{
|
||||||
|
[InitializeOnLoad]
|
||||||
|
static class CompileListener
|
||||||
|
{
|
||||||
|
static CompileListener()
|
||||||
|
{
|
||||||
|
if (Application.isBatchMode)
|
||||||
|
{
|
||||||
|
Application.logMessageReceived += Application_logMessageReceived;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Application_logMessageReceived(string condition, string stackTrace, LogType type)
|
||||||
|
{
|
||||||
|
string prefix = "";
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case LogType.Error:
|
||||||
|
prefix = "error";
|
||||||
|
break;
|
||||||
|
case LogType.Warning:
|
||||||
|
prefix = "warning";
|
||||||
|
break;
|
||||||
|
case LogType.Exception:
|
||||||
|
prefix = "error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Console.WriteLine(Environment.NewLine + "::" + prefix + "::" + condition + Environment.NewLine + stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
dist/default-build-script/Assets/Editor/UnityBuilderAction/Reporting/CompileListener.cs.meta
vendored
Normal file
11
dist/default-build-script/Assets/Editor/UnityBuilderAction/Reporting/CompileListener.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fad44373fb7b61a4bb584e2675795aca
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -11,16 +11,16 @@ namespace UnityBuilderAction.Reporting
|
|||||||
public static void ReportSummary(BuildSummary summary)
|
public static void ReportSummary(BuildSummary summary)
|
||||||
{
|
{
|
||||||
Console.WriteLine(
|
Console.WriteLine(
|
||||||
$"{EOL}" +
|
EOL +
|
||||||
$"###########################{EOL}" +
|
"###########################" + EOL +
|
||||||
$"# Build results #{EOL}" +
|
"# Build results #" + EOL +
|
||||||
$"###########################{EOL}" +
|
"###########################" + EOL +
|
||||||
$"{EOL}" +
|
EOL +
|
||||||
$"Duration: {summary.totalTime.ToString()}{EOL}" +
|
"Duration: " + summary.totalTime.ToString() + EOL +
|
||||||
$"Warnings: {summary.totalWarnings.ToString()}{EOL}" +
|
"Warnings: " + summary.totalWarnings.ToString() + EOL +
|
||||||
$"Errors: {summary.totalErrors.ToString()}{EOL}" +
|
"Errors: " + summary.totalErrors.ToString() + EOL +
|
||||||
$"Size: {summary.totalSize.ToString()} bytes{EOL}" +
|
"Size: " + summary.totalSize.ToString() + " bytes" + EOL +
|
||||||
$"{EOL}"
|
EOL
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ namespace UnityBuilderAction.Versioning
|
|||||||
version = GetSemanticCommitVersion();
|
version = GetSemanticCommitVersion();
|
||||||
Console.WriteLine("Repository has a valid version tag.");
|
Console.WriteLine("Repository has a valid version tag.");
|
||||||
} else {
|
} else {
|
||||||
version = $"0.0.{GetTotalNumberOfCommits()}";
|
version = "0.0." + GetTotalNumberOfCommits();
|
||||||
Console.WriteLine("Repository does not have tags to base the version on.");
|
Console.WriteLine("Repository does not have tags to base the version on.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Version is {version}");
|
Console.WriteLine("Version is " + version);
|
||||||
|
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"m_SettingKeys": [
|
|
||||||
"VR Device Disabled",
|
|
||||||
"VR Device User Alert"
|
|
||||||
],
|
|
||||||
"m_SettingValues": [
|
|
||||||
"False",
|
|
||||||
"False"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
|
||||||
# Visual Studio 2010
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp-Editor", "Assembly-CSharp-Editor.csproj", "{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B7F8614B-1EC2-9D3A-DA1C-4D279A867D74}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Untracked/@EntryIndexedValue">True</s:Boolean>
|
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Versioning/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
||||||
370500
dist/index.js
generated
vendored
370500
dist/index.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
3911
dist/licenses.txt
generated
vendored
3911
dist/licenses.txt
generated
vendored
File diff suppressed because it is too large
Load Diff
36
dist/platforms/mac/entrypoint.sh
vendored
36
dist/platforms/mac/entrypoint.sh
vendored
@@ -1,28 +1,40 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create directories for license activation
|
# Perform Activation
|
||||||
#
|
#
|
||||||
|
|
||||||
sudo mkdir /Library/Application\ Support/Unity
|
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
||||||
sudo chmod -R 777 /Library/Application\ Support/Unity
|
UNITY_LICENSE_PATH="/Library/Application Support/Unity"
|
||||||
|
|
||||||
ACTIVATE_LICENSE_PATH="$ACTION_FOLDER/BlankProject"
|
if [ ! -d "$UNITY_LICENSE_PATH" ]; then
|
||||||
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
echo "Creating Unity License Directory"
|
||||||
|
sudo mkdir -p "$UNITY_LICENSE_PATH"
|
||||||
|
sudo chmod -R 777 "$UNITY_LICENSE_PATH"
|
||||||
|
fi;
|
||||||
|
|
||||||
|
ACTIVATE_LICENSE_PATH="$ACTION_FOLDER/BlankProject"
|
||||||
|
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
|
source $ACTION_FOLDER/platforms/mac/steps/activate.sh
|
||||||
|
else
|
||||||
|
echo "Skipping activation"
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run steps
|
# Run Build
|
||||||
#
|
#
|
||||||
source $ACTION_FOLDER/platforms/mac/steps/activate.sh
|
|
||||||
source $ACTION_FOLDER/platforms/mac/steps/build.sh
|
source $ACTION_FOLDER/platforms/mac/steps/build.sh
|
||||||
source $ACTION_FOLDER/platforms/mac/steps/return_license.sh
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Remove license activation directory
|
# License Cleanup
|
||||||
#
|
#
|
||||||
|
|
||||||
sudo rm -r /Library/Application\ Support/Unity
|
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
||||||
rm -r "$ACTIVATE_LICENSE_PATH"
|
source $ACTION_FOLDER/platforms/mac/steps/return_license.sh
|
||||||
|
rm -r "$ACTIVATE_LICENSE_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Instructions for debugging
|
# Instructions for debugging
|
||||||
@@ -37,7 +49,7 @@ echo ""
|
|||||||
echo "Please note that the exit code is not very descriptive."
|
echo "Please note that the exit code is not very descriptive."
|
||||||
echo "Most likely it will not help you solve the issue."
|
echo "Most likely it will not help you solve the issue."
|
||||||
echo ""
|
echo ""
|
||||||
echo "To find the reason for failure: please search for errors in the log above."
|
echo "To find the reason for failure: please search for errors in the log above and check for annotations in the summary view."
|
||||||
echo ""
|
echo ""
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
|||||||
75
dist/platforms/mac/steps/activate.sh
vendored
75
dist/platforms/mac/steps/activate.sh
vendored
@@ -4,21 +4,69 @@
|
|||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
pushd "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
echo "Requesting activation"
|
if [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
||||||
|
#
|
||||||
|
# SERIAL LICENSE MODE
|
||||||
|
#
|
||||||
|
# This will activate unity, using the serial activation process.
|
||||||
|
#
|
||||||
|
|
||||||
# Activate license
|
echo "Requesting activation"
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
|
||||||
-logFile - \
|
|
||||||
-batchmode \
|
|
||||||
-nographics \
|
|
||||||
-quit \
|
|
||||||
-serial "$UNITY_SERIAL" \
|
|
||||||
-username "$UNITY_EMAIL" \
|
|
||||||
-password "$UNITY_PASSWORD" \
|
|
||||||
-projectPath "$ACTIVATE_LICENSE_PATH"
|
|
||||||
|
|
||||||
# Store the exit code from the verify command
|
# Activate license
|
||||||
UNITY_EXIT_CODE=$?
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
|
-logFile - \
|
||||||
|
-batchmode \
|
||||||
|
-nographics \
|
||||||
|
-quit \
|
||||||
|
-serial "$UNITY_SERIAL" \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
|
-projectPath "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
|
# Store the exit code from the verify command
|
||||||
|
UNITY_EXIT_CODE=$?
|
||||||
|
|
||||||
|
elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||||
|
#
|
||||||
|
# Custom Unity License Server
|
||||||
|
#
|
||||||
|
echo "Adding licensing server config"
|
||||||
|
mkdir -p "$UNITY_LICENSE_PATH/config/"
|
||||||
|
cp "$ACTION_FOLDER/unity-config/services-config.json" "$UNITY_LICENSE_PATH/config/services-config.json"
|
||||||
|
|
||||||
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/Frameworks/UnityLicensingClient.app/Contents/MacOS/Unity.Licensing.Client \
|
||||||
|
--acquire-floating > license.txt
|
||||||
|
|
||||||
|
# Store the exit code from the verify command
|
||||||
|
UNITY_EXIT_CODE=$?
|
||||||
|
|
||||||
|
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
||||||
|
PARSEDFILE=$(grep -oE '\"[^"]*\"' < license.txt | tr -d '"')
|
||||||
|
export FLOATING_LICENSE
|
||||||
|
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
||||||
|
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
||||||
|
|
||||||
|
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
||||||
|
fi
|
||||||
|
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://game.ci/docs/github/activation for more"
|
||||||
|
echo "details on how to set up one of the possible activation strategies."
|
||||||
|
|
||||||
|
echo "::error ::No valid license activation strategy could be determined. Make sure to provide UNITY_EMAIL, UNITY_PASSWORD, and either a UNITY_SERIAL \
|
||||||
|
or UNITY_LICENSE. Otherwise please use UNITY_LICENSING_SERVER. See more info at https://game.ci/docs/github/activation"
|
||||||
|
|
||||||
|
# Immediately exit as no UNITY_EXIT_CODE can be derived.
|
||||||
|
exit 1;
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Display information about the result
|
# Display information about the result
|
||||||
@@ -30,6 +78,7 @@ else
|
|||||||
# Activation failed so exit with the code from the license verification step
|
# Activation failed so exit with the code from the license verification step
|
||||||
echo "Unclassified error occured while trying to activate license."
|
echo "Unclassified error occured while trying to activate license."
|
||||||
echo "Exit code was: $UNITY_EXIT_CODE"
|
echo "Exit code was: $UNITY_EXIT_CODE"
|
||||||
|
echo "::error ::There was an error while trying to activate the Unity license."
|
||||||
exit $UNITY_EXIT_CODE
|
exit $UNITY_EXIT_CODE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
27
dist/platforms/mac/steps/build.sh
vendored
27
dist/platforms/mac/steps/build.sh
vendored
@@ -19,6 +19,23 @@ echo "Using build name \"$BUILD_NAME\"."
|
|||||||
|
|
||||||
echo "Using build target \"$BUILD_TARGET\"."
|
echo "Using build target \"$BUILD_TARGET\"."
|
||||||
|
|
||||||
|
#
|
||||||
|
# Display the build profile
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ -z "$BUILD_PROFILE" ]; then
|
||||||
|
# User has not provided a build profile
|
||||||
|
#
|
||||||
|
echo "Doing a default \"$BUILD_TARGET\" platform build."
|
||||||
|
#
|
||||||
|
else
|
||||||
|
# User has provided a path to a build profile `.asset` file
|
||||||
|
#
|
||||||
|
echo "Using build profile \"$BUILD_PROFILE\" relative to \"$UNITY_PROJECT_PATH\"."
|
||||||
|
#
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Display build path and file
|
# Display build path and file
|
||||||
#
|
#
|
||||||
@@ -129,16 +146,16 @@ echo ""
|
|||||||
|
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
-logFile - \
|
-logFile - \
|
||||||
-quit \
|
$( [ "${MANUAL_EXIT}" == "true" ] || echo "-quit" ) \
|
||||||
-batchmode \
|
-batchmode \
|
||||||
-nographics \
|
$( [ "${ENABLE_GPU}" == "true" ] || echo "-nographics" ) \
|
||||||
-username "$UNITY_EMAIL" \
|
|
||||||
-password "$UNITY_PASSWORD" \
|
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
-projectPath "$UNITY_PROJECT_PATH" \
|
-projectPath "$UNITY_PROJECT_PATH" \
|
||||||
-buildTarget "$BUILD_TARGET" \
|
$( [ -z "$BUILD_PROFILE" ] && echo "-buildTarget $BUILD_TARGET") \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
|
-customBuildProfile "$BUILD_PROFILE" \
|
||||||
|
${BUILD_PROFILE:+-activeBuildProfile} ${BUILD_PROFILE:+"$BUILD_PROFILE"} \
|
||||||
-executeMethod "$BUILD_METHOD" \
|
-executeMethod "$BUILD_METHOD" \
|
||||||
-buildVersion "$VERSION" \
|
-buildVersion "$VERSION" \
|
||||||
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
||||||
|
|||||||
32
dist/platforms/mac/steps/return_license.sh
vendored
32
dist/platforms/mac/steps/return_license.sh
vendored
@@ -4,15 +4,29 @@
|
|||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
pushd "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||||
-logFile - \
|
#
|
||||||
-batchmode \
|
# Return any floating license used.
|
||||||
-nographics \
|
#
|
||||||
-quit \
|
echo "Returning floating license: \"$FLOATING_LICENSE\""
|
||||||
-username "$UNITY_EMAIL" \
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/Frameworks/UnityLicensingClient.app/Contents/MacOS/Unity.Licensing.Client \
|
||||||
-password "$UNITY_PASSWORD" \
|
--return-floating "$FLOATING_LICENSE"
|
||||||
-returnlicense \
|
elif [[ -n "$UNITY_SERIAL" ]]; then
|
||||||
-projectPath "$ACTIVATE_LICENSE_PATH"
|
#
|
||||||
|
# SERIAL LICENSE MODE
|
||||||
|
#
|
||||||
|
# This will return the license that is currently in use.
|
||||||
|
#
|
||||||
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
|
-logFile - \
|
||||||
|
-batchmode \
|
||||||
|
-nographics \
|
||||||
|
-quit \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
|
-returnlicense \
|
||||||
|
-projectPath "$ACTIVATE_LICENSE_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
# Return to previous working directory
|
# Return to previous working directory
|
||||||
popd
|
popd
|
||||||
|
|||||||
109
dist/platforms/ubuntu/entrypoint.sh
vendored
109
dist/platforms/ubuntu/entrypoint.sh
vendored
@@ -1,46 +1,83 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
# Ensure machine ID is randomized for personal license activation
|
||||||
# Create directory for license activation
|
if [[ "$UNITY_SERIAL" = F* ]]; then
|
||||||
#
|
echo "Randomizing machine ID for personal license activation"
|
||||||
|
dbus-uuidgen > /etc/machine-id && mkdir -p /var/lib/dbus/ && ln -sf /etc/machine-id /var/lib/dbus/machine-id
|
||||||
ACTIVATE_LICENSE_PATH="$GITHUB_WORKSPACE/_activate-license~"
|
fi
|
||||||
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run steps
|
# Prepare Android SDK, if needed
|
||||||
#
|
# We do this here to ensure it has root permissions
|
||||||
source /steps/set_extra_git_configs.sh
|
|
||||||
source /steps/set_gitcredential.sh
|
|
||||||
source /steps/activate.sh
|
|
||||||
source /steps/build.sh
|
|
||||||
source /steps/return_license.sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Remove license activation directory
|
|
||||||
#
|
#
|
||||||
|
|
||||||
rm -r "$ACTIVATE_LICENSE_PATH"
|
fullProjectPath="$GITHUB_WORKSPACE/$PROJECT_PATH"
|
||||||
|
|
||||||
#
|
if [[ "$BUILD_TARGET" == "Android" ]]; then
|
||||||
# Instructions for debugging
|
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
|
||||||
#
|
ANDROID_HOME_DIRECTORY="$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
|
||||||
|
SDKMANAGER=$(find $ANDROID_HOME_DIRECTORY/cmdline-tools -name sdkmanager)
|
||||||
|
if [ -z "${SDKMANAGER}" ]
|
||||||
|
then
|
||||||
|
SDKMANAGER=$(find $ANDROID_HOME_DIRECTORY/tools/bin -name sdkmanager)
|
||||||
|
if [ -z "${SDKMANAGER}" ]
|
||||||
|
then
|
||||||
|
echo "No sdkmanager found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $BUILD_EXIT_CODE -gt 0 ]]; then
|
if [[ -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
|
||||||
echo ""
|
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
|
||||||
echo "###########################"
|
$SDKMANAGER "$ANDROID_SDK_MANAGER_PARAMETERS"
|
||||||
echo "# Failure #"
|
else
|
||||||
echo "###########################"
|
echo "Updating Android SDK with auto detected target API version"
|
||||||
echo ""
|
# Read the line containing AndroidTargetSdkVersion from the file
|
||||||
echo "Please note that the exit code is not very descriptive."
|
targetAPILine=$(grep 'AndroidTargetSdkVersion' "$fullProjectPath/ProjectSettings/ProjectSettings.asset")
|
||||||
echo "Most likely it will not help you solve the issue."
|
|
||||||
echo ""
|
|
||||||
echo "To find the reason for failure: please search for errors in the log above."
|
|
||||||
echo ""
|
|
||||||
fi;
|
|
||||||
|
|
||||||
#
|
# Extract the number after the semicolon
|
||||||
# Exit with code from the build step.
|
targetAPI=$(echo "$targetAPILine" | cut -d':' -f2 | tr -d '[:space:]')
|
||||||
#
|
|
||||||
|
|
||||||
exit $BUILD_EXIT_CODE
|
$SDKMANAGER "platforms;android-$targetAPI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updated Android SDK."
|
||||||
|
else
|
||||||
|
echo "Not updating Android SDK."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$RUN_AS_HOST_USER" == "true" ]]; then
|
||||||
|
echo "Running as host user"
|
||||||
|
|
||||||
|
# Stop on error if we can't set up the user
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get host user/group info so we create files with the correct ownership
|
||||||
|
USERNAME=$(stat -c '%U' "$fullProjectPath")
|
||||||
|
USERID=$(stat -c '%u' "$fullProjectPath")
|
||||||
|
GROUPNAME=$(stat -c '%G' "$fullProjectPath")
|
||||||
|
GROUPID=$(stat -c '%g' "$fullProjectPath")
|
||||||
|
|
||||||
|
groupadd -g $GROUPID $GROUPNAME
|
||||||
|
useradd -u $USERID -g $GROUPID $USERNAME
|
||||||
|
usermod -aG $GROUPNAME $USERNAME
|
||||||
|
mkdir -p "/home/$USERNAME"
|
||||||
|
chown $USERNAME:$GROUPNAME "/home/$USERNAME"
|
||||||
|
|
||||||
|
# Normally need root permissions to access when using su
|
||||||
|
chmod 777 /dev/stdout
|
||||||
|
chmod 777 /dev/stderr
|
||||||
|
|
||||||
|
# Don't stop on error when running our scripts as error handling is baked in
|
||||||
|
set +e
|
||||||
|
|
||||||
|
# Switch to the host user so we can create files with the correct ownership
|
||||||
|
su $USERNAME -c "$SHELL -c 'source /steps/runsteps.sh'"
|
||||||
|
else
|
||||||
|
echo "Running as root"
|
||||||
|
|
||||||
|
# Run as root
|
||||||
|
source /steps/runsteps.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $?
|
||||||
|
|||||||
130
dist/platforms/ubuntu/steps/activate.sh
vendored
130
dist/platforms/ubuntu/steps/activate.sh
vendored
@@ -1,78 +1,65 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Run in ACTIVATE_LICENSE_PATH directory
|
# if blankproject folder doesn't exist create it
|
||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
if [ ! -d "/BlankProject" ]; then
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
mkdir /BlankProject
|
||||||
|
fi
|
||||||
|
# if blankproject folder doesn't exist create it
|
||||||
|
if [ ! -d "/BlankProject/Assets" ]; then
|
||||||
|
mkdir /BlankProject/Assets
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
if [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
||||||
#
|
#
|
||||||
# PERSONAL LICENSE MODE
|
# SERIAL LICENSE MODE
|
||||||
#
|
#
|
||||||
# This will activate Unity, using a license file
|
# This will activate unity, using the serial activation process.
|
||||||
#
|
#
|
||||||
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
|
echo "Requesting activation"
|
||||||
# * 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
|
# Loop the unity-editor call until the license is activated with exponential backoff and a maximum of 5 retries
|
||||||
FILE_PATH=UnityLicenseFile.ulf
|
retry_count=0
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSE" ]]; then
|
# Initialize delay to 15 seconds
|
||||||
# Copy license file from Github variables
|
delay=15
|
||||||
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
|
|
||||||
elif [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
|
||||||
# Copy license file from file system
|
|
||||||
cat "$UNITY_LICENSE_FILE" | tr -d '\r' > $FILE_PATH
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Activate license
|
# Loop until UNITY_EXIT_CODE is 0 or retry count reaches 5
|
||||||
ACTIVATION_OUTPUT=$(unity-editor \
|
while [[ $retry_count -lt 5 ]]
|
||||||
|
do
|
||||||
|
# Activate license
|
||||||
|
unity-editor \
|
||||||
-logFile /dev/stdout \
|
-logFile /dev/stdout \
|
||||||
-quit \
|
-quit \
|
||||||
-manualLicenseFile $FILE_PATH)
|
-serial "$UNITY_SERIAL" \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
|
-projectPath "/BlankProject"
|
||||||
|
|
||||||
# Store the exit code from the verify command
|
# Store the exit code from the verify command
|
||||||
UNITY_EXIT_CODE=$?
|
UNITY_EXIT_CODE=$?
|
||||||
|
|
||||||
# The exit code for personal activation is always 1;
|
# Check if UNITY_EXIT_CODE is 0
|
||||||
# Determine whether activation was successful.
|
if [[ $UNITY_EXIT_CODE -eq 0 ]]
|
||||||
#
|
then
|
||||||
# Successful output should include the following:
|
echo "Activation successful"
|
||||||
#
|
break
|
||||||
# "LICENSE SYSTEM [2020120 18:51:20] Next license update check is after 2019-11-25T18:23:38"
|
else
|
||||||
#
|
# Increment retry count
|
||||||
ACTIVATION_SUCCESSFUL=$(echo $ACTIVATION_OUTPUT | grep 'Next license update check is after' | wc -l)
|
((retry_count++))
|
||||||
|
|
||||||
# Set exit code to 0 if activation was successful
|
echo "::warning ::Activation failed, attempting retry #$retry_count"
|
||||||
if [[ $ACTIVATION_SUCCESSFUL -eq 1 ]]; then
|
echo "Activation failed, retrying in $delay seconds..."
|
||||||
UNITY_EXIT_CODE=0
|
sleep $delay
|
||||||
fi;
|
|
||||||
|
|
||||||
# Remove license file
|
# Double the delay for the next iteration
|
||||||
rm -f $FILE_PATH
|
delay=$((delay * 2))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
if [[ $retry_count -eq 5 ]]
|
||||||
#
|
then
|
||||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
echo "Activation failed after 5 retries"
|
||||||
#
|
fi
|
||||||
# This will activate unity, using the activating process.
|
|
||||||
#
|
|
||||||
# Note: This is the preferred way for PROFESSIONAL LICENSES.
|
|
||||||
#
|
|
||||||
echo "Requesting activation (professional license)"
|
|
||||||
|
|
||||||
# Activate license
|
|
||||||
unity-editor \
|
|
||||||
-logFile /dev/stdout \
|
|
||||||
-quit \
|
|
||||||
-serial "$UNITY_SERIAL" \
|
|
||||||
-username "$UNITY_EMAIL" \
|
|
||||||
-password "$UNITY_PASSWORD"
|
|
||||||
|
|
||||||
# Store the exit code from the verify command
|
|
||||||
UNITY_EXIT_CODE=$?
|
|
||||||
|
|
||||||
elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||||
#
|
#
|
||||||
@@ -81,14 +68,18 @@ elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
|||||||
echo "Adding licensing server config"
|
echo "Adding licensing server config"
|
||||||
|
|
||||||
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --acquire-floating > license.txt #is this accessible in a env variable?
|
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --acquire-floating > license.txt #is this accessible in a env variable?
|
||||||
PARSEDFILE=$(grep -oP '\".*?\"' < license.txt | tr -d '"')
|
|
||||||
export FLOATING_LICENSE
|
|
||||||
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
|
||||||
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
|
||||||
|
|
||||||
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
|
||||||
# Store the exit code from the verify command
|
# Store the exit code from the verify command
|
||||||
UNITY_EXIT_CODE=$?
|
UNITY_EXIT_CODE=$?
|
||||||
|
|
||||||
|
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
||||||
|
PARSEDFILE=$(grep -oP '\".*?\"' < license.txt | tr -d '"')
|
||||||
|
export FLOATING_LICENSE
|
||||||
|
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
||||||
|
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
||||||
|
|
||||||
|
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
#
|
#
|
||||||
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||||
@@ -97,10 +88,13 @@ else
|
|||||||
#
|
#
|
||||||
echo "License activation strategy could not be determined."
|
echo "License activation strategy could not be determined."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Visit https://game.ci/docs/github/getting-started for more"
|
echo "Visit https://game.ci/docs/github/activation for more"
|
||||||
echo "details on how to set up one of the possible activation strategies."
|
echo "details on how to set up one of the possible activation strategies."
|
||||||
|
|
||||||
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
|
echo "::error ::No valid license activation strategy could be determined. Make sure to provide UNITY_EMAIL, UNITY_PASSWORD, and either a UNITY_SERIAL \
|
||||||
|
or UNITY_LICENSE. Otherwise please use UNITY_LICENSING_SERVER. See more info at https://game.ci/docs/github/activation"
|
||||||
|
|
||||||
|
# Immediately exit as no UNITY_EXIT_CODE can be derived.
|
||||||
exit 1;
|
exit 1;
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@@ -115,8 +109,6 @@ else
|
|||||||
# Activation failed so exit with the code from the license verification step
|
# Activation failed so exit with the code from the license verification step
|
||||||
echo "Unclassified error occured while trying to activate license."
|
echo "Unclassified error occured while trying to activate license."
|
||||||
echo "Exit code was: $UNITY_EXIT_CODE"
|
echo "Exit code was: $UNITY_EXIT_CODE"
|
||||||
|
echo "::error ::There was an error while trying to activate the Unity license."
|
||||||
exit $UNITY_EXIT_CODE
|
exit $UNITY_EXIT_CODE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Return to previous working directory
|
|
||||||
popd
|
|
||||||
|
|||||||
35
dist/platforms/ubuntu/steps/build.sh
vendored
35
dist/platforms/ubuntu/steps/build.sh
vendored
@@ -19,6 +19,22 @@ echo "Using build name \"$BUILD_NAME\"."
|
|||||||
|
|
||||||
echo "Using build target \"$BUILD_TARGET\"."
|
echo "Using build target \"$BUILD_TARGET\"."
|
||||||
|
|
||||||
|
#
|
||||||
|
# Display the build profile
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ -z "$BUILD_PROFILE" ]; then
|
||||||
|
# User has not provided a build profile
|
||||||
|
#
|
||||||
|
echo "Doing a default \"$BUILD_TARGET\" platform build."
|
||||||
|
#
|
||||||
|
else
|
||||||
|
# User has provided a path to a build profile `.asset` file
|
||||||
|
#
|
||||||
|
echo "Using build profile \"$BUILD_PROFILE\" relative to \"$UNITY_PROJECT_PATH\"."
|
||||||
|
#
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Display build path and file
|
# Display build path and file
|
||||||
#
|
#
|
||||||
@@ -62,19 +78,6 @@ else
|
|||||||
#
|
#
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
|
||||||
# Prepare Android SDK, if needed
|
|
||||||
#
|
|
||||||
|
|
||||||
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
|
|
||||||
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
|
|
||||||
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
|
|
||||||
"$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)/tools/bin/sdkmanager" "$ANDROID_SDK_MANAGER_PARAMETERS"
|
|
||||||
echo "Updated Android SDK."
|
|
||||||
else
|
|
||||||
echo "Not updating Android SDK."
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Pre-build debug information
|
# Pre-build debug information
|
||||||
#
|
#
|
||||||
@@ -119,12 +122,14 @@ echo ""
|
|||||||
|
|
||||||
unity-editor \
|
unity-editor \
|
||||||
-logfile /dev/stdout \
|
-logfile /dev/stdout \
|
||||||
-quit \
|
$( [ "${MANUAL_EXIT}" == "true" ] || echo "-quit" ) \
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
-projectPath "$UNITY_PROJECT_PATH" \
|
-projectPath "$UNITY_PROJECT_PATH" \
|
||||||
-buildTarget "$BUILD_TARGET" \
|
$( [ -z "$BUILD_PROFILE" ] && echo "-buildTarget $BUILD_TARGET" ) \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
|
-customBuildProfile "$BUILD_PROFILE" \
|
||||||
|
${BUILD_PROFILE:+-activeBuildProfile} ${BUILD_PROFILE:+"$BUILD_PROFILE"} \
|
||||||
-executeMethod "$BUILD_METHOD" \
|
-executeMethod "$BUILD_METHOD" \
|
||||||
-buildVersion "$VERSION" \
|
-buildVersion "$VERSION" \
|
||||||
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
||||||
|
|||||||
17
dist/platforms/ubuntu/steps/return_license.sh
vendored
17
dist/platforms/ubuntu/steps/return_license.sh
vendored
@@ -1,11 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Run in ACTIVATE_LICENSE_PATH directory
|
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then #
|
|
||||||
#
|
#
|
||||||
# Return any floating license used.
|
# Return any floating license used.
|
||||||
#
|
#
|
||||||
@@ -13,15 +8,15 @@ if [[ -n "$UNITY_LICENSING_SERVER" ]]; then #
|
|||||||
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --return-floating "$FLOATING_LICENSE"
|
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --return-floating "$FLOATING_LICENSE"
|
||||||
elif [[ -n "$UNITY_SERIAL" ]]; then
|
elif [[ -n "$UNITY_SERIAL" ]]; then
|
||||||
#
|
#
|
||||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
# SERIAL LICENSE MODE
|
||||||
#
|
#
|
||||||
# This will return the license that is currently in use.
|
# This will return the license that is currently in use.
|
||||||
#
|
#
|
||||||
unity-editor \
|
unity-editor \
|
||||||
-logFile /dev/stdout \
|
-logFile /dev/stdout \
|
||||||
-quit \
|
-quit \
|
||||||
-returnlicense
|
-returnlicense \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
|
-projectPath "/BlankProject"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Return to previous working directory
|
|
||||||
popd
|
|
||||||
|
|||||||
48
dist/platforms/ubuntu/steps/runsteps.sh
vendored
Normal file
48
dist/platforms/ubuntu/steps/runsteps.sh
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Run steps
|
||||||
|
#
|
||||||
|
source /steps/set_extra_git_configs.sh
|
||||||
|
source /steps/set_gitcredential.sh
|
||||||
|
|
||||||
|
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
||||||
|
source /steps/activate.sh
|
||||||
|
|
||||||
|
# If we didn't activate successfully, exit with the exit code from the activation step.
|
||||||
|
if [[ $UNITY_EXIT_CODE -ne 0 ]]; then
|
||||||
|
exit $UNITY_EXIT_CODE
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Skipping activation"
|
||||||
|
fi
|
||||||
|
|
||||||
|
source /steps/build.sh
|
||||||
|
|
||||||
|
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
||||||
|
source /steps/return_license.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Instructions for debugging
|
||||||
|
#
|
||||||
|
|
||||||
|
if [[ $BUILD_EXIT_CODE -gt 0 ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "###########################"
|
||||||
|
echo "# Failure #"
|
||||||
|
echo "###########################"
|
||||||
|
echo ""
|
||||||
|
echo "Please note that the exit code is not very descriptive."
|
||||||
|
echo "Most likely it will not help you solve the issue."
|
||||||
|
echo ""
|
||||||
|
echo "To find the reason for failure: please search for errors in the log above and check for annotations in the summary view."
|
||||||
|
echo ""
|
||||||
|
fi;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Exit with code from the build step.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Exiting su
|
||||||
|
exit $BUILD_EXIT_CODE
|
||||||
98
dist/platforms/windows/activate.ps1
vendored
98
dist/platforms/windows/activate.ps1
vendored
@@ -1,7 +1,93 @@
|
|||||||
# Activates Unity
|
# Activates Unity
|
||||||
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -nographics `
|
|
||||||
-username $Env:UNITY_EMAIL `
|
Write-Output ""
|
||||||
-password $Env:UNITY_PASSWORD `
|
Write-Output "###########################"
|
||||||
-serial $Env:UNITY_SERIAL `
|
Write-Output "# Activating #"
|
||||||
-projectPath "c:/BlankProject" `
|
Write-Output "###########################"
|
||||||
-logfile | Out-Host
|
Write-Output ""
|
||||||
|
|
||||||
|
if ( ($null -ne ${env:UNITY_SERIAL}) -and ($null -ne ${env:UNITY_EMAIL}) -and ($null -ne ${env:UNITY_PASSWORD}) )
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# SERIAL LICENSE MODE
|
||||||
|
#
|
||||||
|
# This will activate unity, using the serial activation process.
|
||||||
|
#
|
||||||
|
Write-Output "Requesting activation"
|
||||||
|
|
||||||
|
$ACTIVATION_OUTPUT = Start-Process -FilePath "$Env:UNITY_PATH/Editor/Unity.exe" `
|
||||||
|
-NoNewWindow `
|
||||||
|
-PassThru `
|
||||||
|
-ArgumentList "-batchmode `
|
||||||
|
-quit `
|
||||||
|
-nographics `
|
||||||
|
-username $Env:UNITY_EMAIL `
|
||||||
|
-password $Env:UNITY_PASSWORD `
|
||||||
|
-serial $Env:UNITY_SERIAL `
|
||||||
|
-projectPath c:/BlankProject `
|
||||||
|
-logfile -"
|
||||||
|
|
||||||
|
# Cache the handle so exit code works properly
|
||||||
|
# https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
|
||||||
|
$unityHandle = $ACTIVATION_OUTPUT.Handle
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
if ($ACTIVATION_OUTPUT.HasExited) {
|
||||||
|
$ACTIVATION_EXIT_CODE = $ACTIVATION_OUTPUT.ExitCode
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
if ($ACTIVATION_EXIT_CODE -eq 0)
|
||||||
|
{
|
||||||
|
Write-Output "Activation Succeeded"
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Write-Output "Activation failed, with exit code $ACTIVATION_EXIT_CODE"
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif( ($null -ne ${env:UNITY_LICENSING_SERVER}))
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# Custom Unity License Server
|
||||||
|
#
|
||||||
|
|
||||||
|
Write-Output "Adding licensing server config"
|
||||||
|
|
||||||
|
$ACTIVATION_OUTPUT = Start-Process -FilePath "$Env:UNITY_PATH\Editor\Data\Resources\Licensing\Client\Unity.Licensing.Client.exe" `
|
||||||
|
-ArgumentList "--acquire-floating" `
|
||||||
|
-NoNewWindow `
|
||||||
|
-PassThru `
|
||||||
|
-Wait `
|
||||||
|
-RedirectStandardOutput "license.txt"
|
||||||
|
|
||||||
|
$PARSEDFILE = (Get-Content "license.txt" | Select-String -AllMatches -Pattern '\".*?\"' | ForEach-Object { $_.Matches.Value }) -replace '"'
|
||||||
|
|
||||||
|
$env:FLOATING_LICENSE = $PARSEDFILE[1]
|
||||||
|
$FLOATING_LICENSE_TIMEOUT = $PARSEDFILE[3]
|
||||||
|
|
||||||
|
Write-Output "Acquired floating license: ""$env:FLOATING_LICENSE"" with timeout $FLOATING_LICENSE_TIMEOUT"
|
||||||
|
# Store the exit code from the verify command
|
||||||
|
$ACTIVATION_EXIT_CODE = $ACTIVATION_OUTPUT.ExitCode
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||||
|
#
|
||||||
|
# This will exit since no activation strategies could be matched.
|
||||||
|
#
|
||||||
|
Write-Output "License activation strategy could not be determined."
|
||||||
|
Write-Output ""
|
||||||
|
Write-Output "Visit https://game.ci/docs/github/activation for more"
|
||||||
|
Write-Output "details on how to set up one of the possible activation strategies."
|
||||||
|
|
||||||
|
Write-Output "::error ::No valid license activation strategy could be determined. Make sure to provide UNITY_EMAIL, UNITY_PASSWORD, and either a UNITY_SERIAL \
|
||||||
|
or UNITY_LICENSE. See more info at https://game.ci/docs/github/activation"
|
||||||
|
|
||||||
|
$ACTIVATION_EXIT_CODE = 1;
|
||||||
|
}
|
||||||
|
|||||||
150
dist/platforms/windows/build.ps1
vendored
150
dist/platforms/windows/build.ps1
vendored
@@ -16,6 +16,25 @@ Write-Output "$('Using build name "')$($Env:BUILD_NAME)$('".')"
|
|||||||
|
|
||||||
Write-Output "$('Using build target "')$($Env:BUILD_TARGET)$('".')"
|
Write-Output "$('Using build target "')$($Env:BUILD_TARGET)$('".')"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Display the build profile
|
||||||
|
#
|
||||||
|
|
||||||
|
if ($Env:BUILD_PROFILE)
|
||||||
|
{
|
||||||
|
# User has provided a path to a build profile `.asset` file
|
||||||
|
#
|
||||||
|
Write-Output "$('Using build profile "')$($Env:BUILD_PROFILE)$('" relative to "')$($Env:UNITY_PROJECT_PATH)$('".')"
|
||||||
|
#
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# User has not provided a build profile
|
||||||
|
#
|
||||||
|
Write-Output "$('Doing a default "')$($Env:BUILD_TARGET)$('" platform build.')"
|
||||||
|
#
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Display build path and file
|
# Display build path and file
|
||||||
#
|
#
|
||||||
@@ -66,6 +85,26 @@ else
|
|||||||
Get-ChildItem -Path $Env:UNITY_PROJECT_PATH\Assets\Editor -Recurse
|
Get-ChildItem -Path $Env:UNITY_PROJECT_PATH\Assets\Editor -Recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( "$Env:BUILD_TARGET" -eq "Android" -and -not ([string]::IsNullOrEmpty("$Env:ANDROID_KEYSTORE_BASE64")) )
|
||||||
|
{
|
||||||
|
Write-Output "Creating Android keystore."
|
||||||
|
|
||||||
|
# Write to consistent location as Windows Unity seems to have issues with pwd and can't find the keystore
|
||||||
|
$keystorePath = "C:/android.keystore"
|
||||||
|
[System.IO.File]::WriteAllBytes($keystorePath, [System.Convert]::FromBase64String($Env:ANDROID_KEYSTORE_BASE64))
|
||||||
|
|
||||||
|
# Ensure the project settings are pointed at the correct path
|
||||||
|
$unitySettingsPath = "$Env:UNITY_PROJECT_PATH\ProjectSettings\ProjectSettings.asset"
|
||||||
|
$fileContent = Get-Content -Path "$unitySettingsPath"
|
||||||
|
$fileContent = $fileContent -replace "AndroidKeystoreName:\s+.*", "AndroidKeystoreName: $keystorePath"
|
||||||
|
$fileContent | Set-Content -Path "$unitySettingsPath"
|
||||||
|
|
||||||
|
Write-Output "Created Android keystore."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Output "Not creating Android keystore."
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Pre-build debug information
|
# Pre-build debug information
|
||||||
#
|
#
|
||||||
@@ -109,51 +148,84 @@ Write-Output "# Building project #"
|
|||||||
Write-Output "###########################"
|
Write-Output "###########################"
|
||||||
Write-Output ""
|
Write-Output ""
|
||||||
|
|
||||||
|
$unityGraphics = "-nographics"
|
||||||
|
|
||||||
|
if ($LLVMPIPE_INSTALLED -eq "true")
|
||||||
|
{
|
||||||
|
$unityGraphics = "-force-opengl"
|
||||||
|
}
|
||||||
|
|
||||||
# If $Env:CUSTOM_PARAMETERS contains spaces and is passed directly on the command line to Unity, powershell will wrap it
|
# If $Env:CUSTOM_PARAMETERS contains spaces and is passed directly on the command line to Unity, powershell will wrap it
|
||||||
# in double quotes. To avoid this, parse $Env:CUSTOM_PARAMETERS into an array, while respecting any quotations within the string.
|
# in double quotes. To avoid this, parse $Env:CUSTOM_PARAMETERS into an array, while respecting any quotations within the string.
|
||||||
$_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUSTOM_PARAMETERS)
|
$_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUSTOM_PARAMETERS)
|
||||||
|
$unityArgs = @(
|
||||||
|
"-quit",
|
||||||
|
"-batchmode",
|
||||||
|
$unityGraphics,
|
||||||
|
"-silent-crashes",
|
||||||
|
"-customBuildName", "`"$Env:BUILD_NAME`"",
|
||||||
|
"-projectPath", "`"$Env:UNITY_PROJECT_PATH`"",
|
||||||
|
"-executeMethod", "`"$Env:BUILD_METHOD`"",
|
||||||
|
"-customBuildTarget", "`"$Env:BUILD_TARGET`"",
|
||||||
|
"-customBuildPath", "`"$Env:CUSTOM_BUILD_PATH`"",
|
||||||
|
"-customBuildProfile", "`"$Env:BUILD_PROFILE`"",
|
||||||
|
"-buildVersion", "`"$Env:VERSION`"",
|
||||||
|
"-androidVersionCode", "`"$Env:ANDROID_VERSION_CODE`"",
|
||||||
|
"-androidKeystorePass", "`"$Env:ANDROID_KEYSTORE_PASS`"",
|
||||||
|
"-androidKeyaliasName", "`"$Env:ANDROID_KEYALIAS_NAME`"",
|
||||||
|
"-androidKeyaliasPass", "`"$Env:ANDROID_KEYALIAS_PASS`"",
|
||||||
|
"-androidTargetSdkVersion", "`"$Env:ANDROID_TARGET_SDK_VERSION`"",
|
||||||
|
"-androidExportType", "`"$Env:ANDROID_EXPORT_TYPE`"",
|
||||||
|
"-androidSymbolType", "`"$Env:ANDROID_SYMBOL_TYPE`"",
|
||||||
|
"-logfile", "-"
|
||||||
|
) + $customParametersArray
|
||||||
|
|
||||||
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -quit -batchmode -nographics `
|
if (-not $Env:BUILD_PROFILE) {
|
||||||
-projectPath $Env:UNITY_PROJECT_PATH `
|
$unityArgs += @("-buildTarget", "`"$Env:BUILD_TARGET`"")
|
||||||
-executeMethod $Env:BUILD_METHOD `
|
}
|
||||||
-buildTarget $Env:BUILD_TARGET `
|
if ($Env:BUILD_PROFILE) {
|
||||||
-customBuildTarget $Env:BUILD_TARGET `
|
$unityArgs += @("-activeBuildProfile", "`"$Env:BUILD_PROFILE`"")
|
||||||
-customBuildPath $Env:CUSTOM_BUILD_PATH `
|
|
||||||
-buildVersion $Env:VERSION `
|
|
||||||
-androidVersionCode $Env:ANDROID_VERSION_CODE `
|
|
||||||
-androidKeystoreName $Env:ANDROID_KEYSTORE_NAME `
|
|
||||||
-androidKeystorePass $Env:ANDROID_KEYSTORE_PASS `
|
|
||||||
-androidKeyaliasName $Env:ANDROID_KEYALIAS_NAME `
|
|
||||||
-androidKeyaliasPass $Env:ANDROID_KEYALIAS_PASS `
|
|
||||||
-androidTargetSdkVersion $Env:ANDROID_TARGET_SDK_VERSION `
|
|
||||||
-androidExportType $Env:ANDROID_EXPORT_TYPE `
|
|
||||||
-androidSymbolType $Env:ANDROID_SYMBOL_TYPE `
|
|
||||||
$customParametersArray `
|
|
||||||
-logfile | Out-Host
|
|
||||||
|
|
||||||
# Catch exit code
|
|
||||||
$Env:BUILD_EXIT_CODE=$LastExitCode
|
|
||||||
|
|
||||||
# Display results
|
|
||||||
if ($Env:BUILD_EXIT_CODE -eq 0)
|
|
||||||
{
|
|
||||||
Write-Output "Build Succeeded!"
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
Write-Output "$('Build failed, with exit code ')$($Env:BUILD_EXIT_CODE)$('"')"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Determine if we need to set permissions on any files
|
# Remove null items as that will fail the Start-Process call
|
||||||
|
$unityArgs = $unityArgs | Where-Object { $_ -ne $null }
|
||||||
|
|
||||||
#
|
$unityProcess = Start-Process -FilePath "$Env:UNITY_PATH/Editor/Unity.exe" `
|
||||||
# Results
|
-ArgumentList $unityArgs `
|
||||||
#
|
-PassThru `
|
||||||
|
-NoNewWindow
|
||||||
|
|
||||||
Write-Output ""
|
# Cache the handle so exit code works properly
|
||||||
Write-Output "###########################"
|
# https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
|
||||||
Write-Output "# Build output #"
|
$unityHandle = $unityProcess.Handle
|
||||||
Write-Output "###########################"
|
|
||||||
Write-Output ""
|
|
||||||
|
|
||||||
Get-ChildItem $Env:BUILD_PATH_FULL
|
while ($true) {
|
||||||
Write-Output ""
|
if ($unityProcess.HasExited) {
|
||||||
|
Start-Sleep -Seconds 3
|
||||||
|
Get-Process
|
||||||
|
|
||||||
|
$BUILD_EXIT_CODE = $unityProcess.ExitCode
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
if ($BUILD_EXIT_CODE -eq 0)
|
||||||
|
{
|
||||||
|
Write-Output "Build Succeeded!!"
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Write-Output "Build failed, with exit code $BUILD_EXIT_CODE"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output ""
|
||||||
|
Write-Output "###########################"
|
||||||
|
Write-Output "# Build output #"
|
||||||
|
Write-Output "###########################"
|
||||||
|
Write-Output ""
|
||||||
|
|
||||||
|
Get-ChildItem $Env:BUILD_PATH_FULL
|
||||||
|
Write-Output ""
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 3
|
||||||
|
}
|
||||||
|
|||||||
47
dist/platforms/windows/entrypoint.ps1
vendored
47
dist/platforms/windows/entrypoint.ps1
vendored
@@ -1,18 +1,55 @@
|
|||||||
|
Get-Process
|
||||||
|
|
||||||
|
# Copy .upmconfig.toml if it exists
|
||||||
|
if (Test-Path "C:\githubhome\.upmconfig.toml") {
|
||||||
|
Write-Host "Copying .upmconfig.toml to $Env:USERPROFILE\.upmconfig.toml"
|
||||||
|
Copy-Item -Path "C:\githubhome\.upmconfig.toml" -Destination "$Env:USERPROFILE\.upmconfig.toml" -Force
|
||||||
|
} else {
|
||||||
|
Write-Host "No .upmconfig.toml found at C:\githubhome"
|
||||||
|
}
|
||||||
|
|
||||||
# Import any necessary registry keys, ie: location of windows 10 sdk
|
# Import any necessary registry keys, ie: location of windows 10 sdk
|
||||||
# No guarantee that there will be any necessary registry keys, ie: tvOS
|
# No guarantee that there will be any necessary registry keys, ie: tvOS
|
||||||
Get-ChildItem -Path c:\regkeys -File | Foreach {reg import $_.fullname}
|
Get-ChildItem -Path c:\regkeys -File | ForEach-Object { reg import $_.fullname }
|
||||||
|
|
||||||
# Register the Visual Studio installation so Unity can find it
|
# Register the Visual Studio installation so Unity can find it
|
||||||
regsvr32 C:\ProgramData\Microsoft\VisualStudio\Setup\x64\Microsoft.VisualStudio.Setup.Configuration.Native.dll
|
regsvr32 C:\ProgramData\Microsoft\VisualStudio\Setup\x64\Microsoft.VisualStudio.Setup.Configuration.Native.dll
|
||||||
|
|
||||||
|
# Kill the regsvr process
|
||||||
|
Get-Process -Name regsvr32 | ForEach-Object { Stop-Process -Id $_.Id -Force }
|
||||||
|
|
||||||
|
# Install Visual C++ 2013 Redistributables
|
||||||
|
. "c:\steps\install_vcredist13.ps1"
|
||||||
|
|
||||||
# Setup Git Credentials
|
# Setup Git Credentials
|
||||||
& "c:\steps\set_gitcredential.ps1"
|
. "c:\steps\set_gitcredential.ps1"
|
||||||
|
|
||||||
|
if ($env:ENABLE_GPU -eq "true") {
|
||||||
|
# Install LLVMpipe software graphics driver
|
||||||
|
. "c:\steps\install_llvmpipe.ps1"
|
||||||
|
}
|
||||||
|
|
||||||
# Activate Unity
|
# Activate Unity
|
||||||
& "c:\steps\activate.ps1"
|
if ($env:SKIP_ACTIVATION -ne "true") {
|
||||||
|
. "c:\steps\activate.ps1"
|
||||||
|
|
||||||
|
# If we didn't activate successfully, exit with the exit code from the activation step.
|
||||||
|
if ($ACTIVATION_EXIT_CODE -ne 0) {
|
||||||
|
exit $ACTIVATION_EXIT_CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Skipping activation"
|
||||||
|
}
|
||||||
|
|
||||||
# Build the project
|
# Build the project
|
||||||
& "c:\steps\build.ps1"
|
. "c:\steps\build.ps1"
|
||||||
|
|
||||||
# Free the seat for the activated license
|
# Free the seat for the activated license
|
||||||
& "c:\steps\return_license.ps1"
|
if ($env:SKIP_ACTIVATION -ne "true") {
|
||||||
|
. "c:\steps\return_license.ps1"
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-Process
|
||||||
|
|
||||||
|
exit $BUILD_EXIT_CODE
|
||||||
|
|||||||
56
dist/platforms/windows/install_llvmpipe.ps1
vendored
Normal file
56
dist/platforms/windows/install_llvmpipe.ps1
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
$Private:repo = "mmozeiko/build-mesa"
|
||||||
|
$Private:downloadPath = "$Env:TEMP\mesa.zip"
|
||||||
|
$Private:extractPath = "$Env:TEMP\mesa"
|
||||||
|
$Private:destinationPath = "$Env:UNITY_PATH\Editor\"
|
||||||
|
$Private:version = "25.1.0"
|
||||||
|
|
||||||
|
$LLVMPIPE_INSTALLED = "false"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Get the release info from GitHub API (version fixed to decrease probability of breakage)
|
||||||
|
$releaseUrl = "https://api.github.com/repos/$repo/releases/tags/$version"
|
||||||
|
$release = Invoke-RestMethod -Uri $releaseUrl -Headers @{ "User-Agent" = "PowerShell" }
|
||||||
|
|
||||||
|
# Get the download URL for the zip asset
|
||||||
|
$zipUrl = $release.assets | Where-Object { $_.name -like "mesa-llvmpipe-x64*.zip" } | Select-Object -First 1 -ExpandProperty browser_download_url
|
||||||
|
|
||||||
|
if (-not $zipUrl) {
|
||||||
|
throw "No zip file found in the latest release."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download the zip file
|
||||||
|
Write-Host "Downloading $zipUrl..."
|
||||||
|
Invoke-WebRequest -Uri $zipUrl -OutFile $downloadPath
|
||||||
|
|
||||||
|
# Create extraction directory if it doesn't exist
|
||||||
|
if (-not (Test-Path $extractPath)) {
|
||||||
|
New-Item -ItemType Directory -Path $extractPath | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract the zip file
|
||||||
|
Write-Host "Extracting $downloadPath to $extractPath..."
|
||||||
|
Expand-Archive -Path $downloadPath -DestinationPath $extractPath -Force
|
||||||
|
|
||||||
|
# Create destination directory if it doesn't exist
|
||||||
|
if (-not (Test-Path $destinationPath)) {
|
||||||
|
New-Item -ItemType Directory -Path $destinationPath | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy extracted files to destination
|
||||||
|
Write-Host "Copying files to $destinationPath..."
|
||||||
|
Copy-Item -Path "$extractPath\*" -Destination $destinationPath -Recurse -Force
|
||||||
|
|
||||||
|
Write-Host "Successfully downloaded, extracted, and copied Mesa files to $destinationPath"
|
||||||
|
|
||||||
|
$LLVMPIPE_INSTALLED = "true"
|
||||||
|
} catch {
|
||||||
|
Write-Error "An error occurred: $_"
|
||||||
|
} finally {
|
||||||
|
# Clean up temporary files
|
||||||
|
if (Test-Path $downloadPath) {
|
||||||
|
Remove-Item $downloadPath -Force
|
||||||
|
}
|
||||||
|
if (Test-Path $extractPath) {
|
||||||
|
Remove-Item $extractPath -Recurse -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
11
dist/platforms/windows/install_vcredist13.ps1
vendored
Normal file
11
dist/platforms/windows/install_vcredist13.ps1
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# For some reason, Unity is failing in github actions windows runners
|
||||||
|
# due to missing Visual C++ 2013 redistributables.
|
||||||
|
# This script downloads and installs the required redistributables.
|
||||||
|
Write-Output ""
|
||||||
|
Write-Output "#########################################################"
|
||||||
|
Write-Output "# Installing Visual C++ Redistributables (2013) #"
|
||||||
|
Write-Output "#########################################################"
|
||||||
|
Write-Output ""
|
||||||
|
|
||||||
|
|
||||||
|
choco install vcredist2013 -y --no-progress
|
||||||
66
dist/platforms/windows/return_license.ps1
vendored
66
dist/platforms/windows/return_license.ps1
vendored
@@ -1,7 +1,61 @@
|
|||||||
# Return the active Unity license
|
# Return the active Unity license
|
||||||
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -nographics `
|
|
||||||
-username $Env:UNITY_EMAIL `
|
Write-Output ""
|
||||||
-password $Env:UNITY_PASSWORD `
|
Write-Output "###########################"
|
||||||
-returnlicense `
|
Write-Output "# Return License #"
|
||||||
-projectPath "c:/BlankProject" `
|
Write-Output "###########################"
|
||||||
-logfile | Out-Host
|
Write-Output ""
|
||||||
|
|
||||||
|
if (($null -ne ${env:UNITY_LICENSING_SERVER}))
|
||||||
|
{
|
||||||
|
Write-Output "Returning floating license: ""$env:FLOATING_LICENSE"""
|
||||||
|
Start-Process -FilePath "$Env:UNITY_PATH\Editor\Data\Resources\Licensing\Client\Unity.Licensing.Client.exe" `
|
||||||
|
-ArgumentList "--return-floating ""$env:FLOATING_LICENSE"" " `
|
||||||
|
-NoNewWindow `
|
||||||
|
-Wait
|
||||||
|
}
|
||||||
|
|
||||||
|
elseif (($null -ne ${env:UNITY_SERIAL}) -and ($null -ne ${env:UNITY_EMAIL}) -and ($null -ne ${env:UNITY_PASSWORD}))
|
||||||
|
{
|
||||||
|
#
|
||||||
|
# SERIAL LICENSE MODE
|
||||||
|
#
|
||||||
|
# This will return the license that is currently in use.
|
||||||
|
#
|
||||||
|
$RETURN_LICENSE_OUTPUT = Start-Process -FilePath "$Env:UNITY_PATH/Editor/Unity.exe" `
|
||||||
|
-NoNewWindow `
|
||||||
|
-PassThru `
|
||||||
|
-ArgumentList "-batchmode `
|
||||||
|
-quit `
|
||||||
|
-nographics `
|
||||||
|
-username $Env:UNITY_EMAIL `
|
||||||
|
-password $Env:UNITY_PASSWORD `
|
||||||
|
-returnlicense `
|
||||||
|
-projectPath c:/BlankProject `
|
||||||
|
-logfile -"
|
||||||
|
|
||||||
|
# Cache the handle so exit code works properly
|
||||||
|
# https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
|
||||||
|
$unityHandle = $RETURN_LICENSE_OUTPUT.Handle
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
if ($RETURN_LICENSE_OUTPUT.HasExited) {
|
||||||
|
$RETURN_LICENSE_EXIT_CODE = $RETURN_LICENSE_OUTPUT.ExitCode
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
if ($RETURN_LICENSE_EXIT_CODE -eq 0)
|
||||||
|
{
|
||||||
|
Write-Output "License Return Succeeded"
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Write-Output "License Return failed, with exit code $RETURN_LICENSE_EXIT_CODE"
|
||||||
|
Write-Output "::warning ::License Return failed! If this is a Pro License you might need to manually `
|
||||||
|
free the seat in your Unity admin panel or you might run out of seats to activate with."
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
14
dist/platforms/windows/set_gitcredential.ps1
vendored
14
dist/platforms/windows/set_gitcredential.ps1
vendored
@@ -1,16 +1,16 @@
|
|||||||
if ([string]::IsNullOrEmpty($env:GIT_PRIVATE_TOKEN)) {
|
if ($null -eq ${env:GIT_PRIVATE_TOKEN}) {
|
||||||
Write-Host "GIT_PRIVATE_TOKEN unset skipping"
|
Write-Host "GIT_PRIVATE_TOKEN unset skipping"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Host "GIT_PRIVATE_TOKEN is set configuring git credentials"
|
Write-Host "GIT_PRIVATE_TOKEN is set configuring git credentials"
|
||||||
|
|
||||||
git config --global credential.helper store
|
git config --global credential.helper store
|
||||||
git config --global --replace-all "url.https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
git config --global --replace-all url."https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
||||||
git config --global --add "url.https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com"
|
git config --global --add url."https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com"
|
||||||
git config --global --add "url.https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
|
git config --global --add url."https://token:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
|
||||||
|
|
||||||
git config --global "url.https://ssh:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
git config --global url."https://ssh:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
||||||
git config --global "url.https://git:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
|
git config --global url."https://git:$env:GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "---------- git config --list -------------"
|
Write-Host "---------- git config --list -------------"
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
// Automatically clear mock calls and instances between every test
|
|
||||||
clearMocks: true,
|
|
||||||
|
|
||||||
// An array of file extensions your modules use
|
|
||||||
moduleFileExtensions: ['js', 'ts'],
|
|
||||||
|
|
||||||
// The test environment that will be used for testing
|
|
||||||
testEnvironment: 'node',
|
|
||||||
|
|
||||||
// The glob patterns Jest uses to detect test files
|
|
||||||
testMatch: ['**/*.test.ts'],
|
|
||||||
|
|
||||||
// This option allows use of a custom test runner
|
|
||||||
testRunner: 'jest-circus/runner',
|
|
||||||
|
|
||||||
// A map with regular expressions for transformers to paths
|
|
||||||
transform: {
|
|
||||||
'^.+\\.ts$': 'ts-jest',
|
|
||||||
},
|
|
||||||
|
|
||||||
// Indicates whether each individual test should be reported during the run
|
|
||||||
verbose: true,
|
|
||||||
|
|
||||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
|
||||||
modulePathIgnorePatterns: ['<rootDir>/lib/', '<rootDir>/dist/'],
|
|
||||||
|
|
||||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
|
||||||
setupFilesAfterEnv: ['<rootDir>/src/jest.setup.ts'],
|
|
||||||
};
|
|
||||||
2
jest.setup.js
Normal file
2
jest.setup.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
const fetch = require('node-fetch');
|
||||||
|
global.fetch = fetch;
|
||||||
31
lefthook.yml
31
lefthook.yml
@@ -1,31 +0,0 @@
|
|||||||
# EXAMPLE USAGE
|
|
||||||
# Refer for explanation to following link:
|
|
||||||
# https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md
|
|
||||||
#
|
|
||||||
|
|
||||||
color: true
|
|
||||||
extends: {}
|
|
||||||
|
|
||||||
pre-commit:
|
|
||||||
parallel: true
|
|
||||||
commands:
|
|
||||||
format documents:
|
|
||||||
glob: '*.{md,mdx}'
|
|
||||||
run: yarn prettier --write {staged_files}
|
|
||||||
format configs:
|
|
||||||
glob: '*.{json,yml,yaml}'
|
|
||||||
run: yarn prettier --write {staged_files}
|
|
||||||
format code:
|
|
||||||
glob: '*.{js,jsx,ts,tsx}'
|
|
||||||
exclude: 'dist/'
|
|
||||||
run: yarn prettier --write {staged_files} && yarn eslint {staged_files} && git add {staged_files}
|
|
||||||
run tests:
|
|
||||||
glob: '*.{js,jsx,ts,tsx}'
|
|
||||||
exclude: 'dist/'
|
|
||||||
run: yarn jest --passWithNoTests --findRelatedTests {staged_files}
|
|
||||||
build distributables:
|
|
||||||
skip: ['merge', 'rebase']
|
|
||||||
run: yarn build && git add dist
|
|
||||||
make shell script executable:
|
|
||||||
glob: '*.sh'
|
|
||||||
run: git update-index --chmod=+x
|
|
||||||
6
mise.toml
Normal file
6
mise.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[tools]
|
||||||
|
node = "20.18.0"
|
||||||
|
yarn = "4.14.1"
|
||||||
|
actionlint = "latest"
|
||||||
|
shellcheck = "latest"
|
||||||
|
gitleaks = "latest"
|
||||||
90
package.json
90
package.json
@@ -7,74 +7,70 @@
|
|||||||
"author": "Webber <webber@takken.io>",
|
"author": "Webber <webber@takken.io>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "lefthook install && npx husky uninstall -y",
|
"prepare": "husky",
|
||||||
"build": "yarn && tsc && ncc build lib --source-map --license licenses.txt",
|
"build": "yarn && tsc && ncc build lib --source-map --license licenses.txt",
|
||||||
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts",
|
"test": "node scripts/ensure-husky.mjs && vitest run",
|
||||||
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
"test:watch": "vitest",
|
||||||
"cli": "yarn ts-node src/index.ts -m cli",
|
"test:ci": "vitest run",
|
||||||
"gcp-secrets-tests": "cross-env providerStrategy=aws cloudRunnerTests=true readInputOverrideCommand=\"gcp-secret-manager\" populateOverride=true readInputFromOverrideList=UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD yarn test -i -t \"cloud runner\"",
|
"coverage": "vitest run --coverage",
|
||||||
"gcp-secrets-cli": "cross-env cloudRunnerTests=true readInputOverrideCommand=\"gcp-secret-manager\" yarn ts-node src/index.ts -m cli --populateOverride true --readInputFromOverrideList UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD",
|
"lint": "yarn oxlint --report-unused-disable-directives",
|
||||||
"aws-secrets-cli": "cross-env cloudRunnerTests=true readInputOverrideCommand=\"aws-secret-manager\" yarn ts-node src/index.ts -m cli --populateOverride true --readInputFromOverrideList UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD",
|
"format": "oxfmt --write",
|
||||||
"cli-aws": "cross-env providerStrategy=aws yarn run test-cli",
|
"format:check": "oxfmt --check",
|
||||||
"cli-k8s": "cross-env providerStrategy=k8s yarn run test-cli",
|
"typecheck": "tsc --noEmit",
|
||||||
"test-cli": "cross-env cloudRunnerTests=true yarn ts-node src/index.ts -m cli --projectPath test-project",
|
"typecheck:tsgo": "tsgo --noEmit",
|
||||||
"test": "jest",
|
"setup:hooks": "node scripts/ensure-husky.mjs"
|
||||||
"test-i": "cross-env cloudRunnerTests=true yarn test -i -t \"cloud runner\"",
|
},
|
||||||
"test-i-*": "yarn run test-i-aws && yarn run test-i-k8s",
|
"lint-staged": {
|
||||||
"test-i-aws": "cross-env cloudRunnerTests=true providerStrategy=aws yarn test -i -t \"cloud runner\"",
|
"*.@(ts|tsx|mts|js|jsx|mjs|cjs)": [
|
||||||
"test-i-k8s": "cross-env cloudRunnerTests=true providerStrategy=k8s yarn test -i -t \"cloud runner\""
|
"oxlint --fix --quiet",
|
||||||
|
"oxfmt --write"
|
||||||
|
],
|
||||||
|
"*.@(json|jsonc|json5|md|mdx|yaml|yml|css|scss|sass|html|toml)": "oxfmt --write",
|
||||||
|
".github/workflows/*.@(yml|yaml)": "actionlint"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.x"
|
"node": ">=18.x"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^3.1.3",
|
"@actions/cache": "^4.0.0",
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/exec": "^1.1.0",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^5.0.0",
|
"@actions/github": "^6.0.0",
|
||||||
"@kubernetes/client-node": "^0.16.3",
|
|
||||||
"@octokit/core": "^3.5.1",
|
|
||||||
"async-wait-until": "^2.0.12",
|
|
||||||
"aws-sdk": "^2.1081.0",
|
|
||||||
"base-64": "^1.0.0",
|
|
||||||
"commander": "^9.0.0",
|
"commander": "^9.0.0",
|
||||||
"commander-ts": "^0.2.0",
|
"commander-ts": "^0.2.0",
|
||||||
"kubernetes-client": "^9.0.0",
|
"md5": "^2.3.0",
|
||||||
"nanoid": "^3.3.1",
|
"nanoid": "^3.3.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"semver": "^7.5.2",
|
"semver": "^7.5.2",
|
||||||
"unity-changeset": "^2.0.0",
|
"ts-md5": "^1.3.1",
|
||||||
"uuid": "^9.0.0",
|
"unity-changeset": "^3.1.0",
|
||||||
"yaml": "^2.2.2"
|
"yaml": "^2.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@evilmartians/lefthook": "^1.2.9",
|
|
||||||
"@types/base-64": "^1.0.0",
|
|
||||||
"@types/jest": "^27.4.1",
|
|
||||||
"@types/node": "^17.0.23",
|
"@types/node": "^17.0.23",
|
||||||
"@types/semver": "^7.3.9",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/uuid": "^9.0.0",
|
"@typescript/native-preview": "^7.0.0-dev.20260505.1",
|
||||||
"@typescript-eslint/parser": "4.8.1",
|
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.36.1",
|
||||||
|
"@vitest/coverage-istanbul": "^4.1.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^7.23.0",
|
"eslint": "^10.3.0",
|
||||||
"eslint-config-prettier": "8.1.0",
|
"eslint-plugin-unicorn": "^64.0.0",
|
||||||
"eslint-plugin-github": "^4.1.1",
|
"husky": "9",
|
||||||
"eslint-plugin-jest": "24.1.3",
|
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
|
||||||
"eslint-plugin-unicorn": "28.0.2",
|
|
||||||
"jest": "^27.5.1",
|
|
||||||
"jest-circus": "^27.5.1",
|
|
||||||
"jest-fail-on-console": "^3.0.2",
|
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"prettier": "^2.5.1",
|
"lint-staged": "^16.4.0",
|
||||||
"ts-jest": "^27.1.3",
|
"node-fetch": "2",
|
||||||
"ts-node": "10.4.0",
|
"oxfmt": "^0.48.0",
|
||||||
|
"oxlint": "^1.63.0",
|
||||||
|
"ts-node": "10.8.1",
|
||||||
"typescript": "4.7.4",
|
"typescript": "4.7.4",
|
||||||
|
"vite": "^7",
|
||||||
|
"vitest": "^4",
|
||||||
"yarn-audit-fix": "^9.3.8"
|
"yarn-audit-fix": "^9.3.8"
|
||||||
},
|
},
|
||||||
"volta": {
|
"packageManager": "yarn@4.14.1",
|
||||||
"node": "20.5.1",
|
"dependenciesMeta": {
|
||||||
"yarn": "1.22.19"
|
"lefthook": {
|
||||||
|
"built": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
scripts/ensure-husky.mjs
Executable file
55
scripts/ensure-husky.mjs
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// Self-heals husky git hooks before local dev workflows.
|
||||||
|
//
|
||||||
|
// Why this exists: Yarn 4 skips lifecycle scripts (`prepare`, `postinstall`) on
|
||||||
|
// no-op installs, so `yarn install --immutable` does NOT reinstall hooks once
|
||||||
|
// `.husky/_/` has been wiped. `.husky/_/` is gitignored, so it is also missing
|
||||||
|
// in fresh worktrees and after `git clean -fdx`. Without this guard, commits
|
||||||
|
// silently skip the pre-commit hook (git treats a missing hook file as "no hook").
|
||||||
|
//
|
||||||
|
// Behaviour: ~20 ms no-op when hooks are already installed. Skipped in CI and
|
||||||
|
// when HUSKY=0. Fails loudly (non-zero exit) on real install errors so the
|
||||||
|
// caller stops before commits are made without hooks.
|
||||||
|
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
import { existsSync } from 'node:fs';
|
||||||
|
|
||||||
|
if (process.env.CI || process.env.HUSKY === '0') process.exit(0);
|
||||||
|
|
||||||
|
const expectedHooksPath = '.husky/_';
|
||||||
|
const sentinelHook = '.husky/_/pre-commit';
|
||||||
|
// husky 9.1+ ships bin.js; husky 9.0 ships bin.mjs. Try both.
|
||||||
|
const huskyBin = ['node_modules/husky/bin.js', 'node_modules/husky/bin.mjs'].find(existsSync);
|
||||||
|
|
||||||
|
let configuredHooksPath = '';
|
||||||
|
try {
|
||||||
|
configuredHooksPath = execSync('git config --get core.hooksPath', {
|
||||||
|
encoding: 'utf8',
|
||||||
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
|
}).trim();
|
||||||
|
} catch {
|
||||||
|
// not a git repo or config unset — fall through and try to install
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuredHooksPath === expectedHooksPath && existsSync(sentinelHook)) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!huskyBin) {
|
||||||
|
// husky not installed yet (yarn install hasn't run) — silent no-op
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('· installing git hooks (husky self-heal)…');
|
||||||
|
try {
|
||||||
|
execSync(`node ${huskyBin}`, { stdio: 'inherit' });
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
console.error(
|
||||||
|
`\n❌ husky install failed: ${message}\n\n` +
|
||||||
|
` git pre-commit hooks are NOT installed; commits will skip lint/format/tests.\n` +
|
||||||
|
` Fix the underlying error above, then run \`yarn setup:hooks\` to retry.\n` +
|
||||||
|
` To bypass this guard temporarily (NOT recommended): HUSKY=0 yarn <cmd>.\n`,
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
15
scripts/game-ci.bat
Normal file
15
scripts/game-ci.bat
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
echo "installing game-ci cli"
|
||||||
|
if exist %UserProfile%\AppData\LocalLow\game-ci\ (
|
||||||
|
echo Installed Updating
|
||||||
|
git -C %UserProfile%\AppData\LocalLow\game-ci\ fetch
|
||||||
|
git -C %UserProfile%\AppData\LocalLow\game-ci\ reset --hard
|
||||||
|
git -C %UserProfile%\AppData\LocalLow\game-ci\ pull
|
||||||
|
git -C %UserProfile%\AppData\LocalLow\game-ci\ branch
|
||||||
|
) else (
|
||||||
|
echo Not Installed Downloading...
|
||||||
|
mkdir %UserProfile%\AppData\LocalLow\game-ci\
|
||||||
|
git clone https://github.com/game-ci/unity-builder %UserProfile%\AppData\LocalLow\game-ci\
|
||||||
|
)
|
||||||
|
|
||||||
|
call yarn --cwd %UserProfile%\AppData\LocalLow\game-ci\ install
|
||||||
|
call yarn --cwd %UserProfile%\AppData\LocalLow\game-ci\ run gcp-secrets-cli %* --projectPath %cd% --awsStackName game-ci-cli
|
||||||
278
src/index-plugin-features.test.ts
Normal file
278
src/index-plugin-features.test.ts
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
|
||||||
|
/**
|
||||||
|
* Integration wiring tests for the plugin lifecycle in index.ts
|
||||||
|
*
|
||||||
|
* These tests verify that:
|
||||||
|
* - The plugin lifecycle hooks are called in the correct order
|
||||||
|
* - Plugin canHandleBuild() controls the execution path
|
||||||
|
* - fallbackToLocal is handled correctly
|
||||||
|
* - When no plugin is installed, local builds still work
|
||||||
|
* - When providerStrategy is non-local without a plugin, an error is thrown
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BuildParameters, Docker } from './model';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Mock plugin
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// `vi.mock` hoists to the top of the module, so any factory references must
|
||||||
|
// be hoisted with `vi.hoisted` to be defined at mock-evaluation time.
|
||||||
|
const { mockPlugin, mockLoadPlugin } = vi.hoisted(() => {
|
||||||
|
const plugin = {
|
||||||
|
initialize: vi.fn().mockResolvedValue(undefined),
|
||||||
|
canHandleBuild: vi.fn().mockReturnValue(false),
|
||||||
|
handleBuild: vi.fn().mockResolvedValue({ exitCode: 0 }),
|
||||||
|
beforeLocalBuild: vi.fn().mockResolvedValue(undefined),
|
||||||
|
afterLocalBuild: vi.fn().mockResolvedValue(undefined),
|
||||||
|
handlePostBuild: vi.fn().mockResolvedValue(undefined),
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
mockPlugin: plugin,
|
||||||
|
mockLoadPlugin: vi.fn().mockResolvedValue(plugin),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vi.mock('./model/plugin', () => ({
|
||||||
|
loadPlugin: mockLoadPlugin,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@actions/core');
|
||||||
|
vi.mock('./model', () => ({
|
||||||
|
Action: {
|
||||||
|
checkCompatibility: vi.fn(),
|
||||||
|
workspace: '/workspace',
|
||||||
|
actionFolder: '/action',
|
||||||
|
},
|
||||||
|
BuildParameters: {
|
||||||
|
create: vi.fn(),
|
||||||
|
},
|
||||||
|
Cache: {
|
||||||
|
verify: vi.fn(),
|
||||||
|
},
|
||||||
|
Docker: {
|
||||||
|
run: vi.fn().mockResolvedValue(0),
|
||||||
|
},
|
||||||
|
// vitest 4 requires constructor mocks to use regular `function` (or
|
||||||
|
// `class`); arrow fns aren't valid constructors.
|
||||||
|
ImageTag: vi.fn(function () {
|
||||||
|
return { toString: () => 'mock-image:latest' };
|
||||||
|
}),
|
||||||
|
Output: {
|
||||||
|
setBuildVersion: vi.fn().mockResolvedValue(''),
|
||||||
|
setAndroidVersionCode: vi.fn().mockResolvedValue(''),
|
||||||
|
setEngineExitCode: vi.fn().mockResolvedValue(''),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('./model/cli/cli', () => ({
|
||||||
|
Cli: {
|
||||||
|
InitCliMode: vi.fn().mockReturnValue(false),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('./model/mac-builder', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: {
|
||||||
|
run: vi.fn().mockResolvedValue(0),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('./model/platform-setup', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
default: {
|
||||||
|
setup: vi.fn().mockResolvedValue(''),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockedBuildParametersCreate = BuildParameters.create as Mock;
|
||||||
|
|
||||||
|
function createMockBuildParameters(overrides: Record<string, any> = {}) {
|
||||||
|
return {
|
||||||
|
providerStrategy: 'local',
|
||||||
|
targetPlatform: 'StandaloneLinux64',
|
||||||
|
editorVersion: '2021.3.1f1',
|
||||||
|
buildVersion: '1.0.0',
|
||||||
|
androidVersionCode: '1',
|
||||||
|
projectPath: '.',
|
||||||
|
branch: 'main',
|
||||||
|
runnerTempPath: '/tmp',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runIndex(overrides: Record<string, any> = {}): Promise<void> {
|
||||||
|
mockedBuildParametersCreate.mockResolvedValue(createMockBuildParameters(overrides));
|
||||||
|
|
||||||
|
// index.ts exports `runMain` for testability (the file used to rely on
|
||||||
|
// top-level execution + jest's `vi.isolateModules`, but vitest 4 dropped
|
||||||
|
// that API). Calling the exported function directly is cleaner than
|
||||||
|
// round-tripping through dynamic imports.
|
||||||
|
const { runMain } = await import('./index');
|
||||||
|
await runMain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Tests
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('index.ts plugin lifecycle wiring', () => {
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
const originalEnvironment = { ...process.env };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
process.env.GITHUB_WORKSPACE = '/workspace';
|
||||||
|
Object.defineProperty(process, 'platform', { value: 'linux' });
|
||||||
|
|
||||||
|
// Reset plugin to default behavior
|
||||||
|
mockPlugin.canHandleBuild.mockReturnValue(false);
|
||||||
|
mockPlugin.handleBuild.mockResolvedValue({ exitCode: 0 });
|
||||||
|
mockLoadPlugin.mockResolvedValue(mockPlugin);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||||
|
process.env = { ...originalEnvironment };
|
||||||
|
});
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Local build with plugin
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('local build with plugin installed', () => {
|
||||||
|
it('should call lifecycle hooks in order: initialize -> beforeLocalBuild -> [build] -> afterLocalBuild -> handlePostBuild', async () => {
|
||||||
|
const callOrder: string[] = [];
|
||||||
|
mockPlugin.initialize.mockImplementation(async () => callOrder.push('initialize'));
|
||||||
|
mockPlugin.beforeLocalBuild.mockImplementation(async () =>
|
||||||
|
callOrder.push('beforeLocalBuild'),
|
||||||
|
);
|
||||||
|
mockPlugin.afterLocalBuild.mockImplementation(async () => callOrder.push('afterLocalBuild'));
|
||||||
|
mockPlugin.handlePostBuild.mockImplementation(async () => callOrder.push('handlePostBuild'));
|
||||||
|
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(callOrder).toEqual([
|
||||||
|
'initialize',
|
||||||
|
'beforeLocalBuild',
|
||||||
|
'afterLocalBuild',
|
||||||
|
'handlePostBuild',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass buildParameters and workspace to initialize', async () => {
|
||||||
|
await runIndex({ targetPlatform: 'WebGL' });
|
||||||
|
|
||||||
|
expect(mockPlugin.initialize).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ targetPlatform: 'WebGL' }),
|
||||||
|
'/workspace',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass workspace to beforeLocalBuild', async () => {
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.beforeLocalBuild).toHaveBeenCalledWith('/workspace');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass workspace and exit code to afterLocalBuild', async () => {
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.afterLocalBuild).toHaveBeenCalledWith('/workspace', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass exit code to handlePostBuild', async () => {
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.handlePostBuild).toHaveBeenCalledWith(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Plugin handles build entirely
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('plugin handles build (canHandleBuild = true)', () => {
|
||||||
|
it('should call handleBuild instead of Docker.run', async () => {
|
||||||
|
mockPlugin.canHandleBuild.mockReturnValue(true);
|
||||||
|
mockPlugin.handleBuild.mockResolvedValue({ exitCode: 0 });
|
||||||
|
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.handleBuild).toHaveBeenCalledWith('mock-image:latest');
|
||||||
|
expect(Docker.run).not.toHaveBeenCalled();
|
||||||
|
expect(mockPlugin.beforeLocalBuild).not.toHaveBeenCalled();
|
||||||
|
expect(mockPlugin.afterLocalBuild).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should still call handlePostBuild after handleBuild', async () => {
|
||||||
|
mockPlugin.canHandleBuild.mockReturnValue(true);
|
||||||
|
mockPlugin.handleBuild.mockResolvedValue({ exitCode: 0 });
|
||||||
|
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.handlePostBuild).toHaveBeenCalledWith(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Fallback to local
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('fallback to local build', () => {
|
||||||
|
it('should do a local build when handleBuild returns fallbackToLocal', async () => {
|
||||||
|
mockPlugin.canHandleBuild.mockReturnValue(true);
|
||||||
|
mockPlugin.handleBuild.mockResolvedValue({ exitCode: -1, fallbackToLocal: true });
|
||||||
|
|
||||||
|
await runIndex();
|
||||||
|
|
||||||
|
expect(mockPlugin.handleBuild).toHaveBeenCalled();
|
||||||
|
expect(mockPlugin.beforeLocalBuild).toHaveBeenCalled();
|
||||||
|
expect(Docker.run).toHaveBeenCalled();
|
||||||
|
expect(mockPlugin.afterLocalBuild).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// No plugin installed
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('no plugin installed', () => {
|
||||||
|
it('should build locally without errors when providerStrategy is local', async () => {
|
||||||
|
mockLoadPlugin.mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await runIndex({ providerStrategy: 'local' });
|
||||||
|
|
||||||
|
expect(Docker.run).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error when providerStrategy is non-local and no plugin', async () => {
|
||||||
|
mockLoadPlugin.mockResolvedValue(undefined);
|
||||||
|
|
||||||
|
await runIndex({ providerStrategy: 'aws' });
|
||||||
|
|
||||||
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('requires @game-ci/orchestrator'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// canHandleBuild = false with non-local provider
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
describe('plugin installed but canHandleBuild returns false with non-local provider', () => {
|
||||||
|
it('should error when providerStrategy is non-local', async () => {
|
||||||
|
mockPlugin.canHandleBuild.mockReturnValue(false);
|
||||||
|
|
||||||
|
await runIndex({ providerStrategy: 'aws' });
|
||||||
|
|
||||||
|
// The plugin is initialized but says it can't handle the build,
|
||||||
|
// and providerStrategy is not local, so it falls to the error case
|
||||||
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('requires @game-ci/orchestrator'),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
78
src/index.ts
78
src/index.ts
@@ -1,10 +1,13 @@
|
|||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { Action, BuildParameters, Cache, CloudRunner, Docker, ImageTag, Output } from './model';
|
import { Action, BuildParameters, Cache, Docker, ImageTag, Output } from './model';
|
||||||
import { Cli } from './model/cli/cli';
|
import { Cli } from './model/cli/cli';
|
||||||
import MacBuilder from './model/mac-builder';
|
import MacBuilder from './model/mac-builder';
|
||||||
import PlatformSetup from './model/platform-setup';
|
import PlatformSetup from './model/platform-setup';
|
||||||
|
import { Plugin, loadPlugin } from './model/plugin';
|
||||||
|
|
||||||
async function runMain() {
|
// Exported so tests can drive the lifecycle directly without depending on
|
||||||
|
// vitest's module re-loading (which changed in vitest 4).
|
||||||
|
export async function runMain() {
|
||||||
try {
|
try {
|
||||||
if (Cli.InitCliMode()) {
|
if (Cli.InitCliMode()) {
|
||||||
await Cli.RunCli();
|
await Cli.RunCli();
|
||||||
@@ -15,27 +18,74 @@ async function runMain() {
|
|||||||
Cache.verify();
|
Cache.verify();
|
||||||
|
|
||||||
const { workspace, actionFolder } = Action;
|
const { workspace, actionFolder } = Action;
|
||||||
|
|
||||||
const buildParameters = await BuildParameters.create();
|
const buildParameters = await BuildParameters.create();
|
||||||
const baseImage = new ImageTag(buildParameters);
|
const baseImage = new ImageTag(buildParameters);
|
||||||
|
|
||||||
if (buildParameters.providerStrategy === 'local') {
|
// Load optional plugin. The default implementation is @game-ci/orchestrator.
|
||||||
core.info('Building locally');
|
const plugin = await loadPlugin();
|
||||||
await PlatformSetup.setup(buildParameters, actionFolder);
|
await plugin?.initialize(buildParameters, workspace);
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
MacBuilder.run(actionFolder);
|
let exitCode = -1;
|
||||||
} else {
|
|
||||||
await Docker.run(baseImage.toString(), { workspace, actionFolder, ...buildParameters });
|
if (plugin?.canHandleBuild()) {
|
||||||
}
|
// Plugin handles the build entirely (remote providers, hot runner, test workflows)
|
||||||
|
const result = await plugin.handleBuild(baseImage.toString());
|
||||||
|
|
||||||
|
exitCode = result.fallbackToLocal
|
||||||
|
? await runLocalBuild(buildParameters, baseImage, workspace, actionFolder, plugin)
|
||||||
|
: result.exitCode;
|
||||||
|
} else if (buildParameters.providerStrategy === 'local') {
|
||||||
|
exitCode = await runLocalBuild(buildParameters, baseImage, workspace, actionFolder, plugin);
|
||||||
} else {
|
} else {
|
||||||
await CloudRunner.run(buildParameters, baseImage.toString());
|
throw new Error(
|
||||||
|
`Provider strategy "${buildParameters.providerStrategy}" requires @game-ci/orchestrator. ` +
|
||||||
|
'Install it via the game-ci/orchestrator action, or use providerStrategy=local.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set output
|
// Set core outputs
|
||||||
await Output.setBuildVersion(buildParameters.buildVersion);
|
await Output.setBuildVersion(buildParameters.buildVersion);
|
||||||
await Output.setAndroidVersionCode(buildParameters.androidVersionCode);
|
await Output.setAndroidVersionCode(buildParameters.androidVersionCode);
|
||||||
|
await Output.setEngineExitCode(exitCode);
|
||||||
|
|
||||||
|
// Plugin handles post-build (artifacts, archiving, retention)
|
||||||
|
await plugin?.handlePostBuild(exitCode);
|
||||||
|
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
core.setFailed(`Build failed with exit code ${exitCode}`);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed((error as Error).message);
|
core.setFailed((error as Error).message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runMain();
|
|
||||||
|
async function runLocalBuild(
|
||||||
|
buildParameters: BuildParameters,
|
||||||
|
baseImage: ImageTag,
|
||||||
|
workspace: string,
|
||||||
|
actionFolder: string,
|
||||||
|
plugin?: Plugin,
|
||||||
|
): Promise<number> {
|
||||||
|
await plugin?.beforeLocalBuild(workspace);
|
||||||
|
|
||||||
|
await PlatformSetup.setup(buildParameters, actionFolder);
|
||||||
|
const exitCode =
|
||||||
|
process.platform === 'darwin'
|
||||||
|
? await MacBuilder.run(actionFolder)
|
||||||
|
: await Docker.run(baseImage.toString(), {
|
||||||
|
workspace,
|
||||||
|
actionFolder,
|
||||||
|
...buildParameters,
|
||||||
|
});
|
||||||
|
|
||||||
|
await plugin?.afterLocalBuild(workspace, exitCode);
|
||||||
|
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-run when this module is the entry point. Tests import the file via
|
||||||
|
// `await import('./index')` purely to register the mock factories and then
|
||||||
|
// call `runMain()` directly.
|
||||||
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
|
runMain();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll, test } from 'vitest';
|
||||||
import { stat } from 'node:fs/promises';
|
import { stat } from 'node:fs/promises';
|
||||||
|
|
||||||
describe('Integrity tests', () => {
|
describe('Integrity tests', () => {
|
||||||
|
|||||||
3
src/jest.globals.ts
Normal file
3
src/jest.globals.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { fetch as undiciFetch, Headers, Request, Response } from 'undici';
|
||||||
|
|
||||||
|
Object.assign(globalThis, { fetch: undiciFetch, Headers, Request, Response });
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import failOnConsole from 'jest-fail-on-console';
|
|
||||||
|
|
||||||
// Fail when console logs something inside a test - use spyOn instead
|
|
||||||
failOnConsole({
|
|
||||||
shouldFailOnWarn: true,
|
|
||||||
shouldFailOnError: true,
|
|
||||||
shouldFailOnLog: true,
|
|
||||||
shouldFailOnAssert: true,
|
|
||||||
});
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { vi } from 'vitest';
|
||||||
// Import this named export into your test file:
|
// Import this named export into your test file:
|
||||||
import Platform from '../platform';
|
import Platform from '../platform';
|
||||||
|
|
||||||
export const mockGetFromUser = jest.fn().mockResolvedValue({
|
export const mockGetFromUser = vi.fn().mockResolvedValue({
|
||||||
editorVersion: '',
|
editorVersion: '',
|
||||||
targetPlatform: Platform.types.Test,
|
targetPlatform: Platform.types.Test,
|
||||||
projectPath: '.',
|
projectPath: '.',
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
|
import { vi } from 'vitest';
|
||||||
/* eslint unicorn/prevent-abbreviations: "off" */
|
/* eslint unicorn/prevent-abbreviations: "off" */
|
||||||
|
|
||||||
// Import these named export into your test file:
|
// Import these named export into your test file:
|
||||||
export const mockProjectPath = jest.fn().mockResolvedValue('mockProjectPath');
|
export const mockProjectPath = vi.fn().mockResolvedValue('mockProjectPath');
|
||||||
export const mockIsDirtyAllowed = jest.fn().mockResolvedValue(false);
|
export const mockIsDirtyAllowed = vi.fn().mockResolvedValue(false);
|
||||||
export const mockBranch = jest.fn().mockResolvedValue('mockBranch');
|
export const mockBranch = vi.fn().mockResolvedValue('mockBranch');
|
||||||
export const mockHeadRef = jest.fn().mockResolvedValue('mockHeadRef');
|
export const mockHeadRef = vi.fn().mockResolvedValue('mockHeadRef');
|
||||||
export const mockRef = jest.fn().mockResolvedValue('mockRef');
|
export const mockRef = vi.fn().mockResolvedValue('mockRef');
|
||||||
export const mockDetermineVersion = jest.fn().mockResolvedValue('1.2.3');
|
export const mockDetermineVersion = vi.fn().mockResolvedValue('1.2.3');
|
||||||
export const mockGenerateSemanticVersion = jest.fn().mockResolvedValue('2.3.4');
|
export const mockGenerateSemanticVersion = vi.fn().mockResolvedValue('2.3.4');
|
||||||
export const mockGenerateTagVersion = jest.fn().mockResolvedValue('1.0');
|
export const mockGenerateTagVersion = vi.fn().mockResolvedValue('1.0');
|
||||||
export const mockParseSemanticVersion = jest.fn().mockResolvedValue({});
|
export const mockParseSemanticVersion = vi.fn().mockResolvedValue({});
|
||||||
export const mockFetch = jest.fn().mockImplementation(() => {});
|
export const mockFetch = vi.fn().mockImplementation(() => {});
|
||||||
export const mockGetVersionDescription = jest.fn().mockResolvedValue('1.2-3-g12345678-dirty');
|
export const mockGetVersionDescription = vi.fn().mockResolvedValue('1.2-3-g12345678-dirty');
|
||||||
export const mockIsDirty = jest.fn().mockResolvedValue(false);
|
export const mockIsDirty = vi.fn().mockResolvedValue(false);
|
||||||
export const mockGetTag = jest.fn().mockResolvedValue('v1.0');
|
export const mockGetTag = vi.fn().mockResolvedValue('v1.0');
|
||||||
export const mockHasAnyVersionTags = jest.fn().mockResolvedValue(true);
|
export const mockHasAnyVersionTags = vi.fn().mockResolvedValue(true);
|
||||||
export const mockGetTotalNumberOfCommits = jest.fn().mockResolvedValue(3);
|
export const mockGetTotalNumberOfCommits = vi.fn().mockResolvedValue(3);
|
||||||
export const mockGit = jest.fn().mockImplementation(() => {});
|
export const mockGit = vi.fn().mockImplementation(() => {});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
projectPath: mockProjectPath,
|
projectPath: mockProjectPath,
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Versioning determineBuildVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
exports[`Versioning > determineBuildVersion > throws for invalid strategy somethingRandom 1`] = `[ValidationError: Versioning strategy should be one of None, Semantic, Tag, Custom.]`;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll, test } from 'vitest';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import Action from './action';
|
import Action from './action';
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach, afterEach, beforeAll, afterAll, test } from 'vitest';
|
||||||
import AndroidVersioning from './android-versioning';
|
import AndroidVersioning from './android-versioning';
|
||||||
|
|
||||||
describe('Android Versioning', () => {
|
describe('Android Versioning', () => {
|
||||||
@@ -35,7 +36,9 @@ describe('Android Versioning', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('uses the specified api level', () => {
|
it('uses the specified api level', () => {
|
||||||
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevel30')).toBe('platforms;android-30');
|
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevel30')).toBe(
|
||||||
|
'platforms;android-30',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ export default class AndroidVersioning {
|
|||||||
|
|
||||||
static versionToVersionCode(version: string): string {
|
static versionToVersionCode(version: string): string {
|
||||||
if (version === 'none') {
|
if (version === 'none') {
|
||||||
core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
|
core.info(
|
||||||
|
`Versioning strategy is set to ${version}, so android version code should not be applied.`,
|
||||||
|
);
|
||||||
|
|
||||||
return '0';
|
return '0';
|
||||||
}
|
}
|
||||||
@@ -27,7 +29,8 @@ 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 = parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
|
const versionCode =
|
||||||
|
parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
|
||||||
|
|
||||||
if (versionCode >= 2050000000) {
|
if (versionCode >= 2050000000) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, test, vi } from 'vitest';
|
||||||
import Versioning from './versioning';
|
import Versioning from './versioning';
|
||||||
import UnityVersioning from './unity-versioning';
|
import UnityVersioning from './unity-versioning';
|
||||||
import AndroidVersioning from './android-versioning';
|
import AndroidVersioning from './android-versioning';
|
||||||
@@ -9,12 +10,12 @@ const testLicense =
|
|||||||
'<?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>';
|
'<?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>';
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
vi.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
||||||
process.env.UNITY_LICENSE = testLicense; // Todo - Don't use process.env directly, that's what the input model class is for.
|
process.env.UNITY_LICENSE = testLicense; // Todo - Don't use process.env directly, that's what the input model class is for.
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,20 +26,20 @@ describe('BuildParameters', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('determines the version only once', async () => {
|
it('determines the version only once', async () => {
|
||||||
jest.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
vi.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
|
||||||
await BuildParameters.create();
|
await BuildParameters.create();
|
||||||
await expect(Versioning.determineBuildVersion).toHaveBeenCalledTimes(1);
|
await expect(Versioning.determineBuildVersion).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('determines the unity version only once', async () => {
|
it('determines the unity version only once', async () => {
|
||||||
jest.spyOn(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
vi.spyOn(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
||||||
await BuildParameters.create();
|
await BuildParameters.create();
|
||||||
expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1);
|
expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the android version code with provided input', async () => {
|
it('returns the android version code with provided input', async () => {
|
||||||
const mockValue = '42';
|
const mockValue = '42';
|
||||||
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidVersionCode: mockValue }),
|
expect.objectContaining({ androidVersionCode: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -46,43 +47,59 @@ 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);
|
vi.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('determines the android sdk manager parameters only once', async () => {
|
it('determines the android sdk manager parameters only once', async () => {
|
||||||
jest.spyOn(AndroidVersioning, 'determineSdkManagerParameters').mockImplementation(() => 'platforms;android-30');
|
vi.spyOn(AndroidVersioning, 'determineSdkManagerParameters').mockImplementation(
|
||||||
|
() => 'platforms;android-30',
|
||||||
|
);
|
||||||
await BuildParameters.create();
|
await BuildParameters.create();
|
||||||
expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1);
|
expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the targetPlatform', async () => {
|
it('returns the targetPlatform', async () => {
|
||||||
const mockValue = 'somePlatform';
|
const mockValue = 'somePlatform';
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ targetPlatform: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ targetPlatform: 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(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
vi.spyOn(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
||||||
jest.spyOn(Input, 'projectPath', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'projectPath', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ projectPath: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ projectPath: mockValue }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the build profile', async () => {
|
||||||
|
const mockValue = 'path/to/build_profile.asset';
|
||||||
|
vi.spyOn(Input, 'buildProfile', 'get').mockReturnValue(mockValue);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildProfile: 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);
|
vi.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildName: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildName: mockValue }),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the build path', async () => {
|
it('returns the build path', async () => {
|
||||||
const mockPath = 'somePath';
|
const mockPath = 'somePath';
|
||||||
const mockPlatform = 'somePlatform';
|
const mockPlatform = 'somePlatform';
|
||||||
const expectedBuildPath = `${mockPath}/${mockPlatform}`;
|
const expectedBuildPath = `${mockPath}/${mockPlatform}`;
|
||||||
jest.spyOn(Input, 'buildsPath', 'get').mockReturnValue(mockPath);
|
vi.spyOn(Input, 'buildsPath', 'get').mockReturnValue(mockPath);
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockPlatform);
|
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockPlatform);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ buildPath: expectedBuildPath }),
|
expect.objectContaining({ buildPath: expectedBuildPath }),
|
||||||
);
|
);
|
||||||
@@ -92,24 +109,29 @@ describe('BuildParameters', () => {
|
|||||||
const mockValue = 'someBuildName';
|
const mockValue = 'someBuildName';
|
||||||
const mockPlatform = 'somePlatform';
|
const mockPlatform = 'somePlatform';
|
||||||
|
|
||||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockPlatform);
|
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockPlatform);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildFile: mockValue }),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each`
|
test.each`
|
||||||
targetPlatform | expectedExtension | androidExportType
|
targetPlatform | expectedExtension | androidExportType | linux64RemoveExecutableExtension
|
||||||
${Platform.types.Android} | ${'.apk'} | ${'androidPackage'}
|
${Platform.types.Android} | ${'.apk'} | ${'androidPackage'} | ${false}
|
||||||
${Platform.types.Android} | ${'.aab'} | ${'androidAppBundle'}
|
${Platform.types.Android} | ${'.aab'} | ${'androidAppBundle'} | ${true}
|
||||||
${Platform.types.Android} | ${''} | ${'androidStudioProject'}
|
${Platform.types.Android} | ${''} | ${'androidStudioProject'} | ${false}
|
||||||
${Platform.types.StandaloneWindows} | ${'.exe'} | ${'n/a'}
|
${Platform.types.StandaloneWindows} | ${'.exe'} | ${'n/a'} | ${true}
|
||||||
${Platform.types.StandaloneWindows64} | ${'.exe'} | ${'n/a'}
|
${Platform.types.StandaloneWindows64} | ${'.exe'} | ${'n/a'} | ${false}
|
||||||
|
${Platform.types.StandaloneLinux64} | ${'.x86_64'} | ${'n/a'} | ${false}
|
||||||
|
${Platform.types.StandaloneLinux64} | ${''} | ${'n/a'} | ${true}
|
||||||
`(
|
`(
|
||||||
'appends $expectedExtension for $targetPlatform with androidExportType $androidExportType',
|
'appends $expectedExtension for $targetPlatform with linux64RemoveExecutableExtension=$linux64RemoveExecutableExtension',
|
||||||
async ({ targetPlatform, expectedExtension, androidExportType }) => {
|
async ({ targetPlatform, expectedExtension, androidExportType, linux64RemoveExecutableExtension }) => {
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
vi.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||||
jest.spyOn(Input, 'androidExportType', 'get').mockReturnValue(androidExportType);
|
vi.spyOn(Input, 'androidExportType', 'get').mockReturnValue(androidExportType);
|
||||||
|
vi.spyOn(Input, 'linux64RemoveExecutableExtension', 'get').mockReturnValue(linux64RemoveExecutableExtension);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ buildFile: `${targetPlatform}${expectedExtension}` }),
|
expect.objectContaining({ buildFile: `${targetPlatform}${expectedExtension}` }),
|
||||||
);
|
);
|
||||||
@@ -126,22 +148,26 @@ describe('BuildParameters', () => {
|
|||||||
`(
|
`(
|
||||||
'androidSymbolType is set to $androidSymbolType when targetPlatform is $targetPlatform and input targetSymbolType is $androidSymbolType',
|
'androidSymbolType is set to $androidSymbolType when targetPlatform is $targetPlatform and input targetSymbolType is $androidSymbolType',
|
||||||
async ({ targetPlatform, androidSymbolType }) => {
|
async ({ targetPlatform, androidSymbolType }) => {
|
||||||
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
vi.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||||
jest.spyOn(Input, 'androidSymbolType', 'get').mockReturnValue(androidSymbolType);
|
vi.spyOn(Input, 'androidSymbolType', 'get').mockReturnValue(androidSymbolType);
|
||||||
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
vi.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidSymbolType }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ androidSymbolType }),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
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);
|
vi.spyOn(Input, 'buildMethod', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildMethod: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildMethod: mockValue }),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the android keystore name', async () => {
|
it('returns the android keystore name', async () => {
|
||||||
const mockValue = 'keystore.keystore';
|
const mockValue = 'keystore.keystore';
|
||||||
jest.spyOn(Input, 'androidKeystoreName', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidKeystoreName', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidKeystoreName: mockValue }),
|
expect.objectContaining({ androidKeystoreName: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -149,7 +175,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the android keystore base64-encoded content', async () => {
|
it('returns the android keystore base64-encoded content', async () => {
|
||||||
const mockValue = 'secret';
|
const mockValue = 'secret';
|
||||||
jest.spyOn(Input, 'androidKeystoreBase64', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidKeystoreBase64', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidKeystoreBase64: mockValue }),
|
expect.objectContaining({ androidKeystoreBase64: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -157,7 +183,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the android keystore pass', async () => {
|
it('returns the android keystore pass', async () => {
|
||||||
const mockValue = 'secret';
|
const mockValue = 'secret';
|
||||||
jest.spyOn(Input, 'androidKeystorePass', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidKeystorePass', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidKeystorePass: mockValue }),
|
expect.objectContaining({ androidKeystorePass: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -165,7 +191,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the android keyalias name', async () => {
|
it('returns the android keyalias name', async () => {
|
||||||
const mockValue = 'secret';
|
const mockValue = 'secret';
|
||||||
jest.spyOn(Input, 'androidKeyaliasName', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidKeyaliasName', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidKeyaliasName: mockValue }),
|
expect.objectContaining({ androidKeyaliasName: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -173,7 +199,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the android keyalias pass', async () => {
|
it('returns the android keyalias pass', async () => {
|
||||||
const mockValue = 'secret';
|
const mockValue = 'secret';
|
||||||
jest.spyOn(Input, 'androidKeyaliasPass', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidKeyaliasPass', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidKeyaliasPass: mockValue }),
|
expect.objectContaining({ androidKeyaliasPass: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -181,7 +207,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the android target sdk version', async () => {
|
it('returns the android target sdk version', async () => {
|
||||||
const mockValue = 'AndroidApiLevelAuto';
|
const mockValue = 'AndroidApiLevelAuto';
|
||||||
jest.spyOn(Input, 'androidTargetSdkVersion', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'androidTargetSdkVersion', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ androidTargetSdkVersion: mockValue }),
|
expect.objectContaining({ androidTargetSdkVersion: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -189,7 +215,7 @@ describe('BuildParameters', () => {
|
|||||||
|
|
||||||
it('returns the unity licensing server address', async () => {
|
it('returns the unity licensing server address', async () => {
|
||||||
const mockValue = 'http://example.com';
|
const mockValue = 'http://example.com';
|
||||||
jest.spyOn(Input, 'unityLicensingServer', 'get').mockReturnValue(mockValue);
|
vi.spyOn(Input, 'unityLicensingServer', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
expect.objectContaining({ unityLicensingServer: mockValue }),
|
expect.objectContaining({ unityLicensingServer: mockValue }),
|
||||||
);
|
);
|
||||||
@@ -204,14 +230,25 @@ describe('BuildParameters', () => {
|
|||||||
const mockValue = '123';
|
const mockValue = '123';
|
||||||
delete process.env.UNITY_LICENSE; // Need to delete this as it is set for every test currently
|
delete process.env.UNITY_LICENSE; // Need to delete this as it is set for every test currently
|
||||||
process.env.UNITY_SERIAL = mockValue;
|
process.env.UNITY_SERIAL = mockValue;
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ unitySerial: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ unitySerial: mockValue }),
|
||||||
|
);
|
||||||
delete process.env.UNITY_SERIAL;
|
delete process.env.UNITY_SERIAL;
|
||||||
});
|
});
|
||||||
|
|
||||||
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);
|
vi.spyOn(Input, 'customParameters', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ customParameters: mockValue }));
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ customParameters: mockValue }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([true, false])('returns the flag for useHostNetwork when %s', async (mockValue) => {
|
||||||
|
vi.spyOn(Input, 'useHostNetwork', 'get').mockReturnValue(mockValue);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ useHostNetwork: mockValue }),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import AndroidVersioning from './android-versioning';
|
import AndroidVersioning from './android-versioning';
|
||||||
import CloudRunnerConstants from './cloud-runner/options/cloud-runner-constants';
|
|
||||||
import CloudRunnerBuildGuid from './cloud-runner/options/cloud-runner-guid';
|
|
||||||
import Input from './input';
|
import Input from './input';
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
import UnityVersioning from './unity-versioning';
|
import UnityVersioning from './unity-versioning';
|
||||||
@@ -10,8 +8,7 @@ import { GitRepoReader } from './input-readers/git-repo';
|
|||||||
import { GithubCliReader } from './input-readers/github-cli';
|
import { GithubCliReader } from './input-readers/github-cli';
|
||||||
import { Cli } from './cli/cli';
|
import { Cli } from './cli/cli';
|
||||||
import GitHub from './github';
|
import GitHub from './github';
|
||||||
import CloudRunnerOptions from './cloud-runner/options/cloud-runner-options';
|
import * as core from '@actions/core';
|
||||||
import CloudRunner from './cloud-runner/cloud-runner';
|
|
||||||
|
|
||||||
class BuildParameters {
|
class BuildParameters {
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
@@ -21,14 +18,18 @@ class BuildParameters {
|
|||||||
public customImage!: string;
|
public customImage!: string;
|
||||||
public unitySerial!: string;
|
public unitySerial!: string;
|
||||||
public unityLicensingServer!: string;
|
public unityLicensingServer!: string;
|
||||||
|
public skipActivation!: string;
|
||||||
public runnerTempPath!: string;
|
public runnerTempPath!: string;
|
||||||
public targetPlatform!: string;
|
public targetPlatform!: string;
|
||||||
public projectPath!: string;
|
public projectPath!: string;
|
||||||
|
public buildProfile!: string;
|
||||||
public buildName!: string;
|
public buildName!: string;
|
||||||
public buildPath!: string;
|
public buildPath!: string;
|
||||||
public buildFile!: string;
|
public buildFile!: string;
|
||||||
public buildMethod!: string;
|
public buildMethod!: string;
|
||||||
public buildVersion!: string;
|
public buildVersion!: string;
|
||||||
|
public manualExit!: boolean;
|
||||||
|
public enableGpu!: boolean;
|
||||||
public androidVersionCode!: string;
|
public androidVersionCode!: string;
|
||||||
public androidKeystoreName!: string;
|
public androidKeystoreName!: string;
|
||||||
public androidKeystoreBase64!: string;
|
public androidKeystoreBase64!: string;
|
||||||
@@ -39,62 +40,56 @@ class BuildParameters {
|
|||||||
public androidSdkManagerParameters!: string;
|
public androidSdkManagerParameters!: string;
|
||||||
public androidExportType!: string;
|
public androidExportType!: string;
|
||||||
public androidSymbolType!: string;
|
public androidSymbolType!: string;
|
||||||
|
public dockerCpuLimit!: string;
|
||||||
|
public dockerMemoryLimit!: string;
|
||||||
|
public dockerIsolationMode!: string;
|
||||||
|
public containerRegistryRepository!: string;
|
||||||
|
public containerRegistryImageVersion!: string;
|
||||||
|
|
||||||
public customParameters!: string;
|
public customParameters!: string;
|
||||||
|
public useHostNetwork!: boolean;
|
||||||
public sshAgent!: string;
|
public sshAgent!: string;
|
||||||
public sshPublicKeysDirectoryPath!: string;
|
public sshPublicKeysDirectoryPath!: string;
|
||||||
public providerStrategy!: string;
|
public providerStrategy!: string;
|
||||||
public gitPrivateToken!: string;
|
public gitPrivateToken!: string;
|
||||||
public awsStackName!: string;
|
public runAsHostUser!: string;
|
||||||
public kubeConfig!: string;
|
|
||||||
public containerMemory!: string;
|
|
||||||
public containerCpu!: string;
|
|
||||||
public kubeVolumeSize!: string;
|
|
||||||
public kubeVolume!: string;
|
|
||||||
public kubeStorageClass!: string;
|
|
||||||
public chownFilesTo!: string;
|
public chownFilesTo!: string;
|
||||||
public commandHooks!: string;
|
|
||||||
public pullInputList!: string[];
|
|
||||||
public inputPullCommand!: string;
|
|
||||||
public cacheKey!: string;
|
|
||||||
|
|
||||||
public postBuildContainerHooks!: string;
|
|
||||||
public preBuildContainerHooks!: string;
|
|
||||||
public customJob!: string;
|
|
||||||
public runNumber!: string;
|
public runNumber!: string;
|
||||||
public branch!: string;
|
public branch!: string;
|
||||||
public githubRepo!: string;
|
public githubRepo!: string;
|
||||||
public gitSha!: string;
|
public gitSha!: string;
|
||||||
public logId!: string;
|
public logId!: string;
|
||||||
public buildGuid!: string;
|
public buildGuid!: string;
|
||||||
public cloudRunnerBranch!: string;
|
|
||||||
public cloudRunnerDebug!: boolean | undefined;
|
|
||||||
public buildPlatform!: string | undefined;
|
public buildPlatform!: string | undefined;
|
||||||
public isCliMode!: boolean;
|
public isCliMode!: boolean;
|
||||||
public maxRetainedWorkspaces!: number;
|
|
||||||
public useLargePackages!: boolean;
|
|
||||||
public useCompressionStrategy!: boolean;
|
|
||||||
public garbageMaxAge!: number;
|
|
||||||
public githubChecks!: boolean;
|
|
||||||
public asyncWorkflow!: boolean;
|
|
||||||
public githubCheckId!: string;
|
|
||||||
public finalHooks!: string[];
|
|
||||||
public skipLfs!: boolean;
|
|
||||||
public skipCache!: boolean;
|
|
||||||
public cacheUnityInstallationOnMac!: boolean;
|
public cacheUnityInstallationOnMac!: boolean;
|
||||||
public unityHubVersionOnMac!: string;
|
public unityHubVersionOnMac!: string;
|
||||||
public dockerWorkspacePath!: string;
|
public dockerWorkspacePath!: string;
|
||||||
|
|
||||||
public static shouldUseRetainedWorkspaceMode(buildParameters: BuildParameters) {
|
|
||||||
return buildParameters.maxRetainedWorkspaces > 0 && CloudRunner.lockedWorkspace !== ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(): Promise<BuildParameters> {
|
static async create(): Promise<BuildParameters> {
|
||||||
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidExportType);
|
const buildFile = this.parseBuildFile(
|
||||||
const editorVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
|
Input.buildName,
|
||||||
const buildVersion = await Versioning.determineBuildVersion(Input.versioningStrategy, Input.specifiedVersion);
|
Input.targetPlatform,
|
||||||
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode);
|
Input.androidExportType,
|
||||||
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(Input.androidTargetSdkVersion);
|
Input.linux64RemoveExecutableExtension,
|
||||||
|
);
|
||||||
|
const editorVersion = UnityVersioning.determineUnityVersion(
|
||||||
|
Input.projectPath,
|
||||||
|
Input.unityVersion,
|
||||||
|
);
|
||||||
|
const buildVersion = await Versioning.determineBuildVersion(
|
||||||
|
Input.versioningStrategy,
|
||||||
|
Input.specifiedVersion,
|
||||||
|
);
|
||||||
|
const androidVersionCode = AndroidVersioning.determineVersionCode(
|
||||||
|
buildVersion,
|
||||||
|
Input.androidVersionCode,
|
||||||
|
);
|
||||||
|
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(
|
||||||
|
Input.androidTargetSdkVersion,
|
||||||
|
);
|
||||||
|
|
||||||
const androidSymbolExportType = Input.androidSymbolType;
|
const androidSymbolExportType = Input.androidSymbolType;
|
||||||
if (Platform.isAndroid(Input.targetPlatform)) {
|
if (Platform.isAndroid(Input.targetPlatform)) {
|
||||||
@@ -115,10 +110,12 @@ class BuildParameters {
|
|||||||
if (!Input.unitySerial && GitHub.githubInputEnabled) {
|
if (!Input.unitySerial && GitHub.githubInputEnabled) {
|
||||||
// No serial was present, so it is a personal license that we need to convert
|
// No serial was present, so it is a personal license that we need to convert
|
||||||
if (!Input.unityLicense) {
|
if (!Input.unityLicense) {
|
||||||
throw new Error(`Missing Unity License File and no Serial was found. If this
|
throw new Error(
|
||||||
|
`Missing Unity License File and no Serial was found. If this
|
||||||
is a personal license, make sure to follow the activation
|
is a personal license, make sure to follow the activation
|
||||||
steps and set the UNITY_LICENSE GitHub secret or enter a Unity
|
steps and set the UNITY_LICENSE GitHub secret or enter a Unity
|
||||||
serial number inside the UNITY_SERIAL GitHub secret.`);
|
serial number inside the UNITY_SERIAL GitHub secret.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
unitySerial = this.getSerialFromLicenseFile(Input.unityLicense);
|
unitySerial = this.getSerialFromLicenseFile(Input.unityLicense);
|
||||||
} else {
|
} else {
|
||||||
@@ -126,19 +123,31 @@ class BuildParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unitySerial !== undefined && unitySerial.length === 27) {
|
||||||
|
core.setSecret(unitySerial);
|
||||||
|
core.setSecret(`${unitySerial.slice(0, -4)}XXXX`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerStrategy =
|
||||||
|
Input.getInput('providerStrategy') || (Cli.isCliMode ? 'aws' : 'local');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
editorVersion,
|
editorVersion,
|
||||||
customImage: Input.customImage,
|
customImage: Input.customImage,
|
||||||
unitySerial,
|
unitySerial,
|
||||||
unityLicensingServer: Input.unityLicensingServer,
|
unityLicensingServer: Input.unityLicensingServer,
|
||||||
|
skipActivation: Input.skipActivation,
|
||||||
runnerTempPath: Input.runnerTempPath,
|
runnerTempPath: Input.runnerTempPath,
|
||||||
targetPlatform: Input.targetPlatform,
|
targetPlatform: Input.targetPlatform,
|
||||||
projectPath: Input.projectPath,
|
projectPath: Input.projectPath,
|
||||||
|
buildProfile: Input.buildProfile,
|
||||||
buildName: Input.buildName,
|
buildName: Input.buildName,
|
||||||
buildPath: `${Input.buildsPath}/${Input.targetPlatform}`,
|
buildPath: `${Input.buildsPath}/${Input.targetPlatform}`,
|
||||||
buildFile,
|
buildFile,
|
||||||
buildMethod: Input.buildMethod,
|
buildMethod: Input.buildMethod,
|
||||||
buildVersion,
|
buildVersion,
|
||||||
|
manualExit: Input.manualExit,
|
||||||
|
enableGpu: Input.enableGpu,
|
||||||
androidVersionCode,
|
androidVersionCode,
|
||||||
androidKeystoreName: Input.androidKeystoreName,
|
androidKeystoreName: Input.androidKeystoreName,
|
||||||
androidKeystoreBase64: Input.androidKeystoreBase64,
|
androidKeystoreBase64: Input.androidKeystoreBase64,
|
||||||
@@ -150,52 +159,42 @@ class BuildParameters {
|
|||||||
androidExportType: Input.androidExportType,
|
androidExportType: Input.androidExportType,
|
||||||
androidSymbolType: androidSymbolExportType,
|
androidSymbolType: androidSymbolExportType,
|
||||||
customParameters: Input.customParameters,
|
customParameters: Input.customParameters,
|
||||||
|
useHostNetwork: Input.useHostNetwork,
|
||||||
sshAgent: Input.sshAgent,
|
sshAgent: Input.sshAgent,
|
||||||
sshPublicKeysDirectoryPath: Input.sshPublicKeysDirectoryPath,
|
sshPublicKeysDirectoryPath: Input.sshPublicKeysDirectoryPath,
|
||||||
gitPrivateToken: Input.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()),
|
gitPrivateToken: Input.gitPrivateToken ?? (await GithubCliReader.GetGitHubAuthToken()),
|
||||||
|
runAsHostUser: Input.runAsHostUser,
|
||||||
chownFilesTo: Input.chownFilesTo,
|
chownFilesTo: Input.chownFilesTo,
|
||||||
providerStrategy: CloudRunnerOptions.providerStrategy,
|
dockerCpuLimit: Input.dockerCpuLimit,
|
||||||
buildPlatform: CloudRunnerOptions.buildPlatform,
|
dockerMemoryLimit: Input.dockerMemoryLimit,
|
||||||
kubeConfig: CloudRunnerOptions.kubeConfig,
|
dockerIsolationMode: Input.dockerIsolationMode,
|
||||||
containerMemory: CloudRunnerOptions.containerMemory,
|
containerRegistryRepository: Input.containerRegistryRepository,
|
||||||
containerCpu: CloudRunnerOptions.containerCpu,
|
containerRegistryImageVersion: Input.containerRegistryImageVersion,
|
||||||
kubeVolumeSize: CloudRunnerOptions.kubeVolumeSize,
|
providerStrategy,
|
||||||
kubeVolume: CloudRunnerOptions.kubeVolume,
|
buildPlatform: providerStrategy !== 'local' ? 'linux' : process.platform,
|
||||||
postBuildContainerHooks: CloudRunnerOptions.postBuildContainerHooks,
|
|
||||||
preBuildContainerHooks: CloudRunnerOptions.preBuildContainerHooks,
|
|
||||||
customJob: CloudRunnerOptions.customJob,
|
|
||||||
runNumber: Input.runNumber,
|
runNumber: Input.runNumber,
|
||||||
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
||||||
cloudRunnerBranch: CloudRunnerOptions.cloudRunnerBranch.split('/').reverse()[0],
|
githubRepo:
|
||||||
cloudRunnerDebug: CloudRunnerOptions.cloudRunnerDebug,
|
(Input.githubRepo ?? (await GitRepoReader.GetRemote())) || 'game-ci/unity-builder',
|
||||||
githubRepo: Input.githubRepo || (await GitRepoReader.GetRemote()) || 'game-ci/unity-builder',
|
|
||||||
isCliMode: Cli.isCliMode,
|
|
||||||
awsStackName: CloudRunnerOptions.awsStackName,
|
|
||||||
gitSha: Input.gitSha,
|
gitSha: Input.gitSha,
|
||||||
logId: customAlphabet(CloudRunnerConstants.alphabet, 9)(),
|
logId: customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 9)(),
|
||||||
buildGuid: CloudRunnerBuildGuid.generateGuid(Input.runNumber, Input.targetPlatform),
|
buildGuid: `${Input.runNumber}-${Input.targetPlatform.toLowerCase().replace('standalone', '')}-${customAlphabet(
|
||||||
commandHooks: CloudRunnerOptions.commandHooks,
|
'0123456789abcdefghijklmnopqrstuvwxyz',
|
||||||
inputPullCommand: CloudRunnerOptions.inputPullCommand,
|
4,
|
||||||
pullInputList: CloudRunnerOptions.pullInputList,
|
)()}`,
|
||||||
kubeStorageClass: CloudRunnerOptions.kubeStorageClass,
|
isCliMode: Cli.isCliMode,
|
||||||
cacheKey: CloudRunnerOptions.cacheKey,
|
|
||||||
maxRetainedWorkspaces: Number.parseInt(CloudRunnerOptions.maxRetainedWorkspaces),
|
|
||||||
useLargePackages: CloudRunnerOptions.useLargePackages,
|
|
||||||
useCompressionStrategy: CloudRunnerOptions.useCompressionStrategy,
|
|
||||||
garbageMaxAge: CloudRunnerOptions.garbageMaxAge,
|
|
||||||
githubChecks: CloudRunnerOptions.githubChecks,
|
|
||||||
asyncWorkflow: CloudRunnerOptions.asyncCloudRunner,
|
|
||||||
githubCheckId: CloudRunnerOptions.githubCheckId,
|
|
||||||
finalHooks: CloudRunnerOptions.finalHooks,
|
|
||||||
skipLfs: CloudRunnerOptions.skipLfs,
|
|
||||||
skipCache: CloudRunnerOptions.skipCache,
|
|
||||||
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
|
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
|
||||||
unityHubVersionOnMac: Input.unityHubVersionOnMac,
|
unityHubVersionOnMac: Input.unityHubVersionOnMac,
|
||||||
dockerWorkspacePath: Input.dockerWorkspacePath,
|
dockerWorkspacePath: Input.dockerWorkspacePath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static parseBuildFile(filename: string, platform: string, androidExportType: string): string {
|
static parseBuildFile(
|
||||||
|
filename: string,
|
||||||
|
platform: string,
|
||||||
|
androidExportType: string,
|
||||||
|
linux64RemoveExecutableExtension: boolean,
|
||||||
|
): string {
|
||||||
if (Platform.isWindows(platform)) {
|
if (Platform.isWindows(platform)) {
|
||||||
return `${filename}.exe`;
|
return `${filename}.exe`;
|
||||||
}
|
}
|
||||||
@@ -215,6 +214,10 @@ class BuildParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (platform === Platform.types.StandaloneLinux64 && !linux64RemoveExecutableExtension) {
|
||||||
|
return `${filename}.x86_64`;
|
||||||
|
}
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll, vi } from 'vitest';
|
||||||
import Cache from './cache';
|
import Cache from './cache';
|
||||||
|
|
||||||
jest.mock('./input');
|
vi.mock('./input');
|
||||||
|
|
||||||
describe('Cache', () => {
|
describe('Cache', () => {
|
||||||
describe('Verification', () => {
|
describe('Verification', () => {
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
import { Command } from 'commander-ts';
|
import { Command } from 'commander-ts';
|
||||||
import { BuildParameters, CloudRunner, ImageTag, Input } from '..';
|
import { Input } from '..';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { ActionYamlReader } from '../input-readers/action-yaml';
|
import { ActionYamlReader } from '../input-readers/action-yaml';
|
||||||
import CloudRunnerLogger from '../cloud-runner/services/core/cloud-runner-logger';
|
|
||||||
import CloudRunnerQueryOverride from '../cloud-runner/options/cloud-runner-query-override';
|
|
||||||
import { CliFunction, CliFunctionsRepository } from './cli-functions-repository';
|
import { CliFunction, CliFunctionsRepository } from './cli-functions-repository';
|
||||||
import { Caching } from '../cloud-runner/remote-client/caching';
|
|
||||||
import { LfsHashing } from '../cloud-runner/services/utility/lfs-hashing';
|
|
||||||
import { RemoteClient } from '../cloud-runner/remote-client';
|
|
||||||
import CloudRunnerOptionsReader from '../cloud-runner/options/cloud-runner-options-reader';
|
|
||||||
import GitHub from '../github';
|
|
||||||
import { CloudRunnerFolders } from '../cloud-runner/options/cloud-runner-folders';
|
|
||||||
import { CloudRunnerSystem } from '../cloud-runner/services/core/cloud-runner-system';
|
|
||||||
import { OptionValues } from 'commander';
|
import { OptionValues } from 'commander';
|
||||||
import { InputKey } from '../input';
|
import { InputKey } from '../input';
|
||||||
|
|
||||||
@@ -32,14 +23,13 @@ export class Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static InitCliMode() {
|
public static InitCliMode() {
|
||||||
CliFunctionsRepository.PushCliFunctionSource(RemoteClient);
|
|
||||||
CliFunctionsRepository.PushCliFunctionSource(Caching);
|
|
||||||
CliFunctionsRepository.PushCliFunctionSource(LfsHashing);
|
|
||||||
const program = new Command();
|
const program = new Command();
|
||||||
program.version('0.0.1');
|
program.version('0.0.1');
|
||||||
|
|
||||||
const properties = CloudRunnerOptionsReader.GetProperties();
|
|
||||||
const actionYamlReader: ActionYamlReader = new ActionYamlReader();
|
const actionYamlReader: ActionYamlReader = new ActionYamlReader();
|
||||||
|
const properties = Object.getOwnPropertyNames(Input).filter(
|
||||||
|
(p) => p !== 'length' && p !== 'prototype' && p !== 'name',
|
||||||
|
);
|
||||||
for (const element of properties) {
|
for (const element of properties) {
|
||||||
program.option(`--${element} <${element}>`, actionYamlReader.GetActionYamlValue(element));
|
program.option(`--${element} <${element}>`, actionYamlReader.GetActionYamlValue(element));
|
||||||
}
|
}
|
||||||
@@ -49,11 +39,23 @@ export class Cli {
|
|||||||
.map((x) => `${x.key} (${x.description})`)
|
.map((x) => `${x.key} (${x.description})`)
|
||||||
.join(` | `),
|
.join(` | `),
|
||||||
);
|
);
|
||||||
program.option('--populateOverride <populateOverride>', 'should use override query to pull input false by default');
|
program.option(
|
||||||
|
'--populateOverride <populateOverride>',
|
||||||
|
'should use override query to pull input false by default',
|
||||||
|
);
|
||||||
program.option('--cachePushFrom <cachePushFrom>', 'cache push from source folder');
|
program.option('--cachePushFrom <cachePushFrom>', 'cache push from source folder');
|
||||||
program.option('--cachePushTo <cachePushTo>', 'cache push to caching folder');
|
program.option('--cachePushTo <cachePushTo>', 'cache push to caching folder');
|
||||||
program.option('--artifactName <artifactName>', 'caching artifact name');
|
program.option('--artifactName <artifactName>', 'caching artifact name');
|
||||||
program.option('--select <select>', 'select a particular resource');
|
program.option('--select <select>', 'select a particular resource');
|
||||||
|
program.option('--logFile <logFile>', 'output to log file (log stream only)');
|
||||||
|
program.option('--profilePath <profilePath>', 'path to submodule profile YAML');
|
||||||
|
program.option('--variantPath <variantPath>', 'path to submodule variant YAML');
|
||||||
|
program.option('--agentPath <agentPath>', 'path to custom LFS transfer agent');
|
||||||
|
program.option('--agentArgs <agentArgs>', 'arguments for custom LFS transfer agent');
|
||||||
|
program.option(
|
||||||
|
'--storagePaths <storagePaths>',
|
||||||
|
'semicolon-separated storage paths for LFS agent',
|
||||||
|
);
|
||||||
program.parse(process.argv);
|
program.parse(process.argv);
|
||||||
Cli.options = program.opts();
|
Cli.options = program.opts();
|
||||||
|
|
||||||
@@ -61,26 +63,15 @@ export class Cli {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async RunCli(): Promise<void> {
|
static async RunCli(): Promise<void> {
|
||||||
GitHub.githubInputEnabled = false;
|
|
||||||
if (Cli.options!['populateOverride'] === `true`) {
|
|
||||||
await CloudRunnerQueryOverride.PopulateQueryOverrideInput();
|
|
||||||
}
|
|
||||||
if (Cli.options!['logInput']) {
|
|
||||||
Cli.logInput();
|
|
||||||
}
|
|
||||||
const results = CliFunctionsRepository.GetCliFunctions(Cli.options?.mode);
|
const results = CliFunctionsRepository.GetCliFunctions(Cli.options?.mode);
|
||||||
CloudRunnerLogger.log(`Entrypoint: ${results.key}`);
|
if (!results) {
|
||||||
|
throw new Error(
|
||||||
|
`Unknown CLI mode: ${Cli.options?.mode}. Orchestrator CLI features require @game-ci/orchestrator.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
core.info(`Entrypoint: ${results.key}`);
|
||||||
Cli.options!.versioning = 'None';
|
Cli.options!.versioning = 'None';
|
||||||
|
|
||||||
CloudRunner.buildParameters = await BuildParameters.create();
|
|
||||||
CloudRunner.buildParameters.buildGuid = process.env.BUILD_GUID || ``;
|
|
||||||
CloudRunnerLogger.log(`Build Params:
|
|
||||||
${JSON.stringify(CloudRunner.buildParameters, undefined, 4)}
|
|
||||||
`);
|
|
||||||
CloudRunner.lockedWorkspace = process.env.LOCKED_WORKSPACE || ``;
|
|
||||||
CloudRunnerLogger.log(`Locked Workspace: ${CloudRunner.lockedWorkspace}`);
|
|
||||||
await CloudRunner.setup(CloudRunner.buildParameters);
|
|
||||||
|
|
||||||
return await results.target[results.propertyKey](Cli.options);
|
return await results.target[results.propertyKey](Cli.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +79,9 @@ export class Cli {
|
|||||||
private static logInput() {
|
private static logInput() {
|
||||||
core.info(`\n`);
|
core.info(`\n`);
|
||||||
core.info(`INPUT:`);
|
core.info(`INPUT:`);
|
||||||
const properties = CloudRunnerOptionsReader.GetProperties();
|
const properties = Object.getOwnPropertyNames(Input).filter(
|
||||||
|
(p) => p !== 'length' && p !== 'prototype' && p !== 'name',
|
||||||
|
);
|
||||||
for (const element of properties) {
|
for (const element of properties) {
|
||||||
if (
|
if (
|
||||||
element in Input &&
|
element in Input &&
|
||||||
@@ -104,100 +97,4 @@ export class Cli {
|
|||||||
}
|
}
|
||||||
core.info(`\n`);
|
core.info(`\n`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@CliFunction(`cli-build`, `runs a cloud runner build`)
|
|
||||||
public static async CLIBuild(): Promise<string> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
const baseImage = new ImageTag(buildParameter);
|
|
||||||
|
|
||||||
return await CloudRunner.run(buildParameter, baseImage.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`async-workflow`, `runs a cloud runner build`)
|
|
||||||
public static async asyncronousWorkflow(): Promise<string> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
const baseImage = new ImageTag(buildParameter);
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
|
|
||||||
return await CloudRunner.run(buildParameter, baseImage.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
|
||||||
public static async checksUpdate() {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
const input = JSON.parse(process.env.CHECKS_UPDATE || ``);
|
|
||||||
core.info(`Checks Update ${process.env.CHECKS_UPDATE}`);
|
|
||||||
if (input.mode === `create`) {
|
|
||||||
throw new Error(`Not supported: only use update`);
|
|
||||||
} else if (input.mode === `update`) {
|
|
||||||
await GitHub.updateGitHubCheckRequest(input.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`garbage-collect`, `runs garbage collection`)
|
|
||||||
public static async GarbageCollect(): Promise<string> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
|
|
||||||
return await CloudRunner.Provider.garbageCollect(``, false, 0, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`list-resources`, `lists active resources`)
|
|
||||||
public static async ListResources(): Promise<string[]> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
const result = await CloudRunner.Provider.listResources();
|
|
||||||
CloudRunnerLogger.log(JSON.stringify(result, undefined, 4));
|
|
||||||
|
|
||||||
return result.map((x) => x.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`list-worfklow`, `lists running workflows`)
|
|
||||||
public static async ListWorfklow(): Promise<string[]> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
|
|
||||||
return (await CloudRunner.Provider.listWorkflow()).map((x) => x.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`watch`, `follows logs of a running workflow`)
|
|
||||||
public static async Watch(): Promise<string> {
|
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
|
|
||||||
return await CloudRunner.Provider.watchWorkflow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@CliFunction(`remote-cli-post-build`, `runs a cloud runner build`)
|
|
||||||
public static async PostCLIBuild(): Promise<string> {
|
|
||||||
core.info(`Running POST build tasks`);
|
|
||||||
|
|
||||||
await Caching.PushToCache(
|
|
||||||
CloudRunnerFolders.ToLinuxFolder(`${CloudRunnerFolders.cacheFolderForCacheKeyFull}/Library`),
|
|
||||||
CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.libraryFolderAbsolute),
|
|
||||||
`lib-${CloudRunner.buildParameters.buildGuid}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
await Caching.PushToCache(
|
|
||||||
CloudRunnerFolders.ToLinuxFolder(`${CloudRunnerFolders.cacheFolderForCacheKeyFull}/build`),
|
|
||||||
CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.projectBuildFolderAbsolute),
|
|
||||||
`build-${CloudRunner.buildParameters.buildGuid}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!BuildParameters.shouldUseRetainedWorkspaceMode(CloudRunner.buildParameters)) {
|
|
||||||
await CloudRunnerSystem.Run(
|
|
||||||
`rm -r ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute)}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await RemoteClient.runCustomHookFiles(`after-build`);
|
|
||||||
|
|
||||||
return new Promise((result) => result(``));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,180 +0,0 @@
|
|||||||
import AwsBuildPlatform from './providers/aws';
|
|
||||||
import { BuildParameters, Input } from '..';
|
|
||||||
import Kubernetes from './providers/k8s';
|
|
||||||
import CloudRunnerLogger from './services/core/cloud-runner-logger';
|
|
||||||
import { CloudRunnerStepParameters } from './options/cloud-runner-step-parameters';
|
|
||||||
import { WorkflowCompositionRoot } from './workflows/workflow-composition-root';
|
|
||||||
import { CloudRunnerError } from './error/cloud-runner-error';
|
|
||||||
import { TaskParameterSerializer } from './services/core/task-parameter-serializer';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import CloudRunnerSecret from './options/cloud-runner-secret';
|
|
||||||
import { ProviderInterface } from './providers/provider-interface';
|
|
||||||
import CloudRunnerEnvironmentVariable from './options/cloud-runner-environment-variable';
|
|
||||||
import TestCloudRunner from './providers/test';
|
|
||||||
import LocalCloudRunner from './providers/local';
|
|
||||||
import LocalDockerCloudRunner from './providers/docker';
|
|
||||||
import GitHub from '../github';
|
|
||||||
import SharedWorkspaceLocking from './services/core/shared-workspace-locking';
|
|
||||||
import { FollowLogStreamService } from './services/core/follow-log-stream-service';
|
|
||||||
|
|
||||||
class CloudRunner {
|
|
||||||
public static Provider: ProviderInterface;
|
|
||||||
public static buildParameters: BuildParameters;
|
|
||||||
private static defaultSecrets: CloudRunnerSecret[];
|
|
||||||
private static cloudRunnerEnvironmentVariables: CloudRunnerEnvironmentVariable[];
|
|
||||||
static lockedWorkspace: string = ``;
|
|
||||||
public static readonly retainedWorkspacePrefix: string = `retained-workspace`;
|
|
||||||
public static get isCloudRunnerEnvironment() {
|
|
||||||
return process.env[`GITHUB_ACTIONS`] !== `true`;
|
|
||||||
}
|
|
||||||
public static get isCloudRunnerAsyncEnvironment() {
|
|
||||||
return process.env[`ASYNC_WORKFLOW`] === `true`;
|
|
||||||
}
|
|
||||||
public static async setup(buildParameters: BuildParameters) {
|
|
||||||
CloudRunnerLogger.setup();
|
|
||||||
CloudRunnerLogger.log(`Setting up cloud runner`);
|
|
||||||
CloudRunner.buildParameters = buildParameters;
|
|
||||||
if (CloudRunner.buildParameters.githubCheckId === ``) {
|
|
||||||
CloudRunner.buildParameters.githubCheckId = await GitHub.createGitHubCheck(CloudRunner.buildParameters.buildGuid);
|
|
||||||
}
|
|
||||||
CloudRunner.setupSelectedBuildPlatform();
|
|
||||||
CloudRunner.defaultSecrets = TaskParameterSerializer.readDefaultSecrets();
|
|
||||||
CloudRunner.cloudRunnerEnvironmentVariables =
|
|
||||||
TaskParameterSerializer.createCloudRunnerEnvironmentVariables(buildParameters);
|
|
||||||
if (GitHub.githubInputEnabled) {
|
|
||||||
const buildParameterPropertyNames = Object.getOwnPropertyNames(buildParameters);
|
|
||||||
for (const element of CloudRunner.cloudRunnerEnvironmentVariables) {
|
|
||||||
// CloudRunnerLogger.log(`Cloud Runner output ${Input.ToEnvVarFormat(element.name)} = ${element.value}`);
|
|
||||||
core.setOutput(Input.ToEnvVarFormat(element.name), element.value);
|
|
||||||
}
|
|
||||||
for (const element of buildParameterPropertyNames) {
|
|
||||||
// CloudRunnerLogger.log(`Cloud Runner output ${Input.ToEnvVarFormat(element)} = ${buildParameters[element]}`);
|
|
||||||
core.setOutput(Input.ToEnvVarFormat(element), buildParameters[element]);
|
|
||||||
}
|
|
||||||
core.setOutput(
|
|
||||||
Input.ToEnvVarFormat(`buildArtifact`),
|
|
||||||
`build-${CloudRunner.buildParameters.buildGuid}.tar${
|
|
||||||
CloudRunner.buildParameters.useCompressionStrategy ? '.lz4' : ''
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
FollowLogStreamService.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static setupSelectedBuildPlatform() {
|
|
||||||
CloudRunnerLogger.log(`Cloud Runner platform selected ${CloudRunner.buildParameters.providerStrategy}`);
|
|
||||||
switch (CloudRunner.buildParameters.providerStrategy) {
|
|
||||||
case 'k8s':
|
|
||||||
CloudRunner.Provider = new Kubernetes(CloudRunner.buildParameters);
|
|
||||||
break;
|
|
||||||
case 'aws':
|
|
||||||
CloudRunner.Provider = new AwsBuildPlatform(CloudRunner.buildParameters);
|
|
||||||
break;
|
|
||||||
case 'test':
|
|
||||||
CloudRunner.Provider = new TestCloudRunner();
|
|
||||||
break;
|
|
||||||
case 'local-docker':
|
|
||||||
CloudRunner.Provider = new LocalDockerCloudRunner();
|
|
||||||
break;
|
|
||||||
case 'local-system':
|
|
||||||
CloudRunner.Provider = new LocalCloudRunner();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async run(buildParameters: BuildParameters, baseImage: string) {
|
|
||||||
await CloudRunner.setup(buildParameters);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Setup shared cloud runner resources');
|
|
||||||
await CloudRunner.Provider.setupWorkflow(
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
|
||||||
CloudRunner.buildParameters.branch,
|
|
||||||
CloudRunner.defaultSecrets,
|
|
||||||
);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
try {
|
|
||||||
if (buildParameters.maxRetainedWorkspaces > 0) {
|
|
||||||
CloudRunner.lockedWorkspace = SharedWorkspaceLocking.NewWorkspaceName();
|
|
||||||
|
|
||||||
const result = await SharedWorkspaceLocking.GetLockedWorkspace(
|
|
||||||
CloudRunner.lockedWorkspace,
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
CloudRunnerLogger.logLine(`Using retained workspace ${CloudRunner.lockedWorkspace}`);
|
|
||||||
CloudRunner.cloudRunnerEnvironmentVariables = [
|
|
||||||
...CloudRunner.cloudRunnerEnvironmentVariables,
|
|
||||||
{ name: `LOCKED_WORKSPACE`, value: CloudRunner.lockedWorkspace },
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
CloudRunnerLogger.log(`Max retained workspaces reached ${buildParameters.maxRetainedWorkspaces}`);
|
|
||||||
buildParameters.maxRetainedWorkspaces = 0;
|
|
||||||
CloudRunner.lockedWorkspace = ``;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const content = { ...CloudRunner.buildParameters };
|
|
||||||
content.gitPrivateToken = ``;
|
|
||||||
content.unitySerial = ``;
|
|
||||||
const jsonContent = JSON.stringify(content, undefined, 4);
|
|
||||||
await GitHub.updateGitHubCheck(jsonContent, CloudRunner.buildParameters.buildGuid);
|
|
||||||
const output = await new WorkflowCompositionRoot().run(
|
|
||||||
new CloudRunnerStepParameters(
|
|
||||||
baseImage,
|
|
||||||
CloudRunner.cloudRunnerEnvironmentVariables,
|
|
||||||
CloudRunner.defaultSecrets,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Cleanup shared cloud runner resources');
|
|
||||||
await CloudRunner.Provider.cleanupWorkflow(
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
|
||||||
CloudRunner.buildParameters.branch,
|
|
||||||
CloudRunner.defaultSecrets,
|
|
||||||
);
|
|
||||||
CloudRunnerLogger.log(`Cleanup complete`);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, `success`, `success`, `completed`);
|
|
||||||
|
|
||||||
if (BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
|
||||||
const workspace = CloudRunner.lockedWorkspace || ``;
|
|
||||||
await SharedWorkspaceLocking.ReleaseWorkspace(
|
|
||||||
workspace,
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
|
||||||
);
|
|
||||||
const isLocked = await SharedWorkspaceLocking.IsWorkspaceLocked(workspace, CloudRunner.buildParameters);
|
|
||||||
if (isLocked) {
|
|
||||||
throw new Error(
|
|
||||||
`still locked after releasing ${await SharedWorkspaceLocking.GetAllLocksForWorkspace(
|
|
||||||
workspace,
|
|
||||||
buildParameters,
|
|
||||||
)}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
CloudRunner.lockedWorkspace = ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
await GitHub.triggerWorkflowOnComplete(CloudRunner.buildParameters.finalHooks);
|
|
||||||
|
|
||||||
if (buildParameters.constantGarbageCollection) {
|
|
||||||
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageMaxAge, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
} catch (error: any) {
|
|
||||||
CloudRunnerLogger.log(JSON.stringify(error, undefined, 4));
|
|
||||||
await GitHub.updateGitHubCheck(
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
`Failed - Error ${error?.message || error}`,
|
|
||||||
`failure`,
|
|
||||||
`completed`,
|
|
||||||
);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
await CloudRunnerError.handleException(error, CloudRunner.buildParameters, CloudRunner.defaultSecrets);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default CloudRunner;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import CloudRunnerLogger from '../services/core/cloud-runner-logger';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import CloudRunner from '../cloud-runner';
|
|
||||||
import CloudRunnerSecret from '../options/cloud-runner-secret';
|
|
||||||
import BuildParameters from '../../build-parameters';
|
|
||||||
|
|
||||||
export class CloudRunnerError {
|
|
||||||
public static async handleException(error: unknown, buildParameters: BuildParameters, secrets: CloudRunnerSecret[]) {
|
|
||||||
CloudRunnerLogger.error(JSON.stringify(error, undefined, 4));
|
|
||||||
core.setFailed('Cloud Runner failed');
|
|
||||||
if (CloudRunner.Provider !== undefined) {
|
|
||||||
await CloudRunner.Provider.cleanupWorkflow(
|
|
||||||
buildParameters.buildGuid,
|
|
||||||
buildParameters,
|
|
||||||
buildParameters.branch,
|
|
||||||
secrets,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
class CloudRunnerConstants {
|
|
||||||
static alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
||||||
}
|
|
||||||
export default CloudRunnerConstants;
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
class CloudRunnerEnvironmentVariable {
|
|
||||||
public name!: string;
|
|
||||||
public value!: string;
|
|
||||||
}
|
|
||||||
export default CloudRunnerEnvironmentVariable;
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
import path from 'node:path';
|
|
||||||
import CloudRunnerOptions from './cloud-runner-options';
|
|
||||||
import CloudRunner from '../cloud-runner';
|
|
||||||
import BuildParameters from '../../build-parameters';
|
|
||||||
|
|
||||||
export class CloudRunnerFolders {
|
|
||||||
public static readonly repositoryFolder = 'repo';
|
|
||||||
|
|
||||||
public static ToLinuxFolder(folder: string) {
|
|
||||||
return folder.replace(/\\/g, `/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only the following paths that do not start a path.join with another "Full" suffixed property need to start with an absolute /
|
|
||||||
|
|
||||||
public static get uniqueCloudRunnerJobFolderAbsolute(): string {
|
|
||||||
return CloudRunner.buildParameters && BuildParameters.shouldUseRetainedWorkspaceMode(CloudRunner.buildParameters)
|
|
||||||
? path.join(`/`, CloudRunnerFolders.buildVolumeFolder, CloudRunner.lockedWorkspace)
|
|
||||||
: path.join(`/`, CloudRunnerFolders.buildVolumeFolder, CloudRunner.buildParameters.buildGuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get cacheFolderForAllFull(): string {
|
|
||||||
return path.join('/', CloudRunnerFolders.buildVolumeFolder, CloudRunnerFolders.cacheFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get cacheFolderForCacheKeyFull(): string {
|
|
||||||
return path.join(
|
|
||||||
'/',
|
|
||||||
CloudRunnerFolders.buildVolumeFolder,
|
|
||||||
CloudRunnerFolders.cacheFolder,
|
|
||||||
CloudRunner.buildParameters.cacheKey,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get builderPathAbsolute(): string {
|
|
||||||
return path.join(
|
|
||||||
CloudRunnerOptions.useSharedBuilder
|
|
||||||
? `/${CloudRunnerFolders.buildVolumeFolder}`
|
|
||||||
: CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute,
|
|
||||||
`builder`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get repoPathAbsolute(): string {
|
|
||||||
return path.join(CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute, CloudRunnerFolders.repositoryFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get projectPathAbsolute(): string {
|
|
||||||
return path.join(CloudRunnerFolders.repoPathAbsolute, CloudRunner.buildParameters.projectPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get libraryFolderAbsolute(): string {
|
|
||||||
return path.join(CloudRunnerFolders.projectPathAbsolute, `Library`);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get projectBuildFolderAbsolute(): string {
|
|
||||||
return path.join(CloudRunnerFolders.repoPathAbsolute, CloudRunner.buildParameters.buildPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get lfsFolderAbsolute(): string {
|
|
||||||
return path.join(CloudRunnerFolders.repoPathAbsolute, `.git`, `lfs`);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get purgeRemoteCaching(): boolean {
|
|
||||||
return process.env.PURGE_REMOTE_BUILDER_CACHE !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get lfsCacheFolderFull() {
|
|
||||||
return path.join(CloudRunnerFolders.cacheFolderForCacheKeyFull, `lfs`);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get libraryCacheFolderFull() {
|
|
||||||
return path.join(CloudRunnerFolders.cacheFolderForCacheKeyFull, `Library`);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get unityBuilderRepoUrl(): string {
|
|
||||||
return `https://${CloudRunner.buildParameters.gitPrivateToken}@github.com/game-ci/unity-builder.git`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get targetBuildRepoUrl(): string {
|
|
||||||
return `https://${CloudRunner.buildParameters.gitPrivateToken}@github.com/${CloudRunner.buildParameters.githubRepo}.git`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get buildVolumeFolder() {
|
|
||||||
return 'data';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get cacheFolder() {
|
|
||||||
return 'cache';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { customAlphabet } from 'nanoid';
|
|
||||||
import CloudRunnerConstants from './cloud-runner-constants';
|
|
||||||
|
|
||||||
class CloudRunnerNamespace {
|
|
||||||
static generateGuid(runNumber: string | number, platform: string) {
|
|
||||||
const nanoid = customAlphabet(CloudRunnerConstants.alphabet, 4);
|
|
||||||
|
|
||||||
return `${runNumber}-${platform.toLowerCase().replace('standalone', '')}-${nanoid()}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default CloudRunnerNamespace;
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import Input from '../../input';
|
|
||||||
import CloudRunnerOptions from './cloud-runner-options';
|
|
||||||
|
|
||||||
class CloudRunnerOptionsReader {
|
|
||||||
static GetProperties() {
|
|
||||||
return [...Object.getOwnPropertyNames(Input), ...Object.getOwnPropertyNames(CloudRunnerOptions)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CloudRunnerOptionsReader;
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
import { Cli } from '../../cli/cli';
|
|
||||||
import CloudRunnerQueryOverride from './cloud-runner-query-override';
|
|
||||||
import GitHub from '../../github';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
|
|
||||||
class CloudRunnerOptions {
|
|
||||||
// ### ### ###
|
|
||||||
// Input Handling
|
|
||||||
// ### ### ###
|
|
||||||
public static getInput(query: string): string | undefined {
|
|
||||||
if (GitHub.githubInputEnabled) {
|
|
||||||
const coreInput = core.getInput(query);
|
|
||||||
if (coreInput && coreInput !== '') {
|
|
||||||
return coreInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const alternativeQuery = CloudRunnerOptions.ToEnvVarFormat(query);
|
|
||||||
|
|
||||||
// Query input sources
|
|
||||||
if (Cli.query(query, alternativeQuery)) {
|
|
||||||
return Cli.query(query, alternativeQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CloudRunnerQueryOverride.query(query, alternativeQuery)) {
|
|
||||||
return CloudRunnerQueryOverride.query(query, alternativeQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env[query] !== undefined) {
|
|
||||||
return process.env[query];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alternativeQuery !== query && process.env[alternativeQuery] !== undefined) {
|
|
||||||
return process.env[alternativeQuery];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ToEnvVarFormat(input: string): string {
|
|
||||||
if (input.toUpperCase() === input) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
return input
|
|
||||||
.replace(/([A-Z])/g, ' $1')
|
|
||||||
.trim()
|
|
||||||
.toUpperCase()
|
|
||||||
.replace(/ /g, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Provider parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get region(): string {
|
|
||||||
return CloudRunnerOptions.getInput('region') || 'eu-west-2';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// GitHub parameters
|
|
||||||
// ### ### ###
|
|
||||||
static get githubChecks(): boolean {
|
|
||||||
const value = CloudRunnerOptions.getInput('githubChecks');
|
|
||||||
|
|
||||||
return value === `true` || false;
|
|
||||||
}
|
|
||||||
static get githubCheckId(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubCheckId') || ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get githubOwner(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubOwner') || CloudRunnerOptions.githubRepo?.split(`/`)[0] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get githubRepoName(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubRepoName') || CloudRunnerOptions.githubRepo?.split(`/`)[1] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get finalHooks(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('finalHooks')?.split(',') || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Git syncronization parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get githubRepo(): string | undefined {
|
|
||||||
return CloudRunnerOptions.getInput('GITHUB_REPOSITORY') || CloudRunnerOptions.getInput('GITHUB_REPO') || undefined;
|
|
||||||
}
|
|
||||||
static get branch(): string {
|
|
||||||
if (CloudRunnerOptions.getInput(`GITHUB_REF`)) {
|
|
||||||
return (
|
|
||||||
CloudRunnerOptions.getInput(`GITHUB_REF`)?.replace('refs/', '').replace(`head/`, '').replace(`heads/`, '') || ``
|
|
||||||
);
|
|
||||||
} else if (CloudRunnerOptions.getInput('branch')) {
|
|
||||||
return CloudRunnerOptions.getInput('branch') || ``;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Cloud Runner parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get buildPlatform(): string {
|
|
||||||
const input = CloudRunnerOptions.getInput('buildPlatform');
|
|
||||||
if (input) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
if (CloudRunnerOptions.providerStrategy !== 'local') {
|
|
||||||
return 'linux';
|
|
||||||
}
|
|
||||||
|
|
||||||
return ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get cloudRunnerBranch(): string {
|
|
||||||
return CloudRunnerOptions.getInput('cloudRunnerBranch') || 'main';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get providerStrategy(): string {
|
|
||||||
const provider =
|
|
||||||
CloudRunnerOptions.getInput('cloudRunnerCluster') || CloudRunnerOptions.getInput('providerStrategy');
|
|
||||||
if (Cli.isCliMode) {
|
|
||||||
return provider || 'aws';
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider || 'local';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get containerCpu(): string {
|
|
||||||
return CloudRunnerOptions.getInput('containerCpu') || `1024`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get containerMemory(): string {
|
|
||||||
return CloudRunnerOptions.getInput('containerMemory') || `3072`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get customJob(): string {
|
|
||||||
return CloudRunnerOptions.getInput('customJob') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Custom commands from files parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get containerHookFiles(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('containerHookFiles')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
static get commandHookFiles(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('commandHookFiles')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Custom commands from yaml parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get commandHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('commandHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get postBuildContainerHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('postBuildContainerHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get preBuildContainerHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('preBuildContainerHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Input override handling
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get pullInputList(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('pullInputList')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
static get inputPullCommand(): string {
|
|
||||||
const value = CloudRunnerOptions.getInput('inputPullCommand');
|
|
||||||
|
|
||||||
if (value === 'gcp-secret-manager') {
|
|
||||||
return 'gcloud secrets versions access 1 --secret="{0}"';
|
|
||||||
} else if (value === 'aws-secret-manager') {
|
|
||||||
return 'aws secretsmanager get-secret-value --secret-id {0}';
|
|
||||||
}
|
|
||||||
|
|
||||||
return value || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Aws
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get awsStackName() {
|
|
||||||
return CloudRunnerOptions.getInput('awsStackName') || 'game-ci';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// K8s
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get kubeConfig(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeConfig') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeVolume(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeVolume') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeVolumeSize(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeVolumeSize') || '25Gi';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeStorageClass(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeStorageClass') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Caching
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get cacheKey(): string {
|
|
||||||
return CloudRunnerOptions.getInput('cacheKey') || CloudRunnerOptions.branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Utility Parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get cloudRunnerDebug(): boolean {
|
|
||||||
return (
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerTests`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebug`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebugTree`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebugEnv`) === `true` ||
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static get skipLfs(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`skipLfs`) === `true`;
|
|
||||||
}
|
|
||||||
static get skipCache(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`skipCache`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get asyncCloudRunner(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput('asyncCloudRunner') === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useLargePackages(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useLargePackages`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useSharedBuilder(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useSharedBuilder`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useCompressionStrategy(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useCompressionStrategy`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useCleanupCron(): boolean {
|
|
||||||
return (CloudRunnerOptions.getInput(`useCleanupCron`) || 'true') === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Retained Workspace
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
public static get maxRetainedWorkspaces(): string {
|
|
||||||
return CloudRunnerOptions.getInput(`maxRetainedWorkspaces`) || `0`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Garbage Collection
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get garbageMaxAge(): number {
|
|
||||||
return Number(CloudRunnerOptions.getInput(`garbageMaxAge`)) || 24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CloudRunnerOptions;
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import Input from '../../input';
|
|
||||||
import { GenericInputReader } from '../../input-readers/generic-input-reader';
|
|
||||||
import CloudRunnerOptions from './cloud-runner-options';
|
|
||||||
|
|
||||||
const formatFunction = (value: string, arguments_: any[]) => {
|
|
||||||
for (const element of arguments_) {
|
|
||||||
value = value.replace(`{${element.key}}`, element.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CloudRunnerQueryOverride {
|
|
||||||
static queryOverrides: { [key: string]: string } | undefined;
|
|
||||||
|
|
||||||
// TODO accept premade secret sources or custom secret source definition yamls
|
|
||||||
|
|
||||||
public static query(key: string, alternativeKey: string) {
|
|
||||||
if (CloudRunnerQueryOverride.queryOverrides && CloudRunnerQueryOverride.queryOverrides[key] !== undefined) {
|
|
||||||
return CloudRunnerQueryOverride.queryOverrides[key];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
CloudRunnerQueryOverride.queryOverrides &&
|
|
||||||
alternativeKey &&
|
|
||||||
CloudRunnerQueryOverride.queryOverrides[alternativeKey] !== undefined
|
|
||||||
) {
|
|
||||||
return CloudRunnerQueryOverride.queryOverrides[alternativeKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static shouldUseOverride(query: string) {
|
|
||||||
if (CloudRunnerOptions.inputPullCommand !== '') {
|
|
||||||
if (CloudRunnerOptions.pullInputList.length > 0) {
|
|
||||||
const doesInclude =
|
|
||||||
CloudRunnerOptions.pullInputList.includes(query) ||
|
|
||||||
CloudRunnerOptions.pullInputList.includes(Input.ToEnvVarFormat(query));
|
|
||||||
|
|
||||||
return doesInclude ? true : false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async queryOverride(query: string) {
|
|
||||||
if (!this.shouldUseOverride(query)) {
|
|
||||||
throw new Error(`Should not be trying to run override query on ${query}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await GenericInputReader.Run(
|
|
||||||
formatFunction(CloudRunnerOptions.inputPullCommand, [{ key: 0, value: query }]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async PopulateQueryOverrideInput() {
|
|
||||||
const queries = CloudRunnerOptions.pullInputList;
|
|
||||||
CloudRunnerQueryOverride.queryOverrides = {};
|
|
||||||
for (const element of queries) {
|
|
||||||
if (CloudRunnerQueryOverride.shouldUseOverride(element)) {
|
|
||||||
CloudRunnerQueryOverride.queryOverrides[element] = await CloudRunnerQueryOverride.queryOverride(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default CloudRunnerQueryOverride;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
class CloudRunnerSecret {
|
|
||||||
public ParameterKey!: string;
|
|
||||||
public EnvironmentVariable!: string;
|
|
||||||
public ParameterValue!: string;
|
|
||||||
}
|
|
||||||
export default CloudRunnerSecret;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export class CloudRunnerStatics {
|
|
||||||
public static readonly logPrefix = `Cloud-Runner`;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import CloudRunnerEnvironmentVariable from './cloud-runner-environment-variable';
|
|
||||||
import CloudRunnerSecret from './cloud-runner-secret';
|
|
||||||
|
|
||||||
export class CloudRunnerStepParameters {
|
|
||||||
public image: string;
|
|
||||||
public environment: CloudRunnerEnvironmentVariable[];
|
|
||||||
public secrets: CloudRunnerSecret[];
|
|
||||||
constructor(image: string, environmentVariables: CloudRunnerEnvironmentVariable[], secrets: CloudRunnerSecret[]) {
|
|
||||||
this.image = image;
|
|
||||||
this.environment = environmentVariables;
|
|
||||||
this.secrets = secrets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import * as SDK from 'aws-sdk';
|
|
||||||
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
|
||||||
import crypto from 'node:crypto';
|
|
||||||
|
|
||||||
export class AWSBaseStack {
|
|
||||||
constructor(baseStackName: string) {
|
|
||||||
this.baseStackName = baseStackName;
|
|
||||||
}
|
|
||||||
private baseStackName: string;
|
|
||||||
|
|
||||||
async setupBaseStack(CF: SDK.CloudFormation) {
|
|
||||||
const baseStackName = this.baseStackName;
|
|
||||||
|
|
||||||
const baseStack = BaseStackFormation.formation;
|
|
||||||
|
|
||||||
// Cloud Formation Input
|
|
||||||
const describeStackInput: SDK.CloudFormation.DescribeStacksInput = {
|
|
||||||
StackName: baseStackName,
|
|
||||||
};
|
|
||||||
const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [
|
|
||||||
{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName },
|
|
||||||
];
|
|
||||||
const parametersHash = crypto
|
|
||||||
.createHash('md5')
|
|
||||||
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
|
||||||
.digest('hex');
|
|
||||||
const parameters: SDK.CloudFormation.Parameter[] = [
|
|
||||||
...parametersWithoutHash,
|
|
||||||
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
|
||||||
];
|
|
||||||
const updateInput: SDK.CloudFormation.UpdateStackInput = {
|
|
||||||
StackName: baseStackName,
|
|
||||||
TemplateBody: baseStack,
|
|
||||||
Parameters: parameters,
|
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
|
||||||
};
|
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
|
||||||
StackName: baseStackName,
|
|
||||||
TemplateBody: baseStack,
|
|
||||||
Parameters: parameters,
|
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
|
||||||
};
|
|
||||||
|
|
||||||
const stacks = await CF.listStacks({
|
|
||||||
StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'],
|
|
||||||
}).promise();
|
|
||||||
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
|
||||||
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
|
|
||||||
const describeStack = async () => {
|
|
||||||
return await CF.describeStacks(describeStackInput).promise();
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
if (!stackExists) {
|
|
||||||
CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
|
|
||||||
await CF.createStack(createStackInput).promise();
|
|
||||||
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
|
||||||
}
|
|
||||||
const CFState = await describeStack();
|
|
||||||
let stack = CFState.Stacks?.[0];
|
|
||||||
if (!stack) {
|
|
||||||
throw new Error(`Base stack doesn't exist, even after creation, stackExists check: ${stackExists}`);
|
|
||||||
}
|
|
||||||
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
|
||||||
|
|
||||||
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
|
||||||
await CF.waitFor('stackCreateComplete', describeStackInput).promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stackExists) {
|
|
||||||
CloudRunnerLogger.log(`Base stack exists (version: ${stackVersion}, local version: ${parametersHash})`);
|
|
||||||
if (parametersHash !== stackVersion) {
|
|
||||||
CloudRunnerLogger.log(`Attempting update of base stack`);
|
|
||||||
try {
|
|
||||||
await CF.updateStack(updateInput).promise();
|
|
||||||
} catch (error: any) {
|
|
||||||
if (error['message'].includes('No updates are to be performed')) {
|
|
||||||
CloudRunnerLogger.log(`No updates are to be performed`);
|
|
||||||
} else {
|
|
||||||
CloudRunnerLogger.log(`Update Failed (Stack name: ${baseStackName})`);
|
|
||||||
CloudRunnerLogger.log(error['message']);
|
|
||||||
}
|
|
||||||
CloudRunnerLogger.log(`Continuing...`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CloudRunnerLogger.log(`No update required`);
|
|
||||||
}
|
|
||||||
stack = (await describeStack()).Stacks?.[0];
|
|
||||||
if (!stack) {
|
|
||||||
throw new Error(
|
|
||||||
`Base stack doesn't exist, even after updating and creation, stackExists check: ${stackExists}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
|
||||||
await CF.waitFor('stackUpdateComplete', describeStackInput).promise();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloudRunnerLogger.log('base stack is now ready');
|
|
||||||
} catch (error) {
|
|
||||||
core.error(JSON.stringify(await describeStack(), undefined, 4));
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
|
||||||
|
|
||||||
export class AWSCloudFormationTemplates {
|
|
||||||
public static getParameterTemplate(p1: string) {
|
|
||||||
return `
|
|
||||||
${p1}:
|
|
||||||
Type: String
|
|
||||||
Default: ''
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getSecretTemplate(p1: string) {
|
|
||||||
return `
|
|
||||||
${p1}Secret:
|
|
||||||
Type: AWS::SecretsManager::Secret
|
|
||||||
Properties:
|
|
||||||
Name: '${p1}'
|
|
||||||
SecretString: !Ref ${p1}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getSecretDefinitionTemplate(p1: string, p2: string) {
|
|
||||||
return `
|
|
||||||
- Name: '${p1}'
|
|
||||||
ValueFrom: !Ref ${p2}Secret
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static insertAtTemplate(template: string, insertionKey: string, insertion: string) {
|
|
||||||
const index = template.search(insertionKey) + insertionKey.length + '\n'.length;
|
|
||||||
template = [template.slice(0, index), insertion, template.slice(index)].join('');
|
|
||||||
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readTaskCloudFormationTemplate(): string {
|
|
||||||
return TaskDefinitionFormation.formation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
|
||||||
import * as SDK from 'aws-sdk';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import CloudRunner from '../../cloud-runner';
|
|
||||||
|
|
||||||
export class AWSError {
|
|
||||||
static async handleStackCreationFailure(error: any, CF: SDK.CloudFormation, taskDefStackName: string) {
|
|
||||||
CloudRunnerLogger.log('aws error: ');
|
|
||||||
core.error(JSON.stringify(error, undefined, 4));
|
|
||||||
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
|
||||||
CloudRunnerLogger.log('Getting events and resources for task stack');
|
|
||||||
const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents;
|
|
||||||
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
import * as SDK from 'aws-sdk';
|
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
|
||||||
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
|
||||||
import { AWSError } from './aws-error';
|
|
||||||
import CloudRunner from '../../cloud-runner';
|
|
||||||
import { CleanupCronFormation } from './cloud-formations/cleanup-cron-formation';
|
|
||||||
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
|
||||||
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
|
||||||
|
|
||||||
export class AWSJobStack {
|
|
||||||
private baseStackName: string;
|
|
||||||
constructor(baseStackName: string) {
|
|
||||||
this.baseStackName = baseStackName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async setupCloudFormations(
|
|
||||||
CF: SDK.CloudFormation,
|
|
||||||
buildGuid: string,
|
|
||||||
image: string,
|
|
||||||
entrypoint: string[],
|
|
||||||
commands: string,
|
|
||||||
mountdir: string,
|
|
||||||
workingdir: string,
|
|
||||||
secrets: CloudRunnerSecret[],
|
|
||||||
): Promise<CloudRunnerAWSTaskDef> {
|
|
||||||
const taskDefStackName = `${this.baseStackName}-${buildGuid}`;
|
|
||||||
let taskDefCloudFormation = AWSCloudFormationTemplates.readTaskCloudFormationTemplate();
|
|
||||||
taskDefCloudFormation = taskDefCloudFormation.replace(
|
|
||||||
`ContainerCpu:
|
|
||||||
Default: 1024`,
|
|
||||||
`ContainerCpu:
|
|
||||||
Default: ${Number.parseInt(CloudRunner.buildParameters.containerCpu)}`,
|
|
||||||
);
|
|
||||||
taskDefCloudFormation = taskDefCloudFormation.replace(
|
|
||||||
`ContainerMemory:
|
|
||||||
Default: 2048`,
|
|
||||||
`ContainerMemory:
|
|
||||||
Default: ${Number.parseInt(CloudRunner.buildParameters.containerMemory)}`,
|
|
||||||
);
|
|
||||||
if (!CloudRunnerOptions.asyncCloudRunner) {
|
|
||||||
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
|
||||||
taskDefCloudFormation,
|
|
||||||
'# template resources logstream',
|
|
||||||
TaskDefinitionFormation.streamLogs,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (const secret of secrets) {
|
|
||||||
secret.ParameterKey = `${buildGuid.replace(/[^\dA-Za-z]/g, '')}${secret.ParameterKey.replace(
|
|
||||||
/[^\dA-Za-z]/g,
|
|
||||||
'',
|
|
||||||
)}`;
|
|
||||||
if (typeof secret.ParameterValue == 'number') {
|
|
||||||
secret.ParameterValue = `${secret.ParameterValue}`;
|
|
||||||
}
|
|
||||||
if (!secret.ParameterValue || secret.ParameterValue === '') {
|
|
||||||
secrets = secrets.filter((x) => x !== secret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
|
||||||
taskDefCloudFormation,
|
|
||||||
'p1 - input',
|
|
||||||
AWSCloudFormationTemplates.getParameterTemplate(secret.ParameterKey),
|
|
||||||
);
|
|
||||||
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
|
||||||
taskDefCloudFormation,
|
|
||||||
'# template resources secrets',
|
|
||||||
AWSCloudFormationTemplates.getSecretTemplate(`${secret.ParameterKey}`),
|
|
||||||
);
|
|
||||||
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
|
||||||
taskDefCloudFormation,
|
|
||||||
'p3 - container def',
|
|
||||||
AWSCloudFormationTemplates.getSecretDefinitionTemplate(secret.EnvironmentVariable, secret.ParameterKey),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const secretsMappedToCloudFormationParameters = secrets.map((x) => {
|
|
||||||
return { ParameterKey: x.ParameterKey.replace(/[^\dA-Za-z]/g, ''), ParameterValue: x.ParameterValue };
|
|
||||||
});
|
|
||||||
const logGroupName = `${this.baseStackName}/${taskDefStackName}`;
|
|
||||||
const parameters = [
|
|
||||||
{
|
|
||||||
ParameterKey: 'EnvironmentName',
|
|
||||||
ParameterValue: this.baseStackName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'ImageUrl',
|
|
||||||
ParameterValue: image,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'ServiceName',
|
|
||||||
ParameterValue: taskDefStackName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'LogGroupName',
|
|
||||||
ParameterValue: logGroupName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'Command',
|
|
||||||
ParameterValue: 'echo "this template should be overwritten when running a task"',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'EntryPoint',
|
|
||||||
ParameterValue: entrypoint.join(','),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'WorkingDirectory',
|
|
||||||
ParameterValue: workingdir,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'EFSMountDirectory',
|
|
||||||
ParameterValue: mountdir,
|
|
||||||
},
|
|
||||||
...secretsMappedToCloudFormationParameters,
|
|
||||||
];
|
|
||||||
CloudRunnerLogger.log(
|
|
||||||
`Starting AWS job with memory: ${CloudRunner.buildParameters.containerMemory} cpu: ${CloudRunner.buildParameters.containerCpu}`,
|
|
||||||
);
|
|
||||||
let previousStackExists = true;
|
|
||||||
while (previousStackExists) {
|
|
||||||
previousStackExists = false;
|
|
||||||
const stacks = await CF.listStacks().promise();
|
|
||||||
if (!stacks.StackSummaries) {
|
|
||||||
throw new Error('Faild to get stacks');
|
|
||||||
}
|
|
||||||
for (let index = 0; index < stacks.StackSummaries.length; index++) {
|
|
||||||
const element = stacks.StackSummaries[index];
|
|
||||||
if (element.StackName === taskDefStackName && element.StackStatus !== 'DELETE_COMPLETE') {
|
|
||||||
previousStackExists = true;
|
|
||||||
CloudRunnerLogger.log(`Previous stack still exists: ${JSON.stringify(element)}`);
|
|
||||||
await new Promise((promise) => setTimeout(promise, 5000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
|
||||||
StackName: taskDefStackName,
|
|
||||||
TemplateBody: taskDefCloudFormation,
|
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
|
||||||
Parameters: parameters,
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
|
||||||
await CF.createStack(createStackInput).promise();
|
|
||||||
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
|
|
||||||
const describeStack = await CF.describeStacks({ StackName: taskDefStackName }).promise();
|
|
||||||
for (const parameter of parameters) {
|
|
||||||
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
|
||||||
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
await AWSError.handleStackCreationFailure(error, CF, taskDefStackName);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createCleanupStackInput: SDK.CloudFormation.CreateStackInput = {
|
|
||||||
StackName: `${taskDefStackName}-cleanup`,
|
|
||||||
TemplateBody: CleanupCronFormation.formation,
|
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
|
||||||
Parameters: [
|
|
||||||
{
|
|
||||||
ParameterKey: 'StackName',
|
|
||||||
ParameterValue: taskDefStackName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'DeleteStackName',
|
|
||||||
ParameterValue: `${taskDefStackName}-cleanup`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'TTL',
|
|
||||||
ParameterValue: `1080`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'BUILDGUID',
|
|
||||||
ParameterValue: CloudRunner.buildParameters.buildGuid,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ParameterKey: 'EnvironmentName',
|
|
||||||
ParameterValue: this.baseStackName,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
if (CloudRunnerOptions.useCleanupCron) {
|
|
||||||
try {
|
|
||||||
CloudRunnerLogger.log(`Creating job cleanup formation`);
|
|
||||||
await CF.createStack(createCleanupStackInput).promise();
|
|
||||||
|
|
||||||
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
|
||||||
} catch (error) {
|
|
||||||
await AWSError.handleStackCreationFailure(error, CF, taskDefStackName);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const taskDefResources = (
|
|
||||||
await CF.describeStackResources({
|
|
||||||
StackName: taskDefStackName,
|
|
||||||
}).promise()
|
|
||||||
).StackResources;
|
|
||||||
|
|
||||||
const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources;
|
|
||||||
|
|
||||||
return {
|
|
||||||
taskDefStackName,
|
|
||||||
taskDefCloudFormation,
|
|
||||||
taskDefResources,
|
|
||||||
baseResources,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
import * as AWS from 'aws-sdk';
|
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
|
||||||
import * as zlib from 'node:zlib';
|
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
|
||||||
import { Input } from '../../..';
|
|
||||||
import CloudRunner from '../../cloud-runner';
|
|
||||||
import { CommandHookService } from '../../services/hooks/command-hook-service';
|
|
||||||
import { FollowLogStreamService } from '../../services/core/follow-log-stream-service';
|
|
||||||
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
|
||||||
import GitHub from '../../../github';
|
|
||||||
|
|
||||||
class AWSTaskRunner {
|
|
||||||
public static ECS: AWS.ECS;
|
|
||||||
public static Kinesis: AWS.Kinesis;
|
|
||||||
private static readonly encodedUnderscore = `$252F`;
|
|
||||||
static async runTask(
|
|
||||||
taskDef: CloudRunnerAWSTaskDef,
|
|
||||||
environment: CloudRunnerEnvironmentVariable[],
|
|
||||||
commands: string,
|
|
||||||
): Promise<{ output: string; shouldCleanup: boolean }> {
|
|
||||||
const cluster = taskDef.baseResources?.find((x) => x.LogicalResourceId === 'ECSCluster')?.PhysicalResourceId || '';
|
|
||||||
const taskDefinition =
|
|
||||||
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'TaskDefinition')?.PhysicalResourceId || '';
|
|
||||||
const SubnetOne =
|
|
||||||
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')?.PhysicalResourceId || '';
|
|
||||||
const SubnetTwo =
|
|
||||||
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')?.PhysicalResourceId || '';
|
|
||||||
const ContainerSecurityGroup =
|
|
||||||
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')?.PhysicalResourceId || '';
|
|
||||||
const streamName =
|
|
||||||
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'KinesisStream')?.PhysicalResourceId || '';
|
|
||||||
|
|
||||||
const runParameters = {
|
|
||||||
cluster,
|
|
||||||
taskDefinition,
|
|
||||||
platformVersion: '1.4.0',
|
|
||||||
overrides: {
|
|
||||||
containerOverrides: [
|
|
||||||
{
|
|
||||||
name: taskDef.taskDefStackName,
|
|
||||||
environment,
|
|
||||||
command: ['-c', CommandHookService.ApplyHooksToCommands(commands, CloudRunner.buildParameters)],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
launchType: 'FARGATE',
|
|
||||||
networkConfiguration: {
|
|
||||||
awsvpcConfiguration: {
|
|
||||||
subnets: [SubnetOne, SubnetTwo],
|
|
||||||
assignPublicIp: 'ENABLED',
|
|
||||||
securityGroups: [ContainerSecurityGroup],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (JSON.stringify(runParameters.overrides.containerOverrides).length > 8192) {
|
|
||||||
CloudRunnerLogger.log(JSON.stringify(runParameters.overrides.containerOverrides, undefined, 4));
|
|
||||||
throw new Error(`Container Overrides length must be at most 8192`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const task = await AWSTaskRunner.ECS.runTask(runParameters).promise();
|
|
||||||
const taskArn = task.tasks?.[0].taskArn || '';
|
|
||||||
CloudRunnerLogger.log('Cloud runner job is starting');
|
|
||||||
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
|
||||||
CloudRunnerLogger.log(
|
|
||||||
`Cloud runner job status is running ${(await AWSTaskRunner.describeTasks(cluster, taskArn))?.lastStatus} Async:${
|
|
||||||
CloudRunnerOptions.asyncCloudRunner
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
if (CloudRunnerOptions.asyncCloudRunner) {
|
|
||||||
const shouldCleanup: boolean = false;
|
|
||||||
const output: string = '';
|
|
||||||
CloudRunnerLogger.log(`Watch Cloud Runner To End: false`);
|
|
||||||
|
|
||||||
return { output, shouldCleanup };
|
|
||||||
}
|
|
||||||
|
|
||||||
CloudRunnerLogger.log(`Streaming...`);
|
|
||||||
const { output, shouldCleanup } = await this.streamLogsUntilTaskStops(cluster, taskArn, streamName);
|
|
||||||
let exitCode;
|
|
||||||
let containerState;
|
|
||||||
let taskData;
|
|
||||||
while (exitCode === undefined) {
|
|
||||||
await new Promise((resolve) => resolve(10000));
|
|
||||||
taskData = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
|
||||||
containerState = taskData.containers?.[0];
|
|
||||||
exitCode = containerState?.exitCode;
|
|
||||||
}
|
|
||||||
CloudRunnerLogger.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
|
||||||
if (exitCode === undefined) {
|
|
||||||
CloudRunnerLogger.logWarning(`Undefined exitcode for container`);
|
|
||||||
}
|
|
||||||
const wasSuccessful = exitCode === 0;
|
|
||||||
if (wasSuccessful) {
|
|
||||||
CloudRunnerLogger.log(`Cloud runner job has finished successfully`);
|
|
||||||
|
|
||||||
return { output, shouldCleanup };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taskData?.stoppedReason === 'Essential container in task exited' && exitCode === 1) {
|
|
||||||
throw new Error('Container exited with code 1');
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Task failed`);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
|
||||||
try {
|
|
||||||
await AWSTaskRunner.ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
|
|
||||||
} catch (error_) {
|
|
||||||
const error = error_ as Error;
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
||||||
CloudRunnerLogger.log(
|
|
||||||
`Cloud runner job has ended ${
|
|
||||||
(await AWSTaskRunner.describeTasks(cluster, taskArn)).containers?.[0].lastStatus
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
core.setFailed(error);
|
|
||||||
core.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async describeTasks(clusterName: string, taskArn: string) {
|
|
||||||
const tasks = await AWSTaskRunner.ECS.describeTasks({
|
|
||||||
cluster: clusterName,
|
|
||||||
tasks: [taskArn],
|
|
||||||
}).promise();
|
|
||||||
if (tasks.tasks?.[0]) {
|
|
||||||
return tasks.tasks?.[0];
|
|
||||||
} else {
|
|
||||||
throw new Error('No task found');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async streamLogsUntilTaskStops(clusterName: string, taskArn: string, kinesisStreamName: string) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
||||||
CloudRunnerLogger.log(`Streaming...`);
|
|
||||||
const stream = await AWSTaskRunner.getLogStream(kinesisStreamName);
|
|
||||||
let iterator = await AWSTaskRunner.getLogIterator(stream);
|
|
||||||
|
|
||||||
const logBaseUrl = `https://${Input.region}.console.aws.amazon.com/cloudwatch/home?region=${Input.region}#logsV2:log-groups/log-group/${CloudRunner.buildParameters.awsStackName}${AWSTaskRunner.encodedUnderscore}${CloudRunner.buildParameters.awsStackName}-${CloudRunner.buildParameters.buildGuid}`;
|
|
||||||
CloudRunnerLogger.log(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`);
|
|
||||||
await GitHub.updateGitHubCheck(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`, ``);
|
|
||||||
let shouldReadLogs = true;
|
|
||||||
let shouldCleanup = true;
|
|
||||||
let timestamp: number = 0;
|
|
||||||
let output = '';
|
|
||||||
while (shouldReadLogs) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
||||||
const taskData = await AWSTaskRunner.describeTasks(clusterName, taskArn);
|
|
||||||
({ timestamp, shouldReadLogs } = AWSTaskRunner.checkStreamingShouldContinue(taskData, timestamp, shouldReadLogs));
|
|
||||||
({ iterator, shouldReadLogs, output, shouldCleanup } = await AWSTaskRunner.handleLogStreamIteration(
|
|
||||||
iterator,
|
|
||||||
shouldReadLogs,
|
|
||||||
output,
|
|
||||||
shouldCleanup,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return { output, shouldCleanup };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async handleLogStreamIteration(
|
|
||||||
iterator: string,
|
|
||||||
shouldReadLogs: boolean,
|
|
||||||
output: string,
|
|
||||||
shouldCleanup: boolean,
|
|
||||||
) {
|
|
||||||
const records = await AWSTaskRunner.Kinesis.getRecords({
|
|
||||||
ShardIterator: iterator,
|
|
||||||
}).promise();
|
|
||||||
iterator = records.NextShardIterator || '';
|
|
||||||
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
|
||||||
records,
|
|
||||||
iterator,
|
|
||||||
shouldReadLogs,
|
|
||||||
output,
|
|
||||||
shouldCleanup,
|
|
||||||
));
|
|
||||||
|
|
||||||
return { iterator, shouldReadLogs, output, shouldCleanup };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static checkStreamingShouldContinue(taskData: AWS.ECS.Task, timestamp: number, shouldReadLogs: boolean) {
|
|
||||||
if (taskData?.lastStatus === 'UNKNOWN') {
|
|
||||||
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
|
||||||
}
|
|
||||||
if (taskData?.lastStatus !== 'RUNNING') {
|
|
||||||
if (timestamp === 0) {
|
|
||||||
CloudRunnerLogger.log('## Cloud runner job stopped, streaming end of logs');
|
|
||||||
timestamp = Date.now();
|
|
||||||
}
|
|
||||||
if (timestamp !== 0 && Date.now() - timestamp > 30000) {
|
|
||||||
CloudRunnerLogger.log('## Cloud runner status is not RUNNING for 30 seconds, last query for logs');
|
|
||||||
shouldReadLogs = false;
|
|
||||||
}
|
|
||||||
CloudRunnerLogger.log(`## Status of job: ${taskData.lastStatus}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { timestamp, shouldReadLogs };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static logRecords(
|
|
||||||
records: AWS.Kinesis.GetRecordsOutput,
|
|
||||||
iterator: string,
|
|
||||||
shouldReadLogs: boolean,
|
|
||||||
output: string,
|
|
||||||
shouldCleanup: boolean,
|
|
||||||
) {
|
|
||||||
if (records.Records.length > 0 && iterator) {
|
|
||||||
for (const record of records.Records) {
|
|
||||||
const json = JSON.parse(zlib.gunzipSync(Buffer.from(record.Data as string, 'base64')).toString('utf8'));
|
|
||||||
if (json.messageType === 'DATA_MESSAGE') {
|
|
||||||
for (const logEvent of json.logEvents) {
|
|
||||||
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
|
||||||
logEvent.message,
|
|
||||||
shouldReadLogs,
|
|
||||||
shouldCleanup,
|
|
||||||
output,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { shouldReadLogs, output, shouldCleanup };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async getLogStream(kinesisStreamName: string) {
|
|
||||||
return await AWSTaskRunner.Kinesis.describeStream({
|
|
||||||
StreamName: kinesisStreamName,
|
|
||||||
}).promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async getLogIterator(stream: AWS.Kinesis.DescribeStreamOutput) {
|
|
||||||
return (
|
|
||||||
(
|
|
||||||
await AWSTaskRunner.Kinesis.getShardIterator({
|
|
||||||
ShardIteratorType: 'TRIM_HORIZON',
|
|
||||||
StreamName: stream.StreamDescription.StreamName,
|
|
||||||
ShardId: stream.StreamDescription.Shards[0].ShardId,
|
|
||||||
}).promise()
|
|
||||||
).ShardIterator || ''
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default AWSTaskRunner;
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
export class BaseStackFormation {
|
|
||||||
public static readonly baseStackDecription = `Game-CI base stack`;
|
|
||||||
public static readonly formation: string = `AWSTemplateFormatVersion: '2010-09-09'
|
|
||||||
Description: ${BaseStackFormation.baseStackDecription}
|
|
||||||
Parameters:
|
|
||||||
EnvironmentName:
|
|
||||||
Type: String
|
|
||||||
Default: development
|
|
||||||
Description: 'Your deployment environment: DEV, QA , PROD'
|
|
||||||
Version:
|
|
||||||
Type: String
|
|
||||||
Description: 'hash of template'
|
|
||||||
|
|
||||||
# ContainerPort:
|
|
||||||
# Type: Number
|
|
||||||
# Default: 80
|
|
||||||
# Description: What port number the application inside the docker container is binding to
|
|
||||||
|
|
||||||
Mappings:
|
|
||||||
# Hard values for the subnet masks. These masks define
|
|
||||||
# the range of internal IP addresses that can be assigned.
|
|
||||||
# The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
|
|
||||||
# There are four subnets which cover the ranges:
|
|
||||||
#
|
|
||||||
# 10.0.0.0 - 10.0.0.255
|
|
||||||
# 10.0.1.0 - 10.0.1.255
|
|
||||||
# 10.0.2.0 - 10.0.2.255
|
|
||||||
# 10.0.3.0 - 10.0.3.255
|
|
||||||
|
|
||||||
SubnetConfig:
|
|
||||||
VPC:
|
|
||||||
CIDR: '10.0.0.0/16'
|
|
||||||
PublicOne:
|
|
||||||
CIDR: '10.0.0.0/24'
|
|
||||||
PublicTwo:
|
|
||||||
CIDR: '10.0.1.0/24'
|
|
||||||
|
|
||||||
Resources:
|
|
||||||
# VPC in which containers will be networked.
|
|
||||||
# It has two public subnets, and two private subnets.
|
|
||||||
# We distribute the subnets across the first two available subnets
|
|
||||||
# for the region, for high availability.
|
|
||||||
VPC:
|
|
||||||
Type: AWS::EC2::VPC
|
|
||||||
Properties:
|
|
||||||
EnableDnsSupport: true
|
|
||||||
EnableDnsHostnames: true
|
|
||||||
CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
|
|
||||||
|
|
||||||
MainBucket:
|
|
||||||
Type: "AWS::S3::Bucket"
|
|
||||||
Properties:
|
|
||||||
BucketName: !Ref EnvironmentName
|
|
||||||
|
|
||||||
EFSServerSecurityGroup:
|
|
||||||
Type: AWS::EC2::SecurityGroup
|
|
||||||
Properties:
|
|
||||||
GroupName: 'efs-server-endpoints'
|
|
||||||
GroupDescription: Which client ip addrs are allowed to access EFS server
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
SecurityGroupIngress:
|
|
||||||
- IpProtocol: tcp
|
|
||||||
FromPort: 2049
|
|
||||||
ToPort: 2049
|
|
||||||
SourceSecurityGroupId: !Ref ContainerSecurityGroup
|
|
||||||
#CidrIp: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
|
|
||||||
# A security group for the containers we will run in Fargate.
|
|
||||||
# Rules are added to this security group based on what ingress you
|
|
||||||
# add for the cluster.
|
|
||||||
ContainerSecurityGroup:
|
|
||||||
Type: AWS::EC2::SecurityGroup
|
|
||||||
Properties:
|
|
||||||
GroupName: 'task security group'
|
|
||||||
GroupDescription: Access to the Fargate containers
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
# SecurityGroupIngress:
|
|
||||||
# - IpProtocol: tcp
|
|
||||||
# FromPort: !Ref ContainerPort
|
|
||||||
# ToPort: !Ref ContainerPort
|
|
||||||
# CidrIp: 0.0.0.0/0
|
|
||||||
SecurityGroupEgress:
|
|
||||||
- IpProtocol: -1
|
|
||||||
FromPort: 2049
|
|
||||||
ToPort: 2049
|
|
||||||
CidrIp: '0.0.0.0/0'
|
|
||||||
|
|
||||||
# Two public subnets, where containers can have public IP addresses
|
|
||||||
PublicSubnetOne:
|
|
||||||
Type: AWS::EC2::Subnet
|
|
||||||
Properties:
|
|
||||||
AvailabilityZone: !Select
|
|
||||||
- 0
|
|
||||||
- Fn::GetAZs: !Ref 'AWS::Region'
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
|
|
||||||
# MapPublicIpOnLaunch: true
|
|
||||||
|
|
||||||
PublicSubnetTwo:
|
|
||||||
Type: AWS::EC2::Subnet
|
|
||||||
Properties:
|
|
||||||
AvailabilityZone: !Select
|
|
||||||
- 1
|
|
||||||
- Fn::GetAZs: !Ref 'AWS::Region'
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
|
|
||||||
# MapPublicIpOnLaunch: true
|
|
||||||
|
|
||||||
# Setup networking resources for the public subnets. Containers
|
|
||||||
# in the public subnets have public IP addresses and the routing table
|
|
||||||
# sends network traffic via the internet gateway.
|
|
||||||
InternetGateway:
|
|
||||||
Type: AWS::EC2::InternetGateway
|
|
||||||
GatewayAttachement:
|
|
||||||
Type: AWS::EC2::VPCGatewayAttachment
|
|
||||||
Properties:
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
InternetGatewayId: !Ref 'InternetGateway'
|
|
||||||
|
|
||||||
# Attaching a Internet Gateway to route table makes it public.
|
|
||||||
PublicRouteTable:
|
|
||||||
Type: AWS::EC2::RouteTable
|
|
||||||
Properties:
|
|
||||||
VpcId: !Ref 'VPC'
|
|
||||||
PublicRoute:
|
|
||||||
Type: AWS::EC2::Route
|
|
||||||
DependsOn: GatewayAttachement
|
|
||||||
Properties:
|
|
||||||
RouteTableId: !Ref 'PublicRouteTable'
|
|
||||||
DestinationCidrBlock: '0.0.0.0/0'
|
|
||||||
GatewayId: !Ref 'InternetGateway'
|
|
||||||
|
|
||||||
# Attaching a public route table makes a subnet public.
|
|
||||||
PublicSubnetOneRouteTableAssociation:
|
|
||||||
Type: AWS::EC2::SubnetRouteTableAssociation
|
|
||||||
Properties:
|
|
||||||
SubnetId: !Ref PublicSubnetOne
|
|
||||||
RouteTableId: !Ref PublicRouteTable
|
|
||||||
PublicSubnetTwoRouteTableAssociation:
|
|
||||||
Type: AWS::EC2::SubnetRouteTableAssociation
|
|
||||||
Properties:
|
|
||||||
SubnetId: !Ref PublicSubnetTwo
|
|
||||||
RouteTableId: !Ref PublicRouteTable
|
|
||||||
|
|
||||||
# ECS Resources
|
|
||||||
ECSCluster:
|
|
||||||
Type: AWS::ECS::Cluster
|
|
||||||
|
|
||||||
# A role used to allow AWS Autoscaling to inspect stats and adjust scaleable targets
|
|
||||||
# on your AWS account
|
|
||||||
AutoscalingRole:
|
|
||||||
Type: AWS::IAM::Role
|
|
||||||
Properties:
|
|
||||||
AssumeRolePolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Principal:
|
|
||||||
Service: [application-autoscaling.amazonaws.com]
|
|
||||||
Action: ['sts:AssumeRole']
|
|
||||||
Path: /
|
|
||||||
Policies:
|
|
||||||
- PolicyName: service-autoscaling
|
|
||||||
PolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Action:
|
|
||||||
- 'application-autoscaling:*'
|
|
||||||
- 'cloudwatch:DescribeAlarms'
|
|
||||||
- 'cloudwatch:PutMetricAlarm'
|
|
||||||
- 'ecs:DescribeServices'
|
|
||||||
- 'ecs:UpdateService'
|
|
||||||
Resource: '*'
|
|
||||||
|
|
||||||
# This is an IAM role which authorizes ECS to manage resources on your
|
|
||||||
# account on your behalf, such as updating your load balancer with the
|
|
||||||
# details of where your containers are, so that traffic can reach your
|
|
||||||
# containers.
|
|
||||||
ECSRole:
|
|
||||||
Type: AWS::IAM::Role
|
|
||||||
Properties:
|
|
||||||
AssumeRolePolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Principal:
|
|
||||||
Service: [ecs.amazonaws.com]
|
|
||||||
Action: ['sts:AssumeRole']
|
|
||||||
Path: /
|
|
||||||
Policies:
|
|
||||||
- PolicyName: ecs-service
|
|
||||||
PolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Action:
|
|
||||||
# Rules which allow ECS to attach network interfaces to instances
|
|
||||||
# on your behalf in order for awsvpc networking mode to work right
|
|
||||||
- 'ec2:AttachNetworkInterface'
|
|
||||||
- 'ec2:CreateNetworkInterface'
|
|
||||||
- 'ec2:CreateNetworkInterfacePermission'
|
|
||||||
- 'ec2:DeleteNetworkInterface'
|
|
||||||
- 'ec2:DeleteNetworkInterfacePermission'
|
|
||||||
- 'ec2:Describe*'
|
|
||||||
- 'ec2:DetachNetworkInterface'
|
|
||||||
|
|
||||||
# Rules which allow ECS to update load balancers on your behalf
|
|
||||||
# with the information sabout how to send traffic to your containers
|
|
||||||
- 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
|
|
||||||
- 'elasticloadbalancing:DeregisterTargets'
|
|
||||||
- 'elasticloadbalancing:Describe*'
|
|
||||||
- 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
|
|
||||||
- 'elasticloadbalancing:RegisterTargets'
|
|
||||||
Resource: '*'
|
|
||||||
|
|
||||||
# This is a role which is used by the ECS tasks themselves.
|
|
||||||
ECSTaskExecutionRole:
|
|
||||||
Type: AWS::IAM::Role
|
|
||||||
Properties:
|
|
||||||
AssumeRolePolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Principal:
|
|
||||||
Service: [ecs-tasks.amazonaws.com]
|
|
||||||
Action: ['sts:AssumeRole']
|
|
||||||
Path: /
|
|
||||||
Policies:
|
|
||||||
- PolicyName: AmazonECSTaskExecutionRolePolicy
|
|
||||||
PolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Action:
|
|
||||||
# Allow the use of secret manager
|
|
||||||
- 'secretsmanager:GetSecretValue'
|
|
||||||
- 'kms:Decrypt'
|
|
||||||
|
|
||||||
# Allow the ECS Tasks to download images from ECR
|
|
||||||
- 'ecr:GetAuthorizationToken'
|
|
||||||
- 'ecr:BatchCheckLayerAvailability'
|
|
||||||
- 'ecr:GetDownloadUrlForLayer'
|
|
||||||
- 'ecr:BatchGetImage'
|
|
||||||
|
|
||||||
# Allow the ECS tasks to upload logs to CloudWatch
|
|
||||||
- 'logs:CreateLogStream'
|
|
||||||
- 'logs:PutLogEvents'
|
|
||||||
Resource: '*'
|
|
||||||
|
|
||||||
DeleteCFNLambdaExecutionRole:
|
|
||||||
Type: 'AWS::IAM::Role'
|
|
||||||
Properties:
|
|
||||||
AssumeRolePolicyDocument:
|
|
||||||
Version: '2012-10-17'
|
|
||||||
Statement:
|
|
||||||
- Effect: 'Allow'
|
|
||||||
Principal:
|
|
||||||
Service: ['lambda.amazonaws.com']
|
|
||||||
Action: 'sts:AssumeRole'
|
|
||||||
Path: '/'
|
|
||||||
Policies:
|
|
||||||
- PolicyName: DeleteCFNLambdaExecutionRole
|
|
||||||
PolicyDocument:
|
|
||||||
Version: '2012-10-17'
|
|
||||||
Statement:
|
|
||||||
- Effect: 'Allow'
|
|
||||||
Action:
|
|
||||||
- 'logs:CreateLogGroup'
|
|
||||||
- 'logs:CreateLogStream'
|
|
||||||
- 'logs:PutLogEvents'
|
|
||||||
Resource: 'arn:aws:logs:*:*:*'
|
|
||||||
- Effect: 'Allow'
|
|
||||||
Action:
|
|
||||||
- 'cloudformation:DeleteStack'
|
|
||||||
- 'kinesis:DeleteStream'
|
|
||||||
- 'secretsmanager:DeleteSecret'
|
|
||||||
- 'kinesis:DescribeStreamSummary'
|
|
||||||
- 'logs:DeleteLogGroup'
|
|
||||||
- 'logs:DeleteSubscriptionFilter'
|
|
||||||
- 'ecs:DeregisterTaskDefinition'
|
|
||||||
- 'lambda:DeleteFunction'
|
|
||||||
- 'lambda:InvokeFunction'
|
|
||||||
- 'events:RemoveTargets'
|
|
||||||
- 'events:DeleteRule'
|
|
||||||
- 'lambda:RemovePermission'
|
|
||||||
Resource: '*'
|
|
||||||
|
|
||||||
### cloud watch to kinesis role
|
|
||||||
CloudWatchIAMRole:
|
|
||||||
Type: AWS::IAM::Role
|
|
||||||
Properties:
|
|
||||||
AssumeRolePolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Principal:
|
|
||||||
Service: [logs.amazonaws.com]
|
|
||||||
Action: ['sts:AssumeRole']
|
|
||||||
Path: /
|
|
||||||
Policies:
|
|
||||||
- PolicyName: service-autoscaling
|
|
||||||
PolicyDocument:
|
|
||||||
Statement:
|
|
||||||
- Effect: Allow
|
|
||||||
Action:
|
|
||||||
- 'kinesis:PutRecord'
|
|
||||||
Resource: '*'
|
|
||||||
|
|
||||||
#####################EFS#####################
|
|
||||||
EfsFileStorage:
|
|
||||||
Type: 'AWS::EFS::FileSystem'
|
|
||||||
Properties:
|
|
||||||
BackupPolicy:
|
|
||||||
Status: ENABLED
|
|
||||||
PerformanceMode: maxIO
|
|
||||||
Encrypted: false
|
|
||||||
|
|
||||||
FileSystemPolicy:
|
|
||||||
Version: '2012-10-17'
|
|
||||||
Statement:
|
|
||||||
- Effect: 'Allow'
|
|
||||||
Action:
|
|
||||||
- 'elasticfilesystem:ClientMount'
|
|
||||||
- 'elasticfilesystem:ClientWrite'
|
|
||||||
- 'elasticfilesystem:ClientRootAccess'
|
|
||||||
Principal:
|
|
||||||
AWS: '*'
|
|
||||||
|
|
||||||
MountTargetResource1:
|
|
||||||
Type: AWS::EFS::MountTarget
|
|
||||||
Properties:
|
|
||||||
FileSystemId: !Ref EfsFileStorage
|
|
||||||
SubnetId: !Ref PublicSubnetOne
|
|
||||||
SecurityGroups:
|
|
||||||
- !Ref EFSServerSecurityGroup
|
|
||||||
|
|
||||||
MountTargetResource2:
|
|
||||||
Type: AWS::EFS::MountTarget
|
|
||||||
Properties:
|
|
||||||
FileSystemId: !Ref EfsFileStorage
|
|
||||||
SubnetId: !Ref PublicSubnetTwo
|
|
||||||
SecurityGroups:
|
|
||||||
- !Ref EFSServerSecurityGroup
|
|
||||||
|
|
||||||
Outputs:
|
|
||||||
EfsFileStorageId:
|
|
||||||
Description: 'The connection endpoint for the database.'
|
|
||||||
Value: !Ref EfsFileStorage
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:EfsFileStorageId
|
|
||||||
ClusterName:
|
|
||||||
Description: The name of the ECS cluster
|
|
||||||
Value: !Ref 'ECSCluster'
|
|
||||||
Export:
|
|
||||||
Name: !Sub${' ${EnvironmentName}'}:ClusterName
|
|
||||||
AutoscalingRole:
|
|
||||||
Description: The ARN of the role used for autoscaling
|
|
||||||
Value: !GetAtt 'AutoscalingRole.Arn'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:AutoscalingRole
|
|
||||||
ECSRole:
|
|
||||||
Description: The ARN of the ECS role
|
|
||||||
Value: !GetAtt 'ECSRole.Arn'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:ECSRole
|
|
||||||
ECSTaskExecutionRole:
|
|
||||||
Description: The ARN of the ECS role tsk execution role
|
|
||||||
Value: !GetAtt 'ECSTaskExecutionRole.Arn'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:ECSTaskExecutionRole
|
|
||||||
|
|
||||||
DeleteCFNLambdaExecutionRole:
|
|
||||||
Description: Lambda execution role for cleaning up cloud formations
|
|
||||||
Value: !GetAtt 'DeleteCFNLambdaExecutionRole.Arn'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:DeleteCFNLambdaExecutionRole
|
|
||||||
|
|
||||||
CloudWatchIAMRole:
|
|
||||||
Description: The ARN of the CloudWatch role for subscription filter
|
|
||||||
Value: !GetAtt 'CloudWatchIAMRole.Arn'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:CloudWatchIAMRole
|
|
||||||
VpcId:
|
|
||||||
Description: The ID of the VPC that this stack is deployed in
|
|
||||||
Value: !Ref 'VPC'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:VpcId
|
|
||||||
PublicSubnetOne:
|
|
||||||
Description: Public subnet one
|
|
||||||
Value: !Ref 'PublicSubnetOne'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:PublicSubnetOne
|
|
||||||
PublicSubnetTwo:
|
|
||||||
Description: Public subnet two
|
|
||||||
Value: !Ref 'PublicSubnetTwo'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:PublicSubnetTwo
|
|
||||||
ContainerSecurityGroup:
|
|
||||||
Description: A security group used to allow Fargate containers to receive traffic
|
|
||||||
Value: !Ref 'ContainerSecurityGroup'
|
|
||||||
Export:
|
|
||||||
Name: !Sub ${'${EnvironmentName}'}:ContainerSecurityGroup
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user