mirror of
https://github.com/game-ci/unity-builder.git
synced 2025-07-04 12:25:19 -04:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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,22 +1,11 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": ["jest", "@typescript-eslint", "prettier", "unicorn"],
|
||||||
"jest",
|
"extends": ["plugin:unicorn/recommended", "plugin:github/recommended", "plugin:prettier/recommended"],
|
||||||
"@typescript-eslint",
|
|
||||||
"prettier",
|
|
||||||
"unicorn"
|
|
||||||
],
|
|
||||||
"extends": [
|
|
||||||
"plugin:unicorn/recommended",
|
|
||||||
"plugin:github/recommended",
|
|
||||||
"plugin:prettier/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2020,
|
"ecmaVersion": 2020,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"extraFileExtensions": [
|
"extraFileExtensions": [".mjs"],
|
||||||
".mjs"
|
|
||||||
],
|
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"impliedStrict": true
|
"impliedStrict": true
|
||||||
},
|
},
|
||||||
@ -33,10 +22,7 @@
|
|||||||
// Namespaces or sometimes needed
|
// Namespaces or sometimes needed
|
||||||
"import/no-namespace": "off",
|
"import/no-namespace": "off",
|
||||||
// Properly format comments
|
// Properly format comments
|
||||||
"spaced-comment": [
|
"spaced-comment": ["error", "always"],
|
||||||
"error",
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"lines-around-comment": [
|
"lines-around-comment": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
@ -71,12 +57,7 @@
|
|||||||
// Enforce camelCase
|
// Enforce camelCase
|
||||||
"camelcase": "error",
|
"camelcase": "error",
|
||||||
// Allow forOfStatements
|
// Allow forOfStatements
|
||||||
"no-restricted-syntax": [
|
"no-restricted-syntax": ["error", "ForInStatement", "LabeledStatement", "WithStatement"],
|
||||||
"error",
|
|
||||||
"ForInStatement",
|
|
||||||
"LabeledStatement",
|
|
||||||
"WithStatement"
|
|
||||||
],
|
|
||||||
// Continue is viable in forOf loops in generators
|
// Continue is viable in forOf loops in generators
|
||||||
"no-continue": "off",
|
"no-continue": "off",
|
||||||
// From experience, named exports are almost always desired. I got tired of this rule
|
// From experience, named exports are almost always desired. I got tired of this rule
|
||||||
|
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 }}
|
||||||
|
23
.github/workflows/build-tests-mac.yml
vendored
23
.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,25 @@ jobs:
|
|||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.29f1
|
- 2021.3.45f1
|
||||||
- 2022.1.24f1
|
- 2022.3.13f1
|
||||||
- 2022.2.21f1
|
- 2023.2.2f1
|
||||||
- 2022.3.7f1
|
|
||||||
- 2023.1.8f1
|
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
- StandaloneOSX # Build a MacOS executable
|
- StandaloneOSX # Build a MacOS executable
|
||||||
|
- iOS # Build an iOS executable
|
||||||
|
|
||||||
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,7 +59,9 @@ 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 }}
|
||||||
@ -73,8 +72,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 }})
|
||||||
path: build
|
path: build
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
146
.github/workflows/build-tests-ubuntu.yml
vendored
146
.github/workflows/build-tests-ubuntu.yml
vendored
@ -3,11 +3,6 @@ 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 }}
|
||||||
@ -41,7 +36,8 @@ 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 +48,73 @@ jobs:
|
|||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.29f1
|
- 2021.3.32f1
|
||||||
- 2022.1.24f1
|
- 2022.3.13f1
|
||||||
- 2022.2.21f1
|
- 2023.2.2f1
|
||||||
- 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 +122,85 @@ 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
|
||||||
|
39
.github/workflows/build-tests-windows.yml
vendored
39
.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,42 @@ 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.32f1
|
||||||
- 2022.1.24f1
|
- 2022.3.13f1
|
||||||
- 2022.2.21f1
|
- 2023.2.2f1
|
||||||
- 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
|
||||||
|
|
||||||
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 }}
|
||||||
@ -69,10 +73,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
|
||||||
@ -92,10 +99,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 +124,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 +138,8 @@ 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' || '' }}
|
||||||
path: build
|
path: build
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
4
.github/workflows/cleanup.yml
vendored
4
.github/workflows/cleanup.yml
vendored
@ -15,11 +15,11 @@ jobs:
|
|||||||
cleanupCloudRunner:
|
cleanupCloudRunner:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
if: github.event.event_type != 'pull_request_target'
|
if: github.event.event_type != 'pull_request_target'
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
- run: yarn
|
- run: yarn
|
||||||
|
149
.github/workflows/cloud-runner-ci-pipeline.yml
vendored
149
.github/workflows/cloud-runner-ci-pipeline.yml
vendored
@ -18,45 +18,40 @@ env:
|
|||||||
GCP_PROJECT: unitykubernetesbuilder
|
GCP_PROJECT: unitykubernetesbuilder
|
||||||
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
||||||
AWS_REGION: eu-west-2
|
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_DEFAULT_REGION: eu-west-2
|
||||||
AWS_STACK_NAME: game-ci-team-pipelines
|
AWS_STACK_NAME: game-ci-team-pipelines
|
||||||
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
||||||
DEBUG: true
|
DEBUG: true
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
PROJECT_PATH: test-project
|
PROJECT_PATH: test-project
|
||||||
UNITY_VERSION: 2019.3.15f1
|
UNITY_VERSION: 2019.3.15f1
|
||||||
USE_IL2CPP: false
|
USE_IL2CPP: false
|
||||||
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
||||||
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
smokeTests:
|
tests:
|
||||||
name: Smoke Tests
|
name: Tests
|
||||||
if: github.event.event_type != 'pull_request_target'
|
if: github.event.event_type != 'pull_request_target'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
test:
|
test:
|
||||||
#- 'cloud-runner-async-workflow'
|
- 'cloud-runner-end2end-locking'
|
||||||
|
- 'cloud-runner-end2end-caching'
|
||||||
|
- 'cloud-runner-end2end-retaining'
|
||||||
- 'cloud-runner-caching'
|
- 'cloud-runner-caching'
|
||||||
# - 'cloud-runner-end2end-caching'
|
|
||||||
# - 'cloud-runner-end2end-retaining'
|
|
||||||
- 'cloud-runner-environment'
|
- 'cloud-runner-environment'
|
||||||
|
- 'cloud-runner-image'
|
||||||
- 'cloud-runner-hooks'
|
- 'cloud-runner-hooks'
|
||||||
- 'cloud-runner-local-persistence'
|
- 'cloud-runner-local-persistence'
|
||||||
- 'cloud-runner-locking-core'
|
- 'cloud-runner-locking-core'
|
||||||
- 'cloud-runner-locking-get-locked'
|
- 'cloud-runner-locking-get-locked'
|
||||||
providerStrategy:
|
|
||||||
#- aws
|
|
||||||
- local-docker
|
|
||||||
#- k8s
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout (default)
|
- name: Checkout (default)
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
lfs: false
|
lfs: false
|
||||||
- name: Configure AWS Credentials
|
- name: Configure AWS Credentials
|
||||||
@ -65,55 +60,77 @@ jobs:
|
|||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
aws-region: eu-west-2
|
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: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
||||||
timeout-minutes: 35
|
timeout-minutes: 60
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
PROJECT_PATH: test-project
|
PROJECT_PATH: test-project
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
cloudRunnerTests: true
|
cloudRunnerTests: true
|
||||||
versioning: None
|
versioning: None
|
||||||
CLOUD_RUNNER_CLUSTER: ${{ matrix.providerStrategy }}
|
KUBE_STORAGE_CLASS: local-path
|
||||||
tests:
|
PROVIDER_STRATEGY: local-docker
|
||||||
# needs:
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
# - smokeTests
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
# - buildTargetTests
|
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
name: Integration Tests
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
k8sTests:
|
||||||
|
name: K8s 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-end2end-locking'
|
||||||
|
- 'cloud-runner-end2end-caching'
|
||||||
|
- 'cloud-runner-end2end-retaining'
|
||||||
|
- 'cloud-runner-kubernetes'
|
||||||
|
- 'cloud-runner-environment'
|
||||||
|
- 'cloud-runner-github-checks'
|
||||||
|
steps:
|
||||||
|
- name: Checkout (default)
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
- run: yarn
|
||||||
|
- name: actions-k3s
|
||||||
|
uses: debianmaster/actions-k3s@v1.0.5
|
||||||
|
with:
|
||||||
|
version: 'latest'
|
||||||
|
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
||||||
|
timeout-minutes: 60
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
PROJECT_PATH: test-project
|
||||||
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
|
cloudRunnerTests: true
|
||||||
|
versioning: None
|
||||||
|
KUBE_STORAGE_CLASS: local-path
|
||||||
|
PROVIDER_STRATEGY: k8s
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
awsTests:
|
||||||
|
name: AWS Tests
|
||||||
if: github.event.event_type != 'pull_request_target'
|
if: github.event.event_type != 'pull_request_target'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
providerStrategy:
|
|
||||||
- aws
|
|
||||||
- local-docker
|
|
||||||
- k8s
|
|
||||||
test:
|
test:
|
||||||
- 'cloud-runner-async-workflow'
|
|
||||||
#- 'cloud-runner-caching'
|
|
||||||
- 'cloud-runner-end2end-locking'
|
- 'cloud-runner-end2end-locking'
|
||||||
- 'cloud-runner-end2end-caching'
|
- 'cloud-runner-end2end-caching'
|
||||||
- 'cloud-runner-end2end-retaining'
|
- 'cloud-runner-end2end-retaining'
|
||||||
- 'cloud-runner-environment'
|
- 'cloud-runner-environment'
|
||||||
#- 'cloud-runner-hooks'
|
|
||||||
- 'cloud-runner-s3-steps'
|
- 'cloud-runner-s3-steps'
|
||||||
#- 'cloud-runner-local-persistence'
|
|
||||||
#- 'cloud-runner-locking-core'
|
|
||||||
#- 'cloud-runner-locking-get-locked'
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout (default)
|
- name: Checkout (default)
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@ -125,29 +142,24 @@ jobs:
|
|||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
aws-region: eu-west-2
|
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: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
- run: yarn run test "${{ matrix.test }}" --detectOpenHandles --forceExit --runInBand
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
PROJECT_PATH: test-project
|
PROJECT_PATH: test-project
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
cloudRunnerTests: true
|
cloudRunnerTests: true
|
||||||
versioning: None
|
versioning: None
|
||||||
PROVIDER_STRATEGY: ${{ matrix.providerStrategy }}
|
KUBE_STORAGE_CLASS: local-path
|
||||||
|
PROVIDER_STRATEGY: aws
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
buildTargetTests:
|
buildTargetTests:
|
||||||
name: Local Build Target Tests
|
name: Local Build Target Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -164,10 +176,10 @@ jobs:
|
|||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
||||||
- WebGL # WebGL.
|
- WebGL # WebGL.
|
||||||
- iOS # Build an iOS player.
|
- iOS # Build an iOS player.
|
||||||
- Android # Build an Android .apk.
|
# - Android # Build an Android .apk.
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout (default)
|
- name: Checkout (default)
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
lfs: false
|
lfs: false
|
||||||
- run: yarn
|
- run: yarn
|
||||||
@ -175,7 +187,14 @@ jobs:
|
|||||||
id: unity-build
|
id: unity-build
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
cloudRunnerTests: true
|
cloudRunnerTests: true
|
||||||
versioning: None
|
versioning: None
|
||||||
@ -183,7 +202,7 @@ jobs:
|
|||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
providerStrategy: ${{ matrix.providerStrategy }}
|
||||||
- run: |
|
- 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 }}
|
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
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.providerStrategy }} Build (${{ matrix.targetPlatform }})
|
name: ${{ matrix.providerStrategy }} Build (${{ matrix.targetPlatform }})
|
||||||
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
||||||
|
4
.github/workflows/integrity-check.yml
vendored
4
.github/workflows/integrity-check.yml
vendored
@ -16,8 +16,8 @@ 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
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '18'
|
||||||
- run: yarn
|
- run: yarn
|
||||||
|
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",
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
61
action.yml
61
action.yml
@ -18,7 +18,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,6 +35,14 @@ 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: ''
|
||||||
@ -97,11 +109,43 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: '[CloudRunner] GitHub owner name or organization/team name'
|
description: '[CloudRunner] GitHub owner name or organization/team name'
|
||||||
|
runAsHostUser:
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
description:
|
||||||
|
'Whether to run as a user that matches the host system or the default root container user. Only applicable to
|
||||||
|
Linux hosts and containers. This is useful for fixing permission errors on Self-Hosted runners.'
|
||||||
chownFilesTo:
|
chownFilesTo:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description:
|
description:
|
||||||
'User and optionally group (user or user:group or uid:gid) to give ownership of the resulting build artifacts'
|
'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:
|
||||||
|
'Amount of memory to assign the docker container. Defaults to 95% of total system memory rounded down to the
|
||||||
|
nearest megabyte on Linux and 80% on Windows. On unrecognized platforms, defaults to 75% of total system memory.
|
||||||
|
To manually specify a value, use the format <number><unit>, where unit is either m or g. ie: 512m = 512 megabytes'
|
||||||
|
dockerIsolationMode:
|
||||||
|
required: false
|
||||||
|
default: 'default'
|
||||||
|
description:
|
||||||
|
'Isolation mode to use for the docker container. Can be one of process, hyperv, or default. Default will pick the
|
||||||
|
default mode as described by Microsoft where server versions use process and desktop versions use hyperv. Only
|
||||||
|
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:
|
allowDirtyBuild:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@ -150,11 +194,11 @@ inputs:
|
|||||||
description:
|
description:
|
||||||
'[CloudRunner] Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must
|
'[CloudRunner] Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must
|
||||||
be configured.'
|
be configured.'
|
||||||
cloudRunnerCpu:
|
containerCpu:
|
||||||
default: ''
|
default: ''
|
||||||
required: false
|
required: false
|
||||||
description: '[CloudRunner] Amount of CPU time to assign the remote build container'
|
description: '[CloudRunner] Amount of CPU time to assign the remote build container'
|
||||||
cloudRunnerMemory:
|
containerMemory:
|
||||||
default: ''
|
default: ''
|
||||||
required: false
|
required: false
|
||||||
description: '[CloudRunner] Amount of memory to assign the remote build container'
|
description: '[CloudRunner] Amount of memory to assign the remote build container'
|
||||||
@ -217,6 +261,10 @@ 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.'
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
volume:
|
volume:
|
||||||
@ -225,9 +273,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: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
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,76 @@ 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["customBuildProfile"] != "") {
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
// Load build profile from Assets folder
|
||||||
|
BuildProfile buildProfile = AssetDatabase.LoadAssetAtPath<BuildProfile>(options["customBuildProfile"]);
|
||||||
|
|
||||||
|
// Set it as active
|
||||||
|
BuildProfile.SetActiveBuildProfile(buildProfile);
|
||||||
|
|
||||||
|
// Define BuildPlayerWithProfileOptions
|
||||||
|
buildPlayerOptions = new BuildPlayerWithProfileOptions {
|
||||||
|
buildProfile = buildProfile,
|
||||||
|
locationPathName = options["customBuildPath"],
|
||||||
|
options = buildOptions,
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
throw new Exception("Build profiles are not supported by this version of Unity (" + Application.unityVersion +")");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// 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,35 @@ namespace UnityBuilderAction.Input
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,10 +41,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 +57,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 +78,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>
|
|
BIN
dist/index.js
generated
vendored
BIN
dist/index.js
generated
vendored
Binary file not shown.
BIN
dist/index.js.map
generated
vendored
BIN
dist/index.js.map
generated
vendored
Binary file not shown.
BIN
dist/licenses.txt
generated
vendored
BIN
dist/licenses.txt
generated
vendored
Binary file not shown.
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;
|
||||||
|
|
||||||
|
1
dist/platforms/mac/steps/activate.sh
vendored
1
dist/platforms/mac/steps/activate.sh
vendored
@ -30,6 +30,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
|
||||||
|
|
||||||
|
22
dist/platforms/mac/steps/build.sh
vendored
22
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,9 +146,9 @@ 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" \
|
-username "$UNITY_EMAIL" \
|
||||||
-password "$UNITY_PASSWORD" \
|
-password "$UNITY_PASSWORD" \
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
@ -139,6 +156,7 @@ echo ""
|
|||||||
-buildTarget "$BUILD_TARGET" \
|
-buildTarget "$BUILD_TARGET" \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
|
-customBuildProfile "$BUILD_PROFILE" \
|
||||||
-executeMethod "$BUILD_METHOD" \
|
-executeMethod "$BUILD_METHOD" \
|
||||||
-buildVersion "$VERSION" \
|
-buildVersion "$VERSION" \
|
||||||
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
||||||
|
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 $?
|
||||||
|
116
dist/platforms/ubuntu/steps/activate.sh
vendored
116
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
|
||||||
#
|
#
|
||||||
@ -97,10 +84,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 +105,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
|
|
||||||
|
32
dist/platforms/ubuntu/steps/build.sh
vendored
32
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,13 @@ 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" \
|
-buildTarget "$BUILD_TARGET" \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
|
-customBuildProfile "$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;
|
||||||
|
}
|
||||||
|
148
dist/platforms/windows/build.ps1
vendored
148
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,78 @@ 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`"",
|
||||||
|
"-buildTarget", "`"$Env:BUILD_TARGET`"",
|
||||||
|
"-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 `
|
# Remove null items as that will fail the Start-Process call
|
||||||
-projectPath $Env:UNITY_PROJECT_PATH `
|
$unityArgs = $unityArgs | Where-Object { $_ -ne $null }
|
||||||
-executeMethod $Env:BUILD_METHOD `
|
|
||||||
-buildTarget $Env:BUILD_TARGET `
|
|
||||||
-customBuildTarget $Env:BUILD_TARGET `
|
|
||||||
-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
|
$unityProcess = Start-Process -FilePath "$Env:UNITY_PATH/Editor/Unity.exe" `
|
||||||
$Env:BUILD_EXIT_CODE=$LastExitCode
|
-ArgumentList $unityArgs `
|
||||||
|
-PassThru `
|
||||||
|
-NoNewWindow
|
||||||
|
|
||||||
# Display results
|
# Cache the handle so exit code works properly
|
||||||
if ($Env:BUILD_EXIT_CODE -eq 0)
|
# https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
|
||||||
{
|
$unityHandle = $unityProcess.Handle
|
||||||
Write-Output "Build Succeeded!"
|
|
||||||
} else
|
while ($true) {
|
||||||
{
|
if ($unityProcess.HasExited) {
|
||||||
Write-Output "$('Build failed, with exit code ')$($Env:BUILD_EXIT_CODE)$('"')"
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: Determine if we need to set permissions on any files
|
|
||||||
|
|
||||||
#
|
|
||||||
# Results
|
|
||||||
#
|
|
||||||
|
|
||||||
Write-Output ""
|
|
||||||
Write-Output "###########################"
|
|
||||||
Write-Output "# Build output #"
|
|
||||||
Write-Output "###########################"
|
|
||||||
Write-Output ""
|
|
||||||
|
|
||||||
Get-ChildItem $Env:BUILD_PATH_FULL
|
|
||||||
Write-Output ""
|
|
||||||
|
44
dist/platforms/windows/entrypoint.ps1
vendored
44
dist/platforms/windows/entrypoint.ps1
vendored
@ -1,18 +1,52 @@
|
|||||||
|
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 }
|
||||||
|
|
||||||
# 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
|
||||||
|
}
|
||||||
|
}
|
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 -------------"
|
||||||
|
31
package.json
31
package.json
@ -7,14 +7,14 @@
|
|||||||
"author": "Webber <webber@takken.io>",
|
"author": "Webber <webber@takken.io>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "lefthook install && npx husky uninstall -y",
|
"prepare": "lefthook install",
|
||||||
"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",
|
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts",
|
||||||
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
||||||
"cli": "yarn ts-node src/index.ts -m cli",
|
"cli": "yarn ts-node src/index.ts -m cli",
|
||||||
"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\"",
|
"gcp-secrets-tests": "cross-env providerStrategy=aws cloudRunnerTests=true inputPullCommand=\"gcp-secret-manager\" populateOverride=true pullInputList=UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD yarn test -i -t \"cloud runner\"",
|
||||||
"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",
|
"gcp-secrets-cli": "cross-env cloudRunnerTests=true USE_IL2CPP=false inputPullCommand=\"gcp-secret-manager\" yarn ts-node src/index.ts -m cli --populateOverride true --pullInputList UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD",
|
||||||
"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",
|
"aws-secrets-cli": "cross-env cloudRunnerTests=true inputPullCommand=\"aws-secret-manager\" yarn ts-node src/index.ts -m cli --populateOverride true --pullInputList UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD",
|
||||||
"cli-aws": "cross-env providerStrategy=aws yarn run test-cli",
|
"cli-aws": "cross-env providerStrategy=aws yarn run test-cli",
|
||||||
"cli-k8s": "cross-env providerStrategy=k8s yarn run test-cli",
|
"cli-k8s": "cross-env providerStrategy=k8s yarn run test-cli",
|
||||||
"test-cli": "cross-env cloudRunnerTests=true yarn ts-node src/index.ts -m cli --projectPath test-project",
|
"test-cli": "cross-env cloudRunnerTests=true yarn ts-node src/index.ts -m cli --projectPath test-project",
|
||||||
@ -28,27 +28,33 @@
|
|||||||
"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",
|
||||||
|
"@aws-sdk/client-cloudformation": "^3.777.0",
|
||||||
|
"@aws-sdk/client-cloudwatch-logs": "^3.777.0",
|
||||||
|
"@aws-sdk/client-ecs": "^3.778.0",
|
||||||
|
"@aws-sdk/client-kinesis": "^3.777.0",
|
||||||
|
"@aws-sdk/client-s3": "^3.779.0",
|
||||||
"@kubernetes/client-node": "^0.16.3",
|
"@kubernetes/client-node": "^0.16.3",
|
||||||
"@octokit/core": "^3.5.1",
|
"@octokit/core": "^5.1.0",
|
||||||
"async-wait-until": "^2.0.12",
|
"async-wait-until": "^2.0.12",
|
||||||
"aws-sdk": "^2.1081.0",
|
"aws-sdk": "^2.1081.0",
|
||||||
"base-64": "^1.0.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",
|
"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",
|
||||||
|
"ts-md5": "^1.3.1",
|
||||||
"unity-changeset": "^2.0.0",
|
"unity-changeset": "^2.0.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"yaml": "^2.2.2"
|
"yaml": "^2.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@evilmartians/lefthook": "^1.2.9",
|
|
||||||
"@types/base-64": "^1.0.0",
|
"@types/base-64": "^1.0.0",
|
||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/node": "^17.0.23",
|
"@types/node": "^17.0.23",
|
||||||
@ -67,9 +73,10 @@
|
|||||||
"jest-circus": "^27.5.1",
|
"jest-circus": "^27.5.1",
|
||||||
"jest-fail-on-console": "^3.0.2",
|
"jest-fail-on-console": "^3.0.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
|
"lefthook": "^1.6.1",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"ts-jest": "^27.1.3",
|
"ts-jest": "^27.1.3",
|
||||||
"ts-node": "10.4.0",
|
"ts-node": "10.8.1",
|
||||||
"typescript": "4.7.4",
|
"typescript": "4.7.4",
|
||||||
"yarn-audit-fix": "^9.3.8"
|
"yarn-audit-fix": "^9.3.8"
|
||||||
},
|
},
|
||||||
@ -77,4 +84,4 @@
|
|||||||
"node": "20.5.1",
|
"node": "20.5.1",
|
||||||
"yarn": "1.22.19"
|
"yarn": "1.22.19"
|
||||||
}
|
}
|
||||||
}
|
}
|
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
|
22
src/index.ts
22
src/index.ts
@ -19,23 +19,35 @@ async function runMain() {
|
|||||||
const buildParameters = await BuildParameters.create();
|
const buildParameters = await BuildParameters.create();
|
||||||
const baseImage = new ImageTag(buildParameters);
|
const baseImage = new ImageTag(buildParameters);
|
||||||
|
|
||||||
|
let exitCode = -1;
|
||||||
|
|
||||||
if (buildParameters.providerStrategy === 'local') {
|
if (buildParameters.providerStrategy === 'local') {
|
||||||
core.info('Building locally');
|
core.info('Building locally');
|
||||||
await PlatformSetup.setup(buildParameters, actionFolder);
|
await PlatformSetup.setup(buildParameters, actionFolder);
|
||||||
if (process.platform === 'darwin') {
|
exitCode =
|
||||||
MacBuilder.run(actionFolder);
|
process.platform === 'darwin'
|
||||||
} else {
|
? await MacBuilder.run(actionFolder)
|
||||||
await Docker.run(baseImage.toString(), { workspace, actionFolder, ...buildParameters });
|
: await Docker.run(baseImage.toString(), {
|
||||||
}
|
workspace,
|
||||||
|
actionFolder,
|
||||||
|
...buildParameters,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await CloudRunner.run(buildParameters, baseImage.toString());
|
await CloudRunner.run(buildParameters, baseImage.toString());
|
||||||
|
exitCode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set output
|
// Set output
|
||||||
await Output.setBuildVersion(buildParameters.buildVersion);
|
await Output.setBuildVersion(buildParameters.buildVersion);
|
||||||
await Output.setAndroidVersionCode(buildParameters.androidVersionCode);
|
await Output.setAndroidVersionCode(buildParameters.androidVersionCode);
|
||||||
|
await Output.setEngineExitCode(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();
|
runMain();
|
||||||
|
@ -71,6 +71,12 @@ describe('BuildParameters', () => {
|
|||||||
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';
|
||||||
|
jest.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);
|
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
|
||||||
|
@ -12,6 +12,7 @@ import { Cli } from './cli/cli';
|
|||||||
import GitHub from './github';
|
import GitHub from './github';
|
||||||
import CloudRunnerOptions from './cloud-runner/options/cloud-runner-options';
|
import CloudRunnerOptions from './cloud-runner/options/cloud-runner-options';
|
||||||
import CloudRunner from './cloud-runner/cloud-runner';
|
import CloudRunner from './cloud-runner/cloud-runner';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
class BuildParameters {
|
class BuildParameters {
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
@ -21,14 +22,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,6 +44,11 @@ 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 sshAgent!: string;
|
public sshAgent!: string;
|
||||||
@ -52,6 +62,7 @@ class BuildParameters {
|
|||||||
public kubeVolumeSize!: string;
|
public kubeVolumeSize!: string;
|
||||||
public kubeVolume!: string;
|
public kubeVolume!: string;
|
||||||
public kubeStorageClass!: string;
|
public kubeStorageClass!: string;
|
||||||
|
public runAsHostUser!: string;
|
||||||
public chownFilesTo!: string;
|
public chownFilesTo!: string;
|
||||||
public commandHooks!: string;
|
public commandHooks!: string;
|
||||||
public pullInputList!: string[];
|
public pullInputList!: string[];
|
||||||
@ -115,10 +126,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 +139,28 @@ class BuildParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unitySerial !== undefined && unitySerial.length === 27) {
|
||||||
|
core.setSecret(unitySerial);
|
||||||
|
core.setSecret(`${unitySerial.slice(0, -4)}XXXX`);
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -152,8 +174,14 @@ class BuildParameters {
|
|||||||
customParameters: Input.customParameters,
|
customParameters: Input.customParameters,
|
||||||
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,
|
||||||
|
dockerCpuLimit: Input.dockerCpuLimit,
|
||||||
|
dockerMemoryLimit: Input.dockerMemoryLimit,
|
||||||
|
dockerIsolationMode: Input.dockerIsolationMode,
|
||||||
|
containerRegistryRepository: Input.containerRegistryRepository,
|
||||||
|
containerRegistryImageVersion: Input.containerRegistryImageVersion,
|
||||||
providerStrategy: CloudRunnerOptions.providerStrategy,
|
providerStrategy: CloudRunnerOptions.providerStrategy,
|
||||||
buildPlatform: CloudRunnerOptions.buildPlatform,
|
buildPlatform: CloudRunnerOptions.buildPlatform,
|
||||||
kubeConfig: CloudRunnerOptions.kubeConfig,
|
kubeConfig: CloudRunnerOptions.kubeConfig,
|
||||||
@ -168,7 +196,7 @@ class BuildParameters {
|
|||||||
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
||||||
cloudRunnerBranch: CloudRunnerOptions.cloudRunnerBranch.split('/').reverse()[0],
|
cloudRunnerBranch: CloudRunnerOptions.cloudRunnerBranch.split('/').reverse()[0],
|
||||||
cloudRunnerDebug: CloudRunnerOptions.cloudRunnerDebug,
|
cloudRunnerDebug: CloudRunnerOptions.cloudRunnerDebug,
|
||||||
githubRepo: Input.githubRepo || (await GitRepoReader.GetRemote()) || 'game-ci/unity-builder',
|
githubRepo: (Input.githubRepo ?? (await GitRepoReader.GetRemote())) || 'game-ci/unity-builder',
|
||||||
isCliMode: Cli.isCliMode,
|
isCliMode: Cli.isCliMode,
|
||||||
awsStackName: CloudRunnerOptions.awsStackName,
|
awsStackName: CloudRunnerOptions.awsStackName,
|
||||||
gitSha: Input.gitSha,
|
gitSha: Input.gitSha,
|
||||||
|
@ -10,8 +10,6 @@ import { LfsHashing } from '../cloud-runner/services/utility/lfs-hashing';
|
|||||||
import { RemoteClient } from '../cloud-runner/remote-client';
|
import { RemoteClient } from '../cloud-runner/remote-client';
|
||||||
import CloudRunnerOptionsReader from '../cloud-runner/options/cloud-runner-options-reader';
|
import CloudRunnerOptionsReader from '../cloud-runner/options/cloud-runner-options-reader';
|
||||||
import GitHub from '../github';
|
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';
|
||||||
|
|
||||||
@ -54,6 +52,7 @@ export class Cli {
|
|||||||
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.parse(process.argv);
|
program.parse(process.argv);
|
||||||
Cli.options = program.opts();
|
Cli.options = program.opts();
|
||||||
|
|
||||||
@ -110,7 +109,7 @@ export class Cli {
|
|||||||
const buildParameter = await BuildParameters.create();
|
const buildParameter = await BuildParameters.create();
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
|
|
||||||
return await CloudRunner.run(buildParameter, baseImage.toString());
|
return (await CloudRunner.run(buildParameter, baseImage.toString())).BuildResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CliFunction(`async-workflow`, `runs a cloud runner build`)
|
@CliFunction(`async-workflow`, `runs a cloud runner build`)
|
||||||
@ -119,7 +118,7 @@ export class Cli {
|
|||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
await CloudRunner.setup(buildParameter);
|
await CloudRunner.setup(buildParameter);
|
||||||
|
|
||||||
return await CloudRunner.run(buildParameter, baseImage.toString());
|
return (await CloudRunner.run(buildParameter, baseImage.toString())).BuildResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
||||||
@ -173,31 +172,4 @@ export class Cli {
|
|||||||
|
|
||||||
return await CloudRunner.Provider.watchWorkflow();
|
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(``));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import LocalDockerCloudRunner from './providers/docker';
|
|||||||
import GitHub from '../github';
|
import GitHub from '../github';
|
||||||
import SharedWorkspaceLocking from './services/core/shared-workspace-locking';
|
import SharedWorkspaceLocking from './services/core/shared-workspace-locking';
|
||||||
import { FollowLogStreamService } from './services/core/follow-log-stream-service';
|
import { FollowLogStreamService } from './services/core/follow-log-stream-service';
|
||||||
|
import CloudRunnerResult from './services/core/cloud-runner-result';
|
||||||
|
|
||||||
class CloudRunner {
|
class CloudRunner {
|
||||||
public static Provider: ProviderInterface;
|
public static Provider: ProviderInterface;
|
||||||
@ -83,15 +84,16 @@ class CloudRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async run(buildParameters: BuildParameters, baseImage: string) {
|
static async run(buildParameters: BuildParameters, baseImage: string) {
|
||||||
|
if (baseImage.includes(`undefined`)) {
|
||||||
|
throw new Error(`baseImage is undefined`);
|
||||||
|
}
|
||||||
await CloudRunner.setup(buildParameters);
|
await CloudRunner.setup(buildParameters);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Setup shared cloud runner resources');
|
|
||||||
await CloudRunner.Provider.setupWorkflow(
|
await CloudRunner.Provider.setupWorkflow(
|
||||||
CloudRunner.buildParameters.buildGuid,
|
CloudRunner.buildParameters.buildGuid,
|
||||||
CloudRunner.buildParameters,
|
CloudRunner.buildParameters,
|
||||||
CloudRunner.buildParameters.branch,
|
CloudRunner.buildParameters.branch,
|
||||||
CloudRunner.defaultSecrets,
|
CloudRunner.defaultSecrets,
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
try {
|
try {
|
||||||
if (buildParameters.maxRetainedWorkspaces > 0) {
|
if (buildParameters.maxRetainedWorkspaces > 0) {
|
||||||
CloudRunner.lockedWorkspace = SharedWorkspaceLocking.NewWorkspaceName();
|
CloudRunner.lockedWorkspace = SharedWorkspaceLocking.NewWorkspaceName();
|
||||||
@ -114,11 +116,7 @@ class CloudRunner {
|
|||||||
CloudRunner.lockedWorkspace = ``;
|
CloudRunner.lockedWorkspace = ``;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const content = { ...CloudRunner.buildParameters };
|
await CloudRunner.updateStatusWithBuildParameters();
|
||||||
content.gitPrivateToken = ``;
|
|
||||||
content.unitySerial = ``;
|
|
||||||
const jsonContent = JSON.stringify(content, undefined, 4);
|
|
||||||
await GitHub.updateGitHubCheck(jsonContent, CloudRunner.buildParameters.buildGuid);
|
|
||||||
const output = await new WorkflowCompositionRoot().run(
|
const output = await new WorkflowCompositionRoot().run(
|
||||||
new CloudRunnerStepParameters(
|
new CloudRunnerStepParameters(
|
||||||
baseImage,
|
baseImage,
|
||||||
@ -126,16 +124,15 @@ class CloudRunner {
|
|||||||
CloudRunner.defaultSecrets,
|
CloudRunner.defaultSecrets,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Cleanup shared cloud runner resources');
|
|
||||||
await CloudRunner.Provider.cleanupWorkflow(
|
await CloudRunner.Provider.cleanupWorkflow(
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
CloudRunner.buildParameters,
|
||||||
CloudRunner.buildParameters.branch,
|
CloudRunner.buildParameters.branch,
|
||||||
CloudRunner.defaultSecrets,
|
CloudRunner.defaultSecrets,
|
||||||
);
|
);
|
||||||
CloudRunnerLogger.log(`Cleanup complete`);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
||||||
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, `success`, `success`, `completed`);
|
if (buildParameters.asyncWorkflow && this.isCloudRunnerEnvironment && this.isCloudRunnerAsyncEnvironment) {
|
||||||
|
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, `success`, `success`, `completed`);
|
||||||
|
}
|
||||||
|
|
||||||
if (BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
if (BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
||||||
const workspace = CloudRunner.lockedWorkspace || ``;
|
const workspace = CloudRunner.lockedWorkspace || ``;
|
||||||
@ -162,7 +159,7 @@ class CloudRunner {
|
|||||||
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageMaxAge, true, true);
|
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageMaxAge, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return new CloudRunnerResult(buildParameters, output, true, true, false);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
CloudRunnerLogger.log(JSON.stringify(error, undefined, 4));
|
CloudRunnerLogger.log(JSON.stringify(error, undefined, 4));
|
||||||
await GitHub.updateGitHubCheck(
|
await GitHub.updateGitHubCheck(
|
||||||
@ -176,5 +173,15 @@ class CloudRunner {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async updateStatusWithBuildParameters() {
|
||||||
|
const content = { ...CloudRunner.buildParameters };
|
||||||
|
content.gitPrivateToken = ``;
|
||||||
|
content.unitySerial = ``;
|
||||||
|
content.unityEmail = ``;
|
||||||
|
content.unityPassword = ``;
|
||||||
|
const jsonContent = JSON.stringify(content, undefined, 4);
|
||||||
|
await GitHub.updateGitHubCheck(jsonContent, CloudRunner.buildParameters.buildGuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export default CloudRunner;
|
export default CloudRunner;
|
||||||
|
@ -9,12 +9,7 @@ export class CloudRunnerError {
|
|||||||
CloudRunnerLogger.error(JSON.stringify(error, undefined, 4));
|
CloudRunnerLogger.error(JSON.stringify(error, undefined, 4));
|
||||||
core.setFailed('Cloud Runner failed');
|
core.setFailed('Cloud Runner failed');
|
||||||
if (CloudRunner.Provider !== undefined) {
|
if (CloudRunner.Provider !== undefined) {
|
||||||
await CloudRunner.Provider.cleanupWorkflow(
|
await CloudRunner.Provider.cleanupWorkflow(buildParameters, buildParameters.branch, secrets);
|
||||||
buildParameters.buildGuid,
|
|
||||||
buildParameters,
|
|
||||||
buildParameters.branch,
|
|
||||||
secrets,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,14 +103,14 @@ class CloudRunnerOptions {
|
|||||||
|
|
||||||
static get buildPlatform(): string {
|
static get buildPlatform(): string {
|
||||||
const input = CloudRunnerOptions.getInput('buildPlatform');
|
const input = CloudRunnerOptions.getInput('buildPlatform');
|
||||||
if (input) {
|
if (input && input !== '') {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
if (CloudRunnerOptions.providerStrategy !== 'local') {
|
if (CloudRunnerOptions.providerStrategy !== 'local') {
|
||||||
return 'linux';
|
return 'linux';
|
||||||
}
|
}
|
||||||
|
|
||||||
return ``;
|
return process.platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get cloudRunnerBranch(): string {
|
static get cloudRunnerBranch(): string {
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as SDK from 'aws-sdk';
|
import {
|
||||||
|
CloudFormation,
|
||||||
|
CreateStackCommand,
|
||||||
|
CreateStackCommandInput,
|
||||||
|
DescribeStacksCommand,
|
||||||
|
DescribeStacksCommandInput,
|
||||||
|
ListStacksCommand,
|
||||||
|
Parameter,
|
||||||
|
UpdateStackCommand,
|
||||||
|
UpdateStackCommandInput,
|
||||||
|
waitUntilStackCreateComplete,
|
||||||
|
waitUntilStackUpdateComplete,
|
||||||
|
} from '@aws-sdk/client-cloudformation';
|
||||||
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
import { BaseStackFormation } from './cloud-formations/base-stack-formation';
|
||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
|
|
||||||
@ -10,51 +22,49 @@ export class AWSBaseStack {
|
|||||||
}
|
}
|
||||||
private baseStackName: string;
|
private baseStackName: string;
|
||||||
|
|
||||||
async setupBaseStack(CF: SDK.CloudFormation) {
|
async setupBaseStack(CF: CloudFormation) {
|
||||||
const baseStackName = this.baseStackName;
|
const baseStackName = this.baseStackName;
|
||||||
|
|
||||||
const baseStack = BaseStackFormation.formation;
|
const baseStack = BaseStackFormation.formation;
|
||||||
|
|
||||||
// Cloud Formation Input
|
// Cloud Formation Input
|
||||||
const describeStackInput: SDK.CloudFormation.DescribeStacksInput = {
|
const describeStackInput: DescribeStacksCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
};
|
};
|
||||||
const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [
|
const parametersWithoutHash: Parameter[] = [{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName }];
|
||||||
{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName },
|
|
||||||
];
|
|
||||||
const parametersHash = crypto
|
const parametersHash = crypto
|
||||||
.createHash('md5')
|
.createHash('md5')
|
||||||
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
.update(baseStack + JSON.stringify(parametersWithoutHash))
|
||||||
.digest('hex');
|
.digest('hex');
|
||||||
const parameters: SDK.CloudFormation.Parameter[] = [
|
const parameters: Parameter[] = [
|
||||||
...parametersWithoutHash,
|
...parametersWithoutHash,
|
||||||
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
||||||
];
|
];
|
||||||
const updateInput: SDK.CloudFormation.UpdateStackInput = {
|
const updateInput: UpdateStackCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createStackInput: CreateStackCommandInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const stacks = await CF.listStacks({
|
const stacks = await CF.send(
|
||||||
StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'],
|
new ListStacksCommand({ StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'] }),
|
||||||
}).promise();
|
);
|
||||||
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
|
||||||
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
|
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
|
||||||
const describeStack = async () => {
|
const describeStack = async () => {
|
||||||
return await CF.describeStacks(describeStackInput).promise();
|
return await CF.send(new DescribeStacksCommand(describeStackInput));
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
if (!stackExists) {
|
if (!stackExists) {
|
||||||
CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
|
CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
|
||||||
await CF.createStack(createStackInput).promise();
|
await CF.send(new CreateStackCommand(createStackInput));
|
||||||
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
||||||
}
|
}
|
||||||
const CFState = await describeStack();
|
const CFState = await describeStack();
|
||||||
@ -65,7 +75,13 @@ export class AWSBaseStack {
|
|||||||
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
|
||||||
|
|
||||||
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
|
||||||
await CF.waitFor('stackCreateComplete', describeStackInput).promise();
|
await waitUntilStackCreateComplete(
|
||||||
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
describeStackInput,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackExists) {
|
if (stackExists) {
|
||||||
@ -73,7 +89,7 @@ export class AWSBaseStack {
|
|||||||
if (parametersHash !== stackVersion) {
|
if (parametersHash !== stackVersion) {
|
||||||
CloudRunnerLogger.log(`Attempting update of base stack`);
|
CloudRunnerLogger.log(`Attempting update of base stack`);
|
||||||
try {
|
try {
|
||||||
await CF.updateStack(updateInput).promise();
|
await CF.send(new UpdateStackCommand(updateInput));
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (error['message'].includes('No updates are to be performed')) {
|
if (error['message'].includes('No updates are to be performed')) {
|
||||||
CloudRunnerLogger.log(`No updates are to be performed`);
|
CloudRunnerLogger.log(`No updates are to be performed`);
|
||||||
@ -93,7 +109,13 @@ export class AWSBaseStack {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
||||||
await CF.waitFor('stackUpdateComplete', describeStackInput).promise();
|
await waitUntilStackUpdateComplete(
|
||||||
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
describeStackInput,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloudRunnerLogger.log('base stack is now ready');
|
CloudRunnerLogger.log('base stack is now ready');
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
||||||
import * as SDK from 'aws-sdk';
|
import { CloudFormation, DescribeStackEventsCommand } from '@aws-sdk/client-cloudformation';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
|
|
||||||
export class AWSError {
|
export class AWSError {
|
||||||
static async handleStackCreationFailure(error: any, CF: SDK.CloudFormation, taskDefStackName: string) {
|
static async handleStackCreationFailure(error: any, CF: CloudFormation, taskDefStackName: string) {
|
||||||
CloudRunnerLogger.log('aws error: ');
|
CloudRunnerLogger.log('aws error: ');
|
||||||
core.error(JSON.stringify(error, undefined, 4));
|
core.error(JSON.stringify(error, undefined, 4));
|
||||||
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
if (CloudRunner.buildParameters.cloudRunnerDebug) {
|
||||||
CloudRunnerLogger.log('Getting events and resources for task stack');
|
CloudRunnerLogger.log('Getting events and resources for task stack');
|
||||||
const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents;
|
const events = (await CF.send(new DescribeStackEventsCommand({ StackName: taskDefStackName }))).StackEvents;
|
||||||
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
import * as SDK from 'aws-sdk';
|
import {
|
||||||
|
CloudFormation,
|
||||||
|
CreateStackCommand,
|
||||||
|
CreateStackCommandInput,
|
||||||
|
DescribeStackResourcesCommand,
|
||||||
|
DescribeStacksCommand,
|
||||||
|
ListStacksCommand,
|
||||||
|
waitUntilStackCreateComplete,
|
||||||
|
} from '@aws-sdk/client-cloudformation';
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
||||||
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
||||||
@ -16,7 +24,7 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async setupCloudFormations(
|
public async setupCloudFormations(
|
||||||
CF: SDK.CloudFormation,
|
CF: CloudFormation,
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
image: string,
|
image: string,
|
||||||
entrypoint: string[],
|
entrypoint: string[],
|
||||||
@ -119,7 +127,7 @@ export class AWSJobStack {
|
|||||||
let previousStackExists = true;
|
let previousStackExists = true;
|
||||||
while (previousStackExists) {
|
while (previousStackExists) {
|
||||||
previousStackExists = false;
|
previousStackExists = false;
|
||||||
const stacks = await CF.listStacks().promise();
|
const stacks = await CF.send(new ListStacksCommand({}));
|
||||||
if (!stacks.StackSummaries) {
|
if (!stacks.StackSummaries) {
|
||||||
throw new Error('Faild to get stacks');
|
throw new Error('Faild to get stacks');
|
||||||
}
|
}
|
||||||
@ -132,7 +140,7 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createStackInput: CreateStackCommandInput = {
|
||||||
StackName: taskDefStackName,
|
StackName: taskDefStackName,
|
||||||
TemplateBody: taskDefCloudFormation,
|
TemplateBody: taskDefCloudFormation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
@ -140,9 +148,15 @@ export class AWSJobStack {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
||||||
await CF.createStack(createStackInput).promise();
|
await CF.send(new CreateStackCommand(createStackInput));
|
||||||
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
|
await waitUntilStackCreateComplete(
|
||||||
const describeStack = await CF.describeStacks({ StackName: taskDefStackName }).promise();
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
{ StackName: taskDefStackName },
|
||||||
|
);
|
||||||
|
const describeStack = await CF.send(new DescribeStacksCommand({ StackName: taskDefStackName }));
|
||||||
for (const parameter of parameters) {
|
for (const parameter of parameters) {
|
||||||
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
||||||
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
||||||
@ -153,7 +167,7 @@ export class AWSJobStack {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCleanupStackInput: SDK.CloudFormation.CreateStackInput = {
|
const createCleanupStackInput: CreateStackCommandInput = {
|
||||||
StackName: `${taskDefStackName}-cleanup`,
|
StackName: `${taskDefStackName}-cleanup`,
|
||||||
TemplateBody: CleanupCronFormation.formation,
|
TemplateBody: CleanupCronFormation.formation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
@ -183,7 +197,7 @@ export class AWSJobStack {
|
|||||||
if (CloudRunnerOptions.useCleanupCron) {
|
if (CloudRunnerOptions.useCleanupCron) {
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`Creating job cleanup formation`);
|
CloudRunnerLogger.log(`Creating job cleanup formation`);
|
||||||
await CF.createStack(createCleanupStackInput).promise();
|
await CF.send(new CreateStackCommand(createCleanupStackInput));
|
||||||
|
|
||||||
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -193,12 +207,15 @@ export class AWSJobStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const taskDefResources = (
|
const taskDefResources = (
|
||||||
await CF.describeStackResources({
|
await CF.send(
|
||||||
StackName: taskDefStackName,
|
new DescribeStackResourcesCommand({
|
||||||
}).promise()
|
StackName: taskDefStackName,
|
||||||
|
}),
|
||||||
|
)
|
||||||
).StackResources;
|
).StackResources;
|
||||||
|
|
||||||
const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources;
|
const baseResources = (await CF.send(new DescribeStackResourcesCommand({ StackName: this.baseStackName })))
|
||||||
|
.StackResources;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
taskDefStackName,
|
taskDefStackName,
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
import * as AWS from 'aws-sdk';
|
import {
|
||||||
|
DescribeTasksCommand,
|
||||||
|
ECS,
|
||||||
|
RunTaskCommand,
|
||||||
|
RunTaskCommandInput,
|
||||||
|
Task,
|
||||||
|
waitUntilTasksRunning,
|
||||||
|
} from '@aws-sdk/client-ecs';
|
||||||
|
import {
|
||||||
|
DescribeStreamCommand,
|
||||||
|
DescribeStreamCommandOutput,
|
||||||
|
GetRecordsCommand,
|
||||||
|
GetRecordsCommandOutput,
|
||||||
|
GetShardIteratorCommand,
|
||||||
|
Kinesis,
|
||||||
|
} from '@aws-sdk/client-kinesis';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
@ -12,8 +27,8 @@ import CloudRunnerOptions from '../../options/cloud-runner-options';
|
|||||||
import GitHub from '../../../github';
|
import GitHub from '../../../github';
|
||||||
|
|
||||||
class AWSTaskRunner {
|
class AWSTaskRunner {
|
||||||
public static ECS: AWS.ECS;
|
public static ECS: ECS;
|
||||||
public static Kinesis: AWS.Kinesis;
|
public static Kinesis: Kinesis;
|
||||||
private static readonly encodedUnderscore = `$252F`;
|
private static readonly encodedUnderscore = `$252F`;
|
||||||
static async runTask(
|
static async runTask(
|
||||||
taskDef: CloudRunnerAWSTaskDef,
|
taskDef: CloudRunnerAWSTaskDef,
|
||||||
@ -60,7 +75,7 @@ class AWSTaskRunner {
|
|||||||
throw new Error(`Container Overrides length must be at most 8192`);
|
throw new Error(`Container Overrides length must be at most 8192`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const task = await AWSTaskRunner.ECS.runTask(runParameters).promise();
|
const task = await AWSTaskRunner.ECS.send(new RunTaskCommand(runParameters as RunTaskCommandInput));
|
||||||
const taskArn = task.tasks?.[0].taskArn || '';
|
const taskArn = task.tasks?.[0].taskArn || '';
|
||||||
CloudRunnerLogger.log('Cloud runner job is starting');
|
CloudRunnerLogger.log('Cloud runner job is starting');
|
||||||
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
await AWSTaskRunner.waitUntilTaskRunning(taskArn, cluster);
|
||||||
@ -108,7 +123,13 @@ class AWSTaskRunner {
|
|||||||
|
|
||||||
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
||||||
try {
|
try {
|
||||||
await AWSTaskRunner.ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
|
await waitUntilTasksRunning(
|
||||||
|
{
|
||||||
|
client: AWSTaskRunner.ECS,
|
||||||
|
maxWaitTime: 120,
|
||||||
|
},
|
||||||
|
{ tasks: [taskArn], cluster },
|
||||||
|
);
|
||||||
} catch (error_) {
|
} catch (error_) {
|
||||||
const error = error_ as Error;
|
const error = error_ as Error;
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
@ -124,10 +145,7 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async describeTasks(clusterName: string, taskArn: string) {
|
static async describeTasks(clusterName: string, taskArn: string) {
|
||||||
const tasks = await AWSTaskRunner.ECS.describeTasks({
|
const tasks = await AWSTaskRunner.ECS.send(new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
||||||
cluster: clusterName,
|
|
||||||
tasks: [taskArn],
|
|
||||||
}).promise();
|
|
||||||
if (tasks.tasks?.[0]) {
|
if (tasks.tasks?.[0]) {
|
||||||
return tasks.tasks?.[0];
|
return tasks.tasks?.[0];
|
||||||
} else {
|
} else {
|
||||||
@ -169,9 +187,7 @@ class AWSTaskRunner {
|
|||||||
output: string,
|
output: string,
|
||||||
shouldCleanup: boolean,
|
shouldCleanup: boolean,
|
||||||
) {
|
) {
|
||||||
const records = await AWSTaskRunner.Kinesis.getRecords({
|
const records = await AWSTaskRunner.Kinesis.send(new GetRecordsCommand({ ShardIterator: iterator }));
|
||||||
ShardIterator: iterator,
|
|
||||||
}).promise();
|
|
||||||
iterator = records.NextShardIterator || '';
|
iterator = records.NextShardIterator || '';
|
||||||
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
||||||
records,
|
records,
|
||||||
@ -184,7 +200,7 @@ class AWSTaskRunner {
|
|||||||
return { iterator, shouldReadLogs, output, shouldCleanup };
|
return { iterator, shouldReadLogs, output, shouldCleanup };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static checkStreamingShouldContinue(taskData: AWS.ECS.Task, timestamp: number, shouldReadLogs: boolean) {
|
private static checkStreamingShouldContinue(taskData: Task, timestamp: number, shouldReadLogs: boolean) {
|
||||||
if (taskData?.lastStatus === 'UNKNOWN') {
|
if (taskData?.lastStatus === 'UNKNOWN') {
|
||||||
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
CloudRunnerLogger.log('## Cloud runner job unknwon');
|
||||||
}
|
}
|
||||||
@ -204,15 +220,17 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static logRecords(
|
private static logRecords(
|
||||||
records: AWS.Kinesis.GetRecordsOutput,
|
records: GetRecordsCommandOutput,
|
||||||
iterator: string,
|
iterator: string,
|
||||||
shouldReadLogs: boolean,
|
shouldReadLogs: boolean,
|
||||||
output: string,
|
output: string,
|
||||||
shouldCleanup: boolean,
|
shouldCleanup: boolean,
|
||||||
) {
|
) {
|
||||||
if (records.Records.length > 0 && iterator) {
|
if ((records.Records ?? []).length > 0 && iterator) {
|
||||||
for (const record of records.Records) {
|
for (const record of records.Records ?? []) {
|
||||||
const json = JSON.parse(zlib.gunzipSync(Buffer.from(record.Data as string, 'base64')).toString('utf8'));
|
const json = JSON.parse(
|
||||||
|
zlib.gunzipSync(Buffer.from(record.Data as unknown as string, 'base64')).toString('utf8'),
|
||||||
|
);
|
||||||
if (json.messageType === 'DATA_MESSAGE') {
|
if (json.messageType === 'DATA_MESSAGE') {
|
||||||
for (const logEvent of json.logEvents) {
|
for (const logEvent of json.logEvents) {
|
||||||
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
||||||
@ -230,19 +248,19 @@ class AWSTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogStream(kinesisStreamName: string) {
|
private static async getLogStream(kinesisStreamName: string) {
|
||||||
return await AWSTaskRunner.Kinesis.describeStream({
|
return await AWSTaskRunner.Kinesis.send(new DescribeStreamCommand({ StreamName: kinesisStreamName }));
|
||||||
StreamName: kinesisStreamName,
|
|
||||||
}).promise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogIterator(stream: AWS.Kinesis.DescribeStreamOutput) {
|
private static async getLogIterator(stream: DescribeStreamCommandOutput) {
|
||||||
return (
|
return (
|
||||||
(
|
(
|
||||||
await AWSTaskRunner.Kinesis.getShardIterator({
|
await AWSTaskRunner.Kinesis.send(
|
||||||
ShardIteratorType: 'TRIM_HORIZON',
|
new GetShardIteratorCommand({
|
||||||
StreamName: stream.StreamDescription.StreamName,
|
ShardIteratorType: 'TRIM_HORIZON',
|
||||||
ShardId: stream.StreamDescription.Shards[0].ShardId,
|
StreamName: stream.StreamDescription?.StreamName ?? '',
|
||||||
}).promise()
|
ShardId: stream.StreamDescription?.Shards?.[0]?.ShardId || '',
|
||||||
|
}),
|
||||||
|
)
|
||||||
).ShardIterator || ''
|
).ShardIterator || ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import CloudRunner from '../../../cloud-runner';
|
||||||
|
|
||||||
export class TaskDefinitionFormation {
|
export class TaskDefinitionFormation {
|
||||||
public static readonly description: string = `Game CI Cloud Runner Task Stack`;
|
public static readonly description: string = `Game CI Cloud Runner Task Stack`;
|
||||||
public static readonly formation: string = `AWSTemplateFormatVersion: 2010-09-09
|
public static get formation(): string {
|
||||||
|
return `AWSTemplateFormatVersion: 2010-09-09
|
||||||
Description: ${TaskDefinitionFormation.description}
|
Description: ${TaskDefinitionFormation.description}
|
||||||
Parameters:
|
Parameters:
|
||||||
EnvironmentName:
|
EnvironmentName:
|
||||||
@ -26,11 +29,11 @@ Parameters:
|
|||||||
Default: 80
|
Default: 80
|
||||||
Description: What port number the application inside the docker container is binding to
|
Description: What port number the application inside the docker container is binding to
|
||||||
ContainerCpu:
|
ContainerCpu:
|
||||||
Default: 1024
|
Default: ${CloudRunner.buildParameters.containerCpu}
|
||||||
Type: Number
|
Type: Number
|
||||||
Description: How much CPU to give the container. 1024 is 1 CPU
|
Description: How much CPU to give the container. 1024 is 1 CPU
|
||||||
ContainerMemory:
|
ContainerMemory:
|
||||||
Default: 4096
|
Default: ${CloudRunner.buildParameters.containerMemory}
|
||||||
Type: Number
|
Type: Number
|
||||||
Description: How much memory in megabytes to give the container
|
Description: How much memory in megabytes to give the container
|
||||||
BUILDGUID:
|
BUILDGUID:
|
||||||
@ -92,7 +95,7 @@ Resources:
|
|||||||
EFSVolumeConfiguration:
|
EFSVolumeConfiguration:
|
||||||
FilesystemId:
|
FilesystemId:
|
||||||
'Fn::ImportValue': !Sub '${'${EnvironmentName}'}:EfsFileStorageId'
|
'Fn::ImportValue': !Sub '${'${EnvironmentName}'}:EfsFileStorageId'
|
||||||
TransitEncryption: ENABLED
|
TransitEncryption: DISABLED
|
||||||
RequiresCompatibilities:
|
RequiresCompatibilities:
|
||||||
- FARGATE
|
- FARGATE
|
||||||
ExecutionRoleArn:
|
ExecutionRoleArn:
|
||||||
@ -135,6 +138,7 @@ Resources:
|
|||||||
DependsOn:
|
DependsOn:
|
||||||
- LogGroup
|
- LogGroup
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
public static streamLogs = `
|
public static streamLogs = `
|
||||||
SubscriptionFilter:
|
SubscriptionFilter:
|
||||||
Type: 'AWS::Logs::SubscriptionFilter'
|
Type: 'AWS::Logs::SubscriptionFilter'
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import * as AWS from 'aws-sdk';
|
import { StackResource } from '@aws-sdk/client-cloudformation';
|
||||||
|
|
||||||
class CloudRunnerAWSTaskDef {
|
class CloudRunnerAWSTaskDef {
|
||||||
public taskDefStackName!: string;
|
public taskDefStackName!: string;
|
||||||
public taskDefCloudFormation!: string;
|
public taskDefCloudFormation!: string;
|
||||||
public taskDefResources: AWS.CloudFormation.StackResources | undefined;
|
public taskDefResources: StackResource[] | undefined;
|
||||||
public baseResources: AWS.CloudFormation.StackResources | undefined;
|
public baseResources: StackResource[] | undefined;
|
||||||
}
|
}
|
||||||
export default CloudRunnerAWSTaskDef;
|
export default CloudRunnerAWSTaskDef;
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import * as SDK from 'aws-sdk';
|
import { CloudFormation, DeleteStackCommand, waitUntilStackDeleteComplete } from '@aws-sdk/client-cloudformation';
|
||||||
|
import { ECS as ECSClient } from '@aws-sdk/client-ecs';
|
||||||
|
import { Kinesis } from '@aws-sdk/client-kinesis';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
@ -57,8 +59,6 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cleanupWorkflow(
|
async cleanupWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
buildGuid: string,
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
@ -77,7 +77,7 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
||||||
) {
|
) {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const CF = new SDK.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
await new AwsBaseStack(this.baseStackName).setupBaseStack(CF);
|
await new AwsBaseStack(this.baseStackName).setupBaseStack(CF);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +91,10 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
secrets: CloudRunnerSecret[],
|
secrets: CloudRunnerSecret[],
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const ECS = new SDK.ECS();
|
const ECS = new ECSClient({ region: Input.region });
|
||||||
const CF = new SDK.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
AwsTaskRunner.ECS = ECS;
|
AwsTaskRunner.ECS = ECS;
|
||||||
AwsTaskRunner.Kinesis = new SDK.Kinesis();
|
AwsTaskRunner.Kinesis = new Kinesis({ region: Input.region });
|
||||||
CloudRunnerLogger.log(`AWS Region: ${CF.config.region}`);
|
CloudRunnerLogger.log(`AWS Region: ${CF.config.region}`);
|
||||||
const entrypoint = ['/bin/sh'];
|
const entrypoint = ['/bin/sh'];
|
||||||
const startTimeMs = Date.now();
|
const startTimeMs = Date.now();
|
||||||
@ -131,23 +131,31 @@ class AWSBuildEnvironment implements ProviderInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cleanupResources(CF: SDK.CloudFormation, taskDef: CloudRunnerAWSTaskDef) {
|
async cleanupResources(CF: CloudFormation, taskDef: CloudRunnerAWSTaskDef) {
|
||||||
CloudRunnerLogger.log('Cleanup starting');
|
CloudRunnerLogger.log('Cleanup starting');
|
||||||
await CF.deleteStack({
|
await CF.send(new DeleteStackCommand({ StackName: taskDef.taskDefStackName }));
|
||||||
StackName: taskDef.taskDefStackName,
|
|
||||||
}).promise();
|
|
||||||
if (CloudRunnerOptions.useCleanupCron) {
|
if (CloudRunnerOptions.useCleanupCron) {
|
||||||
await CF.deleteStack({
|
await CF.send(new DeleteStackCommand({ StackName: `${taskDef.taskDefStackName}-cleanup` }));
|
||||||
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
|
||||||
}).promise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await CF.waitFor('stackDeleteComplete', {
|
await waitUntilStackDeleteComplete(
|
||||||
StackName: taskDef.taskDefStackName,
|
{
|
||||||
}).promise();
|
client: CF,
|
||||||
await CF.waitFor('stackDeleteComplete', {
|
maxWaitTime: 200,
|
||||||
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
},
|
||||||
}).promise();
|
{
|
||||||
|
StackName: taskDef.taskDefStackName,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await waitUntilStackDeleteComplete(
|
||||||
|
{
|
||||||
|
client: CF,
|
||||||
|
maxWaitTime: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
||||||
|
},
|
||||||
|
);
|
||||||
CloudRunnerLogger.log(`Deleted Stack: ${taskDef.taskDefStackName}`);
|
CloudRunnerLogger.log(`Deleted Stack: ${taskDef.taskDefStackName}`);
|
||||||
CloudRunnerLogger.log('Cleanup complete');
|
CloudRunnerLogger.log('Cleanup complete');
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import AWS from 'aws-sdk';
|
import {
|
||||||
|
CloudFormation,
|
||||||
|
DeleteStackCommand,
|
||||||
|
DeleteStackCommandInput,
|
||||||
|
DescribeStackResourcesCommand,
|
||||||
|
} from '@aws-sdk/client-cloudformation';
|
||||||
|
import { CloudWatchLogs, DeleteLogGroupCommand } from '@aws-sdk/client-cloudwatch-logs';
|
||||||
|
import { ECS, StopTaskCommand } from '@aws-sdk/client-ecs';
|
||||||
import Input from '../../../../input';
|
import Input from '../../../../input';
|
||||||
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
|
||||||
import { TaskService } from './task-service';
|
import { TaskService } from './task-service';
|
||||||
@ -12,9 +19,9 @@ export class GarbageCollectionService {
|
|||||||
|
|
||||||
public static async cleanup(deleteResources = false, OneDayOlderOnly: boolean = false) {
|
public static async cleanup(deleteResources = false, OneDayOlderOnly: boolean = false) {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const CF = new AWS.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
const ecs = new AWS.ECS();
|
const ecs = new ECS({ region: Input.region });
|
||||||
const cwl = new AWS.CloudWatchLogs();
|
const cwl = new CloudWatchLogs({ region: Input.region });
|
||||||
const taskDefinitionsInUse = new Array();
|
const taskDefinitionsInUse = new Array();
|
||||||
const tasks = await TaskService.getTasks();
|
const tasks = await TaskService.getTasks();
|
||||||
|
|
||||||
@ -23,14 +30,14 @@ export class GarbageCollectionService {
|
|||||||
taskDefinitionsInUse.push(taskElement.taskDefinitionArn);
|
taskDefinitionsInUse.push(taskElement.taskDefinitionArn);
|
||||||
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(taskElement.createdAt!))) {
|
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(taskElement.createdAt!))) {
|
||||||
CloudRunnerLogger.log(`Stopping task ${taskElement.containers?.[0].name}`);
|
CloudRunnerLogger.log(`Stopping task ${taskElement.containers?.[0].name}`);
|
||||||
await ecs.stopTask({ task: taskElement.taskArn || '', cluster: element }).promise();
|
await ecs.send(new StopTaskCommand({ task: taskElement.taskArn || '', cluster: element }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const jobStacks = await TaskService.getCloudFormationJobStacks();
|
const jobStacks = await TaskService.getCloudFormationJobStacks();
|
||||||
for (const element of jobStacks) {
|
for (const element of jobStacks) {
|
||||||
if (
|
if (
|
||||||
(await CF.describeStackResources({ StackName: element.StackName }).promise()).StackResources?.some(
|
(await CF.send(new DescribeStackResourcesCommand({ StackName: element.StackName }))).StackResources?.some(
|
||||||
(x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId),
|
(x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -39,7 +46,10 @@ export class GarbageCollectionService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(element.CreationTime))) {
|
if (
|
||||||
|
deleteResources &&
|
||||||
|
(!OneDayOlderOnly || (element.CreationTime && GarbageCollectionService.isOlderThan1day(element.CreationTime)))
|
||||||
|
) {
|
||||||
if (element.StackName === 'game-ci' || element.TemplateDescription === 'Game-CI base stack') {
|
if (element.StackName === 'game-ci' || element.TemplateDescription === 'Game-CI base stack') {
|
||||||
CloudRunnerLogger.log(`Skipping ${element.StackName} ignore list`);
|
CloudRunnerLogger.log(`Skipping ${element.StackName} ignore list`);
|
||||||
|
|
||||||
@ -47,8 +57,8 @@ export class GarbageCollectionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CloudRunnerLogger.log(`Deleting ${element.StackName}`);
|
CloudRunnerLogger.log(`Deleting ${element.StackName}`);
|
||||||
const deleteStackInput: AWS.CloudFormation.DeleteStackInput = { StackName: element.StackName };
|
const deleteStackInput: DeleteStackCommandInput = { StackName: element.StackName };
|
||||||
await CF.deleteStack(deleteStackInput).promise();
|
await CF.send(new DeleteStackCommand(deleteStackInput));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const logGroups = await TaskService.getLogGroups();
|
const logGroups = await TaskService.getLogGroups();
|
||||||
@ -58,7 +68,7 @@ export class GarbageCollectionService {
|
|||||||
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!)))
|
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!)))
|
||||||
) {
|
) {
|
||||||
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
|
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
|
||||||
await cwl.deleteLogGroup({ logGroupName: element.logGroupName || '' }).promise();
|
await cwl.send(new DeleteLogGroupCommand({ logGroupName: element.logGroupName || '' }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,31 @@
|
|||||||
import AWS from 'aws-sdk';
|
import {
|
||||||
|
CloudFormation,
|
||||||
|
DescribeStackResourcesCommand,
|
||||||
|
DescribeStacksCommand,
|
||||||
|
ListStacksCommand,
|
||||||
|
StackSummary,
|
||||||
|
} from '@aws-sdk/client-cloudformation';
|
||||||
|
import {
|
||||||
|
CloudWatchLogs,
|
||||||
|
DescribeLogGroupsCommand,
|
||||||
|
DescribeLogGroupsCommandInput,
|
||||||
|
LogGroup,
|
||||||
|
} from '@aws-sdk/client-cloudwatch-logs';
|
||||||
|
import {
|
||||||
|
DescribeTasksCommand,
|
||||||
|
DescribeTasksCommandInput,
|
||||||
|
ECS,
|
||||||
|
ListClustersCommand,
|
||||||
|
ListTasksCommand,
|
||||||
|
ListTasksCommandInput,
|
||||||
|
Task,
|
||||||
|
} from '@aws-sdk/client-ecs';
|
||||||
|
import { ListObjectsCommand, ListObjectsCommandInput, S3 } from '@aws-sdk/client-s3';
|
||||||
import Input from '../../../../input';
|
import Input from '../../../../input';
|
||||||
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../../services/core/cloud-runner-logger';
|
||||||
import { BaseStackFormation } from '../cloud-formations/base-stack-formation';
|
import { BaseStackFormation } from '../cloud-formations/base-stack-formation';
|
||||||
import AwsTaskRunner from '../aws-task-runner';
|
import AwsTaskRunner from '../aws-task-runner';
|
||||||
import { ListObjectsRequest } from 'aws-sdk/clients/s3';
|
|
||||||
import CloudRunner from '../../../cloud-runner';
|
import CloudRunner from '../../../cloud-runner';
|
||||||
import { StackSummaries } from 'aws-sdk/clients/cloudformation';
|
|
||||||
import { LogGroups } from 'aws-sdk/clients/cloudwatchlogs';
|
|
||||||
|
|
||||||
export class TaskService {
|
export class TaskService {
|
||||||
static async watch() {
|
static async watch() {
|
||||||
@ -20,20 +39,24 @@ export class TaskService {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
public static async getCloudFormationJobStacks() {
|
public static async getCloudFormationJobStacks() {
|
||||||
const result: StackSummaries = [];
|
const result: StackSummary[] = [];
|
||||||
CloudRunnerLogger.log(``);
|
CloudRunnerLogger.log(``);
|
||||||
CloudRunnerLogger.log(`List Cloud Formation Stacks`);
|
CloudRunnerLogger.log(`List Cloud Formation Stacks`);
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const CF = new AWS.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
const stacks =
|
const stacks =
|
||||||
(await CF.listStacks().promise()).StackSummaries?.filter(
|
(await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
|
||||||
(_x) =>
|
(_x) =>
|
||||||
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription !== BaseStackFormation.baseStackDecription,
|
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription !== BaseStackFormation.baseStackDecription,
|
||||||
) || [];
|
) || [];
|
||||||
CloudRunnerLogger.log(``);
|
CloudRunnerLogger.log(``);
|
||||||
CloudRunnerLogger.log(`Cloud Formation Stacks ${stacks.length}`);
|
CloudRunnerLogger.log(`Cloud Formation Stacks ${stacks.length}`);
|
||||||
for (const element of stacks) {
|
for (const element of stacks) {
|
||||||
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime());
|
if (!element.CreationTime) {
|
||||||
|
CloudRunnerLogger.log(`${element.StackName} due to undefined CreationTime`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ageDate: Date = new Date(Date.now() - (element.CreationTime?.getTime() ?? 0));
|
||||||
|
|
||||||
CloudRunnerLogger.log(
|
CloudRunnerLogger.log(
|
||||||
`Task Stack ${element.StackName} - Age D${Math.floor(
|
`Task Stack ${element.StackName} - Age D${Math.floor(
|
||||||
@ -43,14 +66,18 @@ export class TaskService {
|
|||||||
result.push(element);
|
result.push(element);
|
||||||
}
|
}
|
||||||
const baseStacks =
|
const baseStacks =
|
||||||
(await CF.listStacks().promise()).StackSummaries?.filter(
|
(await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
|
||||||
(_x) =>
|
(_x) =>
|
||||||
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription === BaseStackFormation.baseStackDecription,
|
_x.StackStatus !== 'DELETE_COMPLETE' && _x.TemplateDescription === BaseStackFormation.baseStackDecription,
|
||||||
) || [];
|
) || [];
|
||||||
CloudRunnerLogger.log(``);
|
CloudRunnerLogger.log(``);
|
||||||
CloudRunnerLogger.log(`Base Stacks ${baseStacks.length}`);
|
CloudRunnerLogger.log(`Base Stacks ${baseStacks.length}`);
|
||||||
for (const element of baseStacks) {
|
for (const element of baseStacks) {
|
||||||
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime());
|
if (!element.CreationTime) {
|
||||||
|
CloudRunnerLogger.log(`${element.StackName} due to undefined CreationTime`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ageDate: Date = new Date(Date.now() - (element.CreationTime?.getTime() ?? 0));
|
||||||
|
|
||||||
CloudRunnerLogger.log(
|
CloudRunnerLogger.log(
|
||||||
`Task Stack ${element.StackName} - Age D${Math.floor(
|
`Task Stack ${element.StackName} - Age D${Math.floor(
|
||||||
@ -64,22 +91,22 @@ export class TaskService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static async getTasks() {
|
public static async getTasks() {
|
||||||
const result: { taskElement: AWS.ECS.Task; element: string }[] = [];
|
const result: { taskElement: Task; element: string }[] = [];
|
||||||
CloudRunnerLogger.log(``);
|
CloudRunnerLogger.log(``);
|
||||||
CloudRunnerLogger.log(`List Tasks`);
|
CloudRunnerLogger.log(`List Tasks`);
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const ecs = new AWS.ECS();
|
const ecs = new ECS({ region: Input.region });
|
||||||
const clusters = (await ecs.listClusters().promise()).clusterArns || [];
|
const clusters = (await ecs.send(new ListClustersCommand({}))).clusterArns || [];
|
||||||
CloudRunnerLogger.log(`Task Clusters ${clusters.length}`);
|
CloudRunnerLogger.log(`Task Clusters ${clusters.length}`);
|
||||||
for (const element of clusters) {
|
for (const element of clusters) {
|
||||||
const input: AWS.ECS.ListTasksRequest = {
|
const input: ListTasksCommandInput = {
|
||||||
cluster: element,
|
cluster: element,
|
||||||
};
|
};
|
||||||
|
|
||||||
const list = (await ecs.listTasks(input).promise()).taskArns || [];
|
const list = (await ecs.send(new ListTasksCommand(input))).taskArns || [];
|
||||||
if (list.length > 0) {
|
if (list.length > 0) {
|
||||||
const describeInput: AWS.ECS.DescribeTasksRequest = { tasks: list, cluster: element };
|
const describeInput: DescribeTasksCommandInput = { tasks: list, cluster: element };
|
||||||
const describeList = (await ecs.describeTasks(describeInput).promise()).tasks || [];
|
const describeList = (await ecs.send(new DescribeTasksCommand(describeInput))).tasks || [];
|
||||||
if (describeList.length === 0) {
|
if (describeList.length === 0) {
|
||||||
CloudRunnerLogger.log(`No Tasks`);
|
CloudRunnerLogger.log(`No Tasks`);
|
||||||
continue;
|
continue;
|
||||||
@ -105,37 +132,48 @@ export class TaskService {
|
|||||||
}
|
}
|
||||||
public static async awsDescribeJob(job: string) {
|
public static async awsDescribeJob(job: string) {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const CF = new AWS.CloudFormation();
|
const CF = new CloudFormation({ region: Input.region });
|
||||||
const stack = (await CF.listStacks().promise()).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
|
try {
|
||||||
const stackInfo = (await CF.describeStackResources({ StackName: job }).promise()) || undefined;
|
const stack =
|
||||||
const stackInfo2 = (await CF.describeStacks({ StackName: job }).promise()) || undefined;
|
(await CF.send(new ListStacksCommand({}))).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
|
||||||
if (stack === undefined) {
|
const stackInfo = (await CF.send(new DescribeStackResourcesCommand({ StackName: job }))) || undefined;
|
||||||
throw new Error('stack not defined');
|
const stackInfo2 = (await CF.send(new DescribeStacksCommand({ StackName: job }))) || undefined;
|
||||||
}
|
if (stack === undefined) {
|
||||||
const ageDate: Date = new Date(Date.now() - stack.CreationTime.getTime());
|
throw new Error('stack not defined');
|
||||||
const message = `
|
}
|
||||||
|
if (!stack.CreationTime) {
|
||||||
|
CloudRunnerLogger.log(`${stack.StackName} due to undefined CreationTime`);
|
||||||
|
}
|
||||||
|
const ageDate: Date = new Date(Date.now() - (stack.CreationTime?.getTime() ?? 0));
|
||||||
|
const message = `
|
||||||
Task Stack ${stack.StackName}
|
Task Stack ${stack.StackName}
|
||||||
Age D${Math.floor(ageDate.getHours() / 24)} H${ageDate.getHours()} M${ageDate.getMinutes()}
|
Age D${Math.floor(ageDate.getHours() / 24)} H${ageDate.getHours()} M${ageDate.getMinutes()}
|
||||||
${JSON.stringify(stack, undefined, 4)}
|
${JSON.stringify(stack, undefined, 4)}
|
||||||
${JSON.stringify(stackInfo, undefined, 4)}
|
${JSON.stringify(stackInfo, undefined, 4)}
|
||||||
${JSON.stringify(stackInfo2, undefined, 4)}
|
${JSON.stringify(stackInfo2, undefined, 4)}
|
||||||
`;
|
`;
|
||||||
CloudRunnerLogger.log(message);
|
CloudRunnerLogger.log(message);
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
|
} catch (error) {
|
||||||
|
CloudRunnerLogger.error(
|
||||||
|
`Failed to describe job ${job}: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public static async getLogGroups() {
|
public static async getLogGroups() {
|
||||||
const result: LogGroups = [];
|
const result: Array<LogGroup> = [];
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const ecs = new AWS.CloudWatchLogs();
|
const ecs = new CloudWatchLogs();
|
||||||
let logStreamInput: AWS.CloudWatchLogs.DescribeLogGroupsRequest = {
|
let logStreamInput: DescribeLogGroupsCommandInput = {
|
||||||
/* logGroupNamePrefix: 'game-ci' */
|
/* logGroupNamePrefix: 'game-ci' */
|
||||||
};
|
};
|
||||||
let logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise();
|
let logGroupsDescribe = await ecs.send(new DescribeLogGroupsCommand(logStreamInput));
|
||||||
const logGroups = logGroupsDescribe.logGroups || [];
|
const logGroups = logGroupsDescribe.logGroups || [];
|
||||||
while (logGroupsDescribe.nextToken) {
|
while (logGroupsDescribe.nextToken) {
|
||||||
logStreamInput = { /* logGroupNamePrefix: 'game-ci',*/ nextToken: logGroupsDescribe.nextToken };
|
logStreamInput = { /* logGroupNamePrefix: 'game-ci',*/ nextToken: logGroupsDescribe.nextToken };
|
||||||
logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise();
|
logGroupsDescribe = await ecs.send(new DescribeLogGroupsCommand(logStreamInput));
|
||||||
logGroups.push(...(logGroupsDescribe?.logGroups || []));
|
logGroups.push(...(logGroupsDescribe?.logGroups || []));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,11 +197,12 @@ export class TaskService {
|
|||||||
}
|
}
|
||||||
public static async getLocks() {
|
public static async getLocks() {
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const s3 = new AWS.S3();
|
const s3 = new S3({ region: Input.region });
|
||||||
const listRequest: ListObjectsRequest = {
|
const listRequest: ListObjectsCommandInput = {
|
||||||
Bucket: CloudRunner.buildParameters.awsStackName,
|
Bucket: CloudRunner.buildParameters.awsStackName,
|
||||||
};
|
};
|
||||||
const results = await s3.listObjects(listRequest).promise();
|
|
||||||
|
const results = await s3.send(new ListObjectsCommand(listRequest));
|
||||||
|
|
||||||
return results.Contents || [];
|
return results.Contents || [];
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ class LocalDockerCloudRunner implements ProviderInterface {
|
|||||||
return new Promise((result) => result(``));
|
return new Promise((result) => result(``));
|
||||||
}
|
}
|
||||||
async cleanupWorkflow(
|
async cleanupWorkflow(
|
||||||
buildGuid: string,
|
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
branchName: string,
|
branchName: string,
|
||||||
@ -133,7 +132,7 @@ cp -a ${sharedFolder}. /github/workspace/cloud-runner-cache/
|
|||||||
if (fs.existsSync(`${workspace}/cloud-runner-cache`)) {
|
if (fs.existsSync(`${workspace}/cloud-runner-cache`)) {
|
||||||
await CloudRunnerSystem.Run(`ls ${workspace}/cloud-runner-cache && du -sh ${workspace}/cloud-runner-cache`);
|
await CloudRunnerSystem.Run(`ls ${workspace}/cloud-runner-cache && du -sh ${workspace}/cloud-runner-cache`);
|
||||||
}
|
}
|
||||||
await Docker.run(
|
const exitCode = await Docker.run(
|
||||||
image,
|
image,
|
||||||
{ workspace, actionFolder, ...this.buildParameters },
|
{ workspace, actionFolder, ...this.buildParameters },
|
||||||
false,
|
false,
|
||||||
@ -150,9 +149,14 @@ cp -a ${sharedFolder}. /github/workspace/cloud-runner-cache/
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Docker doesn't exit on fail now so adding this to ensure behavior is unchanged
|
||||||
|
// TODO: Is there a helpful way to consume the exit code or is it best to except
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
throw new Error(`Build failed with exit code ${exitCode}`);
|
||||||
|
}
|
||||||
|
|
||||||
return myOutput;
|
return myOutput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,17 @@ import { CoreV1Api } from '@kubernetes/client-node';
|
|||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
import { ProviderResource } from '../provider-resource';
|
import { ProviderResource } from '../provider-resource';
|
||||||
import { ProviderWorkflow } from '../provider-workflow';
|
import { ProviderWorkflow } from '../provider-workflow';
|
||||||
|
import { RemoteClientLogger } from '../../remote-client/remote-client-logger';
|
||||||
|
import { KubernetesRole } from './kubernetes-role';
|
||||||
|
import { CloudRunnerSystem } from '../../services/core/cloud-runner-system';
|
||||||
|
|
||||||
class Kubernetes implements ProviderInterface {
|
class Kubernetes implements ProviderInterface {
|
||||||
public static Instance: Kubernetes;
|
public static Instance: Kubernetes;
|
||||||
public kubeConfig!: k8s.KubeConfig;
|
public kubeConfig!: k8s.KubeConfig;
|
||||||
public kubeClient!: k8s.CoreV1Api;
|
public kubeClient!: k8s.CoreV1Api;
|
||||||
|
public kubeClientApps!: k8s.AppsV1Api;
|
||||||
public kubeClientBatch!: k8s.BatchV1Api;
|
public kubeClientBatch!: k8s.BatchV1Api;
|
||||||
|
public rbacAuthorizationV1Api!: k8s.RbacAuthorizationV1Api;
|
||||||
public buildGuid: string = '';
|
public buildGuid: string = '';
|
||||||
public buildParameters!: BuildParameters;
|
public buildParameters!: BuildParameters;
|
||||||
public pvcName: string = '';
|
public pvcName: string = '';
|
||||||
@ -30,6 +35,7 @@ class Kubernetes implements ProviderInterface {
|
|||||||
public containerName: string = '';
|
public containerName: string = '';
|
||||||
public cleanupCronJobName: string = '';
|
public cleanupCronJobName: string = '';
|
||||||
public serviceAccountName: string = '';
|
public serviceAccountName: string = '';
|
||||||
|
public ip: string = '';
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
constructor(buildParameters: BuildParameters) {
|
constructor(buildParameters: BuildParameters) {
|
||||||
@ -37,11 +43,30 @@ class Kubernetes implements ProviderInterface {
|
|||||||
this.kubeConfig = new k8s.KubeConfig();
|
this.kubeConfig = new k8s.KubeConfig();
|
||||||
this.kubeConfig.loadFromDefault();
|
this.kubeConfig.loadFromDefault();
|
||||||
this.kubeClient = this.kubeConfig.makeApiClient(k8s.CoreV1Api);
|
this.kubeClient = this.kubeConfig.makeApiClient(k8s.CoreV1Api);
|
||||||
|
this.kubeClientApps = this.kubeConfig.makeApiClient(k8s.AppsV1Api);
|
||||||
this.kubeClientBatch = this.kubeConfig.makeApiClient(k8s.BatchV1Api);
|
this.kubeClientBatch = this.kubeConfig.makeApiClient(k8s.BatchV1Api);
|
||||||
|
this.rbacAuthorizationV1Api = this.kubeConfig.makeApiClient(k8s.RbacAuthorizationV1Api);
|
||||||
this.namespace = 'default';
|
this.namespace = 'default';
|
||||||
CloudRunnerLogger.log('Loaded default Kubernetes configuration for this environment');
|
CloudRunnerLogger.log('Loaded default Kubernetes configuration for this environment');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async PushLogUpdate(logs: string) {
|
||||||
|
// push logs to nginx file server via 'LOG_SERVICE_IP' env var
|
||||||
|
const ip = process.env[`LOG_SERVICE_IP`];
|
||||||
|
if (ip === undefined) {
|
||||||
|
RemoteClientLogger.logWarning(`LOG_SERVICE_IP not set, skipping log push`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const url = `http://${ip}/api/log`;
|
||||||
|
RemoteClientLogger.log(`Pushing logs to ${url}`);
|
||||||
|
|
||||||
|
// logs to base64
|
||||||
|
logs = Buffer.from(logs).toString('base64');
|
||||||
|
const response = await CloudRunnerSystem.Run(`curl -X POST -d "${logs}" ${url}`, false, true);
|
||||||
|
RemoteClientLogger.log(`Pushed logs to ${url} ${response}`);
|
||||||
|
}
|
||||||
|
|
||||||
async listResources(): Promise<ProviderResource[]> {
|
async listResources(): Promise<ProviderResource[]> {
|
||||||
const pods = await this.kubeClient.listNamespacedPod(this.namespace);
|
const pods = await this.kubeClient.listNamespacedPod(this.namespace);
|
||||||
const serviceAccounts = await this.kubeClient.listNamespacedServiceAccount(this.namespace);
|
const serviceAccounts = await this.kubeClient.listNamespacedServiceAccount(this.namespace);
|
||||||
@ -115,9 +140,10 @@ class Kubernetes implements ProviderInterface {
|
|||||||
CloudRunnerLogger.log('Cloud Runner K8s workflow!');
|
CloudRunnerLogger.log('Cloud Runner K8s workflow!');
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
const id = BuildParameters.shouldUseRetainedWorkspaceMode(this.buildParameters)
|
const id =
|
||||||
? CloudRunner.lockedWorkspace
|
BuildParameters && BuildParameters.shouldUseRetainedWorkspaceMode(this.buildParameters)
|
||||||
: this.buildParameters.buildGuid;
|
? CloudRunner.lockedWorkspace
|
||||||
|
: this.buildParameters.buildGuid;
|
||||||
this.pvcName = `unity-builder-pvc-${id}`;
|
this.pvcName = `unity-builder-pvc-${id}`;
|
||||||
await KubernetesStorage.createPersistentVolumeClaim(
|
await KubernetesStorage.createPersistentVolumeClaim(
|
||||||
this.buildParameters,
|
this.buildParameters,
|
||||||
@ -137,10 +163,7 @@ class Kubernetes implements ProviderInterface {
|
|||||||
CloudRunnerLogger.log('Watching pod until running');
|
CloudRunnerLogger.log('Watching pod until running');
|
||||||
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
||||||
|
|
||||||
CloudRunnerLogger.log('Pod running, streaming logs');
|
CloudRunnerLogger.log('Pod is running');
|
||||||
CloudRunnerLogger.log(
|
|
||||||
`Starting logs follow for pod: ${this.podName} container: ${this.containerName} namespace: ${this.namespace} pvc: ${this.pvcName} ${CloudRunner.buildParameters.kubeVolumeSize}/${CloudRunner.buildParameters.containerCpu}/${CloudRunner.buildParameters.containerMemory}`,
|
|
||||||
);
|
|
||||||
output += await KubernetesTaskRunner.runTask(
|
output += await KubernetesTaskRunner.runTask(
|
||||||
this.kubeConfig,
|
this.kubeConfig,
|
||||||
this.kubeClient,
|
this.kubeClient,
|
||||||
@ -232,8 +255,12 @@ class Kubernetes implements ProviderInterface {
|
|||||||
this.jobName,
|
this.jobName,
|
||||||
k8s,
|
k8s,
|
||||||
this.containerName,
|
this.containerName,
|
||||||
|
this.ip,
|
||||||
);
|
);
|
||||||
await new Promise((promise) => setTimeout(promise, 15000));
|
await new Promise((promise) => setTimeout(promise, 15000));
|
||||||
|
|
||||||
|
// await KubernetesRole.createRole(this.serviceAccountName, this.namespace, this.rbacAuthorizationV1Api);
|
||||||
|
|
||||||
const result = await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
const result = await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||||
CloudRunnerLogger.log(`Build job created`);
|
CloudRunnerLogger.log(`Build job created`);
|
||||||
await new Promise((promise) => setTimeout(promise, 5000));
|
await new Promise((promise) => setTimeout(promise, 5000));
|
||||||
@ -257,6 +284,7 @@ class Kubernetes implements ProviderInterface {
|
|||||||
try {
|
try {
|
||||||
await this.kubeClientBatch.deleteNamespacedJob(this.jobName, this.namespace);
|
await this.kubeClientBatch.deleteNamespacedJob(this.jobName, this.namespace);
|
||||||
await this.kubeClient.deleteNamespacedPod(this.podName, this.namespace);
|
await this.kubeClient.deleteNamespacedPod(this.podName, this.namespace);
|
||||||
|
await KubernetesRole.deleteRole(this.serviceAccountName, this.namespace, this.rbacAuthorizationV1Api);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
CloudRunnerLogger.log(`Failed to cleanup`);
|
CloudRunnerLogger.log(`Failed to cleanup`);
|
||||||
if (error.response.body.reason !== `NotFound`) {
|
if (error.response.body.reason !== `NotFound`) {
|
||||||
@ -275,14 +303,13 @@ class Kubernetes implements ProviderInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async cleanupWorkflow(
|
async cleanupWorkflow(
|
||||||
buildGuid: string,
|
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
branchName: string,
|
branchName: string,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
defaultSecretsArray: { ParameterKey: string; EnvironmentVariable: string; ParameterValue: string }[],
|
||||||
) {
|
) {
|
||||||
if (BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
if (BuildParameters && BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CloudRunnerLogger.log(`deleting PVC`);
|
CloudRunnerLogger.log(`deleting PVC`);
|
||||||
|
@ -20,6 +20,7 @@ class KubernetesJobSpecFactory {
|
|||||||
jobName: string,
|
jobName: string,
|
||||||
k8s: any,
|
k8s: any,
|
||||||
containerName: string,
|
containerName: string,
|
||||||
|
ip: string = '',
|
||||||
) {
|
) {
|
||||||
const job = new k8s.V1Job();
|
const job = new k8s.V1Job();
|
||||||
job.apiVersion = 'batch/v1';
|
job.apiVersion = 'batch/v1';
|
||||||
@ -81,6 +82,7 @@ class KubernetesJobSpecFactory {
|
|||||||
|
|
||||||
return environmentVariable;
|
return environmentVariable;
|
||||||
}),
|
}),
|
||||||
|
{ name: 'LOG_SERVICE_IP', value: ip },
|
||||||
],
|
],
|
||||||
volumeMounts: [
|
volumeMounts: [
|
||||||
{
|
{
|
||||||
@ -92,9 +94,8 @@ class KubernetesJobSpecFactory {
|
|||||||
preStop: {
|
preStop: {
|
||||||
exec: {
|
exec: {
|
||||||
command: [
|
command: [
|
||||||
'bin/bash',
|
`wait 60s;
|
||||||
'-c',
|
cd /data/builder/action/steps;
|
||||||
`cd /data/builder/action/steps;
|
|
||||||
chmod +x /return_license.sh;
|
chmod +x /return_license.sh;
|
||||||
/return_license.sh;`,
|
/return_license.sh;`,
|
||||||
],
|
],
|
||||||
@ -108,6 +109,16 @@ class KubernetesJobSpecFactory {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (process.env['CLOUD_RUNNER_MINIKUBE']) {
|
||||||
|
job.spec.template.spec.volumes[0] = {
|
||||||
|
name: 'build-mount',
|
||||||
|
hostPath: {
|
||||||
|
path: `/data`,
|
||||||
|
type: `Directory`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
job.spec.template.spec.containers[0].resources.requests[`ephemeral-storage`] = '10Gi';
|
job.spec.template.spec.containers[0].resources.requests[`ephemeral-storage`] = '10Gi';
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
|
53
src/model/cloud-runner/providers/k8s/kubernetes-role.ts
Normal file
53
src/model/cloud-runner/providers/k8s/kubernetes-role.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { RbacAuthorizationV1Api } from '@kubernetes/client-node';
|
||||||
|
|
||||||
|
class KubernetesRole {
|
||||||
|
static async createRole(serviceAccountName: string, namespace: string, rbac: RbacAuthorizationV1Api) {
|
||||||
|
// create admin kubernetes role and role binding
|
||||||
|
const roleBinding = {
|
||||||
|
apiVersion: 'rbac.authorization.k8s.io/v1',
|
||||||
|
kind: 'RoleBinding',
|
||||||
|
metadata: {
|
||||||
|
name: `${serviceAccountName}-admin`,
|
||||||
|
namespace,
|
||||||
|
},
|
||||||
|
subjects: [
|
||||||
|
{
|
||||||
|
kind: 'ServiceAccount',
|
||||||
|
name: serviceAccountName,
|
||||||
|
namespace,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
roleRef: {
|
||||||
|
apiGroup: 'rbac.authorization.k8s.io',
|
||||||
|
kind: 'Role',
|
||||||
|
name: `${serviceAccountName}-admin`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const role = {
|
||||||
|
apiVersion: 'rbac.authorization.k8s.io/v1',
|
||||||
|
kind: 'Role',
|
||||||
|
metadata: {
|
||||||
|
name: `${serviceAccountName}-admin`,
|
||||||
|
namespace,
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
apiGroups: ['*'],
|
||||||
|
resources: ['*'],
|
||||||
|
verbs: ['*'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const roleBindingResponse = await rbac.createNamespacedRoleBinding(namespace, roleBinding);
|
||||||
|
const roleResponse = await rbac.createNamespacedRole(namespace, role);
|
||||||
|
|
||||||
|
return { roleBindingResponse, roleResponse };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async deleteRole(serviceAccountName: string, namespace: string, rbac: RbacAuthorizationV1Api) {
|
||||||
|
await rbac.deleteNamespacedRoleBinding(`${serviceAccountName}-admin`, namespace);
|
||||||
|
await rbac.deleteNamespacedRole(`${serviceAccountName}-admin`, namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export { KubernetesRole };
|
@ -9,7 +9,7 @@ class KubernetesServiceAccount {
|
|||||||
serviceAccount.metadata = {
|
serviceAccount.metadata = {
|
||||||
name: serviceAccountName,
|
name: serviceAccountName,
|
||||||
};
|
};
|
||||||
serviceAccount.automountServiceAccountToken = false;
|
serviceAccount.automountServiceAccountToken = true;
|
||||||
|
|
||||||
return kubeClient.createNamespacedServiceAccount(namespace, serviceAccount);
|
return kubeClient.createNamespacedServiceAccount(namespace, serviceAccount);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import KubernetesPods from './kubernetes-pods';
|
|||||||
import { FollowLogStreamService } from '../../services/core/follow-log-stream-service';
|
import { FollowLogStreamService } from '../../services/core/follow-log-stream-service';
|
||||||
|
|
||||||
class KubernetesTaskRunner {
|
class KubernetesTaskRunner {
|
||||||
static lastReceivedTimestamp: number = 0;
|
|
||||||
static readonly maxRetry: number = 3;
|
static readonly maxRetry: number = 3;
|
||||||
static lastReceivedMessage: string = ``;
|
static lastReceivedMessage: string = ``;
|
||||||
|
|
||||||
@ -22,38 +21,33 @@ class KubernetesTaskRunner {
|
|||||||
let output = '';
|
let output = '';
|
||||||
let shouldReadLogs = true;
|
let shouldReadLogs = true;
|
||||||
let shouldCleanup = true;
|
let shouldCleanup = true;
|
||||||
let sinceTime = ``;
|
|
||||||
let retriesAfterFinish = 0;
|
let retriesAfterFinish = 0;
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
const lastReceivedMessage =
|
|
||||||
KubernetesTaskRunner.lastReceivedTimestamp > 0
|
|
||||||
? `\nLast Log Message "${this.lastReceivedMessage}" ${this.lastReceivedTimestamp}`
|
|
||||||
: ``;
|
|
||||||
CloudRunnerLogger.log(
|
CloudRunnerLogger.log(
|
||||||
`Streaming logs from pod: ${podName} container: ${containerName} namespace: ${namespace} ${CloudRunner.buildParameters.kubeVolumeSize}/${CloudRunner.buildParameters.containerCpu}/${CloudRunner.buildParameters.containerMemory}\n${lastReceivedMessage}`,
|
`Streaming logs from pod: ${podName} container: ${containerName} namespace: ${namespace} ${CloudRunner.buildParameters.kubeVolumeSize}/${CloudRunner.buildParameters.containerCpu}/${CloudRunner.buildParameters.containerMemory}`,
|
||||||
);
|
);
|
||||||
if (KubernetesTaskRunner.lastReceivedTimestamp > 0) {
|
|
||||||
const currentDate = new Date(KubernetesTaskRunner.lastReceivedTimestamp);
|
|
||||||
const dateTimeIsoString = currentDate.toISOString();
|
|
||||||
sinceTime = ` --since-time="${dateTimeIsoString}"`;
|
|
||||||
}
|
|
||||||
let extraFlags = ``;
|
let extraFlags = ``;
|
||||||
extraFlags += (await KubernetesPods.IsPodRunning(podName, namespace, kubeClient))
|
extraFlags += (await KubernetesPods.IsPodRunning(podName, namespace, kubeClient))
|
||||||
? ` -f -c ${containerName}`
|
? ` -f -c ${containerName}`
|
||||||
: ` --previous`;
|
: ` --previous`;
|
||||||
let lastMessageSeenIncludedInChunk = false;
|
|
||||||
let lastMessageSeen = false;
|
|
||||||
|
|
||||||
let logs;
|
const callback = (outputChunk: string) => {
|
||||||
|
output += outputChunk;
|
||||||
|
|
||||||
|
// split output chunk and handle per line
|
||||||
|
for (const chunk of outputChunk.split(`\n`)) {
|
||||||
|
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
||||||
|
chunk,
|
||||||
|
shouldReadLogs,
|
||||||
|
shouldCleanup,
|
||||||
|
output,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
logs = await CloudRunnerSystem.Run(
|
await CloudRunnerSystem.Run(`kubectl logs ${podName}${extraFlags}`, false, true, callback);
|
||||||
`kubectl logs ${podName}${extraFlags} --timestamps${sinceTime}`,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
const continueStreaming = await KubernetesPods.IsPodRunning(podName, namespace, kubeClient);
|
const continueStreaming = await KubernetesPods.IsPodRunning(podName, namespace, kubeClient);
|
||||||
@ -68,34 +62,6 @@ class KubernetesTaskRunner {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const splitLogs = logs.split(`\n`);
|
|
||||||
for (const chunk of splitLogs) {
|
|
||||||
if (
|
|
||||||
chunk.replace(/\s/g, ``) === KubernetesTaskRunner.lastReceivedMessage.replace(/\s/g, ``) &&
|
|
||||||
KubernetesTaskRunner.lastReceivedMessage.replace(/\s/g, ``) !== ``
|
|
||||||
) {
|
|
||||||
CloudRunnerLogger.log(`Previous log message found ${chunk}`);
|
|
||||||
lastMessageSeenIncludedInChunk = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const chunk of splitLogs) {
|
|
||||||
const newDate = Date.parse(`${chunk.toString().split(`Z `)[0]}Z`);
|
|
||||||
if (chunk.replace(/\s/g, ``) === KubernetesTaskRunner.lastReceivedMessage.replace(/\s/g, ``)) {
|
|
||||||
lastMessageSeen = true;
|
|
||||||
}
|
|
||||||
if (lastMessageSeenIncludedInChunk && !lastMessageSeen) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const message = CloudRunner.buildParameters.cloudRunnerDebug ? chunk : chunk.split(`Z `)[1];
|
|
||||||
KubernetesTaskRunner.lastReceivedMessage = chunk;
|
|
||||||
KubernetesTaskRunner.lastReceivedTimestamp = newDate;
|
|
||||||
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
|
||||||
message,
|
|
||||||
shouldReadLogs,
|
|
||||||
shouldCleanup,
|
|
||||||
output,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if (FollowLogStreamService.DidReceiveEndOfTransmission) {
|
if (FollowLogStreamService.DidReceiveEndOfTransmission) {
|
||||||
CloudRunnerLogger.log('end of log stream');
|
CloudRunnerLogger.log('end of log stream');
|
||||||
break;
|
break;
|
||||||
@ -106,14 +72,14 @@ class KubernetesTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async watchUntilPodRunning(kubeClient: CoreV1Api, podName: string, namespace: string) {
|
static async watchUntilPodRunning(kubeClient: CoreV1Api, podName: string, namespace: string) {
|
||||||
let success: boolean = false;
|
let waitComplete: boolean = false;
|
||||||
let message = ``;
|
let message = ``;
|
||||||
CloudRunnerLogger.log(`Watching ${podName} ${namespace}`);
|
CloudRunnerLogger.log(`Watching ${podName} ${namespace}`);
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
async () => {
|
async () => {
|
||||||
const status = await kubeClient.readNamespacedPodStatus(podName, namespace);
|
const status = await kubeClient.readNamespacedPodStatus(podName, namespace);
|
||||||
const phase = status?.body.status?.phase;
|
const phase = status?.body.status?.phase;
|
||||||
success = phase === 'Running';
|
waitComplete = phase !== 'Pending';
|
||||||
message = `Phase:${status.body.status?.phase} \n Reason:${
|
message = `Phase:${status.body.status?.phase} \n Reason:${
|
||||||
status.body.status?.conditions?.[0].reason || ''
|
status.body.status?.conditions?.[0].reason || ''
|
||||||
} \n Message:${status.body.status?.conditions?.[0].message || ''}`;
|
} \n Message:${status.body.status?.conditions?.[0].message || ''}`;
|
||||||
@ -133,7 +99,7 @@ class KubernetesTaskRunner {
|
|||||||
// 4,
|
// 4,
|
||||||
// ),
|
// ),
|
||||||
// );
|
// );
|
||||||
if (success || phase !== 'Pending') return true;
|
if (waitComplete || phase !== 'Pending') return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -142,11 +108,11 @@ class KubernetesTaskRunner {
|
|||||||
intervalBetweenAttempts: 15000,
|
intervalBetweenAttempts: 15000,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!success) {
|
if (!waitComplete) {
|
||||||
CloudRunnerLogger.log(message);
|
CloudRunnerLogger.log(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return waitComplete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,8 +32,6 @@ class LocalCloudRunner implements ProviderInterface {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
cleanupWorkflow(
|
cleanupWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
buildGuid: string,
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
@ -6,8 +6,6 @@ import { ProviderWorkflow } from './provider-workflow';
|
|||||||
|
|
||||||
export interface ProviderInterface {
|
export interface ProviderInterface {
|
||||||
cleanupWorkflow(
|
cleanupWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
buildGuid: string,
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
@ -25,8 +25,6 @@ class TestCloudRunner implements ProviderInterface {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
cleanupWorkflow(
|
cleanupWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
buildGuid: string,
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
@ -80,7 +80,7 @@ export class Caching {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await CloudRunnerSystem.Run(
|
await CloudRunnerSystem.Run(
|
||||||
`tar -cf ${cacheArtifactName}.tar${compressionSuffix} ${path.basename(sourceFolder)}`,
|
`tar -cf ${cacheArtifactName}.tar${compressionSuffix} "${path.basename(sourceFolder)}"`,
|
||||||
);
|
);
|
||||||
await CloudRunnerSystem.Run(`du ${cacheArtifactName}.tar${compressionSuffix}`);
|
await CloudRunnerSystem.Run(`du ${cacheArtifactName}.tar${compressionSuffix}`);
|
||||||
assert(await fileExists(`${cacheArtifactName}.tar${compressionSuffix}`), 'cache archive exists');
|
assert(await fileExists(`${cacheArtifactName}.tar${compressionSuffix}`), 'cache archive exists');
|
||||||
|
@ -12,16 +12,83 @@ import { CloudRunnerSystem } from '../services/core/cloud-runner-system';
|
|||||||
import YAML from 'yaml';
|
import YAML from 'yaml';
|
||||||
import GitHub from '../../github';
|
import GitHub from '../../github';
|
||||||
import BuildParameters from '../../build-parameters';
|
import BuildParameters from '../../build-parameters';
|
||||||
|
import { Cli } from '../../cli/cli';
|
||||||
|
import CloudRunnerOptions from '../options/cloud-runner-options';
|
||||||
|
|
||||||
export class RemoteClient {
|
export class RemoteClient {
|
||||||
@CliFunction(`remote-cli-pre-build`, `sets up a repository, usually before a game-ci build`)
|
@CliFunction(`remote-cli-pre-build`, `sets up a repository, usually before a game-ci build`)
|
||||||
static async runRemoteClientJob() {
|
static async setupRemoteClient() {
|
||||||
CloudRunnerLogger.log(`bootstrap game ci cloud runner...`);
|
CloudRunnerLogger.log(`bootstrap game ci cloud runner...`);
|
||||||
if (!(await RemoteClient.handleRetainedWorkspace())) {
|
if (!(await RemoteClient.handleRetainedWorkspace())) {
|
||||||
await RemoteClient.bootstrapRepository();
|
await RemoteClient.bootstrapRepository();
|
||||||
}
|
}
|
||||||
|
await RemoteClient.replaceLargePackageReferencesWithSharedReferences();
|
||||||
await RemoteClient.runCustomHookFiles(`before-build`);
|
await RemoteClient.runCustomHookFiles(`before-build`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CliFunction('remote-cli-log-stream', `log stream from standard input`)
|
||||||
|
public static async remoteClientLogStream() {
|
||||||
|
const logFile = Cli.options!['logFile'];
|
||||||
|
process.stdin.resume();
|
||||||
|
process.stdin.setEncoding('utf8');
|
||||||
|
|
||||||
|
let lingeringLine = '';
|
||||||
|
|
||||||
|
process.stdin.on('data', (chunk) => {
|
||||||
|
const lines = chunk.toString().split('\n');
|
||||||
|
|
||||||
|
lines[0] = lingeringLine + lines[0];
|
||||||
|
lingeringLine = lines.pop() || '';
|
||||||
|
|
||||||
|
for (const element of lines) {
|
||||||
|
if (CloudRunnerOptions.providerStrategy !== 'k8s') {
|
||||||
|
CloudRunnerLogger.log(element);
|
||||||
|
} else {
|
||||||
|
fs.appendFileSync(logFile, element);
|
||||||
|
CloudRunnerLogger.log(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stdin.on('end', () => {
|
||||||
|
if (CloudRunnerOptions.providerStrategy !== 'k8s') {
|
||||||
|
CloudRunnerLogger.log(lingeringLine);
|
||||||
|
} else {
|
||||||
|
fs.appendFileSync(logFile, lingeringLine);
|
||||||
|
CloudRunnerLogger.log(lingeringLine);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@CliFunction(`remote-cli-post-build`, `runs a cloud runner build`)
|
||||||
|
public static async remoteClientPostBuild(): Promise<string> {
|
||||||
|
RemoteClientLogger.log(`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`);
|
||||||
|
|
||||||
|
// WIP - need to give the pod permissions to create config map
|
||||||
|
await RemoteClientLogger.handleLogManagementPostJob();
|
||||||
|
|
||||||
|
return new Promise((result) => result(``));
|
||||||
|
}
|
||||||
static async runCustomHookFiles(hookLifecycle: string) {
|
static async runCustomHookFiles(hookLifecycle: string) {
|
||||||
RemoteClientLogger.log(`RunCustomHookFiles: ${hookLifecycle}`);
|
RemoteClientLogger.log(`RunCustomHookFiles: ${hookLifecycle}`);
|
||||||
const gameCiCustomHooksPath = path.join(CloudRunnerFolders.repoPathAbsolute, `game-ci`, `hooks`);
|
const gameCiCustomHooksPath = path.join(CloudRunnerFolders.repoPathAbsolute, `game-ci`, `hooks`);
|
||||||
@ -47,7 +114,6 @@ export class RemoteClient {
|
|||||||
`mkdir -p ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.cacheFolderForCacheKeyFull)}`,
|
`mkdir -p ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.cacheFolderForCacheKeyFull)}`,
|
||||||
);
|
);
|
||||||
await RemoteClient.cloneRepoWithoutLFSFiles();
|
await RemoteClient.cloneRepoWithoutLFSFiles();
|
||||||
await RemoteClient.replaceLargePackageReferencesWithSharedReferences();
|
|
||||||
await RemoteClient.sizeOfFolder(
|
await RemoteClient.sizeOfFolder(
|
||||||
'repo before lfs cache pull',
|
'repo before lfs cache pull',
|
||||||
CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute),
|
CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute),
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
import CloudRunnerLogger from '../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../services/core/cloud-runner-logger';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import CloudRunner from '../cloud-runner';
|
||||||
|
import CloudRunnerOptions from '../options/cloud-runner-options';
|
||||||
|
|
||||||
export class RemoteClientLogger {
|
export class RemoteClientLogger {
|
||||||
|
private static get LogFilePath() {
|
||||||
|
return path.join(`/home`, `job-log.txt`);
|
||||||
|
}
|
||||||
|
|
||||||
public static log(message: string) {
|
public static log(message: string) {
|
||||||
CloudRunnerLogger.log(`[Client] ${message}`);
|
const finalMessage = `[Client] ${message}`;
|
||||||
|
this.appendToFile(finalMessage);
|
||||||
|
CloudRunnerLogger.log(finalMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static logCliError(message: string) {
|
public static logCliError(message: string) {
|
||||||
@ -16,4 +26,57 @@ export class RemoteClientLogger {
|
|||||||
public static logWarning(message: string) {
|
public static logWarning(message: string) {
|
||||||
CloudRunnerLogger.logWarning(message);
|
CloudRunnerLogger.logWarning(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static appendToFile(message: string) {
|
||||||
|
if (CloudRunner.isCloudRunnerEnvironment) {
|
||||||
|
fs.appendFileSync(RemoteClientLogger.LogFilePath, `${message}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async handleLogManagementPostJob() {
|
||||||
|
if (CloudRunnerOptions.providerStrategy !== 'k8s') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CloudRunnerLogger.log(`Collected Logs`);
|
||||||
|
|
||||||
|
// check for log file not existing
|
||||||
|
if (!fs.existsSync(RemoteClientLogger.LogFilePath)) {
|
||||||
|
CloudRunnerLogger.log(`Log file does not exist`);
|
||||||
|
|
||||||
|
// check if CloudRunner.isCloudRunnerEnvironment is true, log
|
||||||
|
if (!CloudRunner.isCloudRunnerEnvironment) {
|
||||||
|
CloudRunnerLogger.log(`Cloud Runner is not running in a cloud environment, not collecting logs`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CloudRunnerLogger.log(`Log file exist`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
||||||
|
|
||||||
|
// let hashedLogs = fs.readFileSync(RemoteClientLogger.LogFilePath).toString();
|
||||||
|
//
|
||||||
|
// hashedLogs = md5(hashedLogs);
|
||||||
|
//
|
||||||
|
// for (let index = 0; index < 3; index++) {
|
||||||
|
// CloudRunnerLogger.log(`LOGHASH: ${hashedLogs}`);
|
||||||
|
// const logs = fs.readFileSync(RemoteClientLogger.LogFilePath).toString();
|
||||||
|
// CloudRunnerLogger.log(`LOGS: ${Buffer.from(logs).toString('base64')}`);
|
||||||
|
// CloudRunnerLogger.log(
|
||||||
|
// `Game CI's "Cloud Runner System" will cancel the log when it has successfully received the log data to verify all logs have been received.`,
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // wait for 15 seconds to allow the log to be sent
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 15000));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
public static HandleLog(message: string): boolean {
|
||||||
|
if (RemoteClientLogger.value !== '') {
|
||||||
|
RemoteClientLogger.value += `\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteClientLogger.value += message;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static value: string = '';
|
||||||
}
|
}
|
||||||
|
24
src/model/cloud-runner/services/core/cloud-runner-result.ts
Normal file
24
src/model/cloud-runner/services/core/cloud-runner-result.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import BuildParameters from '../../../build-parameters';
|
||||||
|
|
||||||
|
class CloudRunnerResult {
|
||||||
|
public BuildParameters: BuildParameters;
|
||||||
|
public BuildResults: string;
|
||||||
|
public BuildSucceeded: boolean;
|
||||||
|
public BuildFinished: boolean;
|
||||||
|
public LibraryCacheUsed: boolean;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
buildParameters: BuildParameters,
|
||||||
|
buildResults: string,
|
||||||
|
buildSucceeded: boolean,
|
||||||
|
buildFinished: boolean,
|
||||||
|
libraryCacheUsed: boolean,
|
||||||
|
) {
|
||||||
|
this.BuildParameters = buildParameters;
|
||||||
|
this.BuildResults = buildResults;
|
||||||
|
this.BuildSucceeded = buildSucceeded;
|
||||||
|
this.BuildFinished = buildFinished;
|
||||||
|
this.LibraryCacheUsed = libraryCacheUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default CloudRunnerResult;
|
@ -16,7 +16,13 @@ export class CloudRunnerSystem {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Run(command: string, suppressError = false, suppressLogs = false) {
|
public static async Run(
|
||||||
|
command: string,
|
||||||
|
suppressError = false,
|
||||||
|
suppressLogs = false,
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
outputCallback?: (output: string) => void,
|
||||||
|
) {
|
||||||
for (const element of command.split(`\n`)) {
|
for (const element of command.split(`\n`)) {
|
||||||
if (!suppressLogs) {
|
if (!suppressLogs) {
|
||||||
RemoteClientLogger.log(element);
|
RemoteClientLogger.log(element);
|
||||||
@ -25,7 +31,7 @@ export class CloudRunnerSystem {
|
|||||||
|
|
||||||
return await new Promise<string>((promise, throwError) => {
|
return await new Promise<string>((promise, throwError) => {
|
||||||
let output = '';
|
let output = '';
|
||||||
const child = exec(command, (error, stdout, stderr) => {
|
const child = exec(command, { maxBuffer: 1024 * 10000 }, (error, stdout, stderr) => {
|
||||||
if (!suppressError && error) {
|
if (!suppressError && error) {
|
||||||
RemoteClientLogger.log(error.toString());
|
RemoteClientLogger.log(error.toString());
|
||||||
throwError(error);
|
throwError(error);
|
||||||
@ -38,6 +44,9 @@ export class CloudRunnerSystem {
|
|||||||
output += diagnosticOutput;
|
output += diagnosticOutput;
|
||||||
}
|
}
|
||||||
const outputChunk = `${stdout}`;
|
const outputChunk = `${stdout}`;
|
||||||
|
if (outputCallback) {
|
||||||
|
outputCallback(outputChunk);
|
||||||
|
}
|
||||||
output += outputChunk;
|
output += outputChunk;
|
||||||
});
|
});
|
||||||
child.on('close', (code) => {
|
child.on('close', (code) => {
|
||||||
|
@ -146,7 +146,8 @@ export class TaskParameterSerializer {
|
|||||||
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_SERIAL');
|
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_SERIAL');
|
||||||
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_EMAIL');
|
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_EMAIL');
|
||||||
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_PASSWORD');
|
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_PASSWORD');
|
||||||
array = TaskParameterSerializer.tryAddInput(array, 'UNITY_LICENSE');
|
|
||||||
|
// array = TaskParameterSerializer.tryAddInput(array, 'UNITY_LICENSE');
|
||||||
array = TaskParameterSerializer.tryAddInput(array, 'GIT_PRIVATE_TOKEN');
|
array = TaskParameterSerializer.tryAddInput(array, 'GIT_PRIVATE_TOKEN');
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import YAML from 'yaml';
|
import YAML from 'yaml';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
import * as core from '@actions/core';
|
|
||||||
import { CustomWorkflow } from '../../workflows/custom-workflow';
|
import { CustomWorkflow } from '../../workflows/custom-workflow';
|
||||||
import { RemoteClientLogger } from '../../remote-client/remote-client-logger';
|
import { RemoteClientLogger } from '../../remote-client/remote-client-logger';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
@ -237,13 +236,11 @@ export class ContainerHookService {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (steps.length > 0) {
|
if (steps.length > 0) {
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('post build steps');
|
|
||||||
output += await CustomWorkflow.runContainerJob(
|
output += await CustomWorkflow.runContainerJob(
|
||||||
steps,
|
steps,
|
||||||
cloudRunnerStepState.environment,
|
cloudRunnerStepState.environment,
|
||||||
cloudRunnerStepState.secrets,
|
cloudRunnerStepState.secrets,
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -256,13 +253,11 @@ export class ContainerHookService {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (steps.length > 0) {
|
if (steps.length > 0) {
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('pre build steps');
|
|
||||||
output += await CustomWorkflow.runContainerJob(
|
output += await CustomWorkflow.runContainerJob(
|
||||||
steps,
|
steps,
|
||||||
cloudRunnerStepState.environment,
|
cloudRunnerStepState.environment,
|
||||||
cloudRunnerStepState.secrets,
|
cloudRunnerStepState.secrets,
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -24,11 +24,17 @@ describe('Cloud Runner Async Workflows', () => {
|
|||||||
unityVersion: UnityVersioning.read('test-project'),
|
unityVersion: UnityVersioning.read('test-project'),
|
||||||
asyncCloudRunner: `true`,
|
asyncCloudRunner: `true`,
|
||||||
githubChecks: `true`,
|
githubChecks: `true`,
|
||||||
|
providerStrategy: 'k8s',
|
||||||
|
buildPlatform: 'linux',
|
||||||
|
targetPlatform: 'StandaloneLinux64',
|
||||||
});
|
});
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
|
|
||||||
// Run the job
|
// Run the job
|
||||||
await CloudRunner.run(buildParameter, baseImage.toString());
|
await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
|
|
||||||
|
// wait for 15 seconds
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000 * 60 * 12));
|
||||||
}, 1_000_000_000);
|
}, 1_000_000_000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,7 @@ describe('Cloud Runner Sync Environments', () => {
|
|||||||
versioning: 'None',
|
versioning: 'None',
|
||||||
projectPath: 'test-project',
|
projectPath: 'test-project',
|
||||||
unityVersion: UnityVersioning.read('test-project'),
|
unityVersion: UnityVersioning.read('test-project'),
|
||||||
|
targetPlatform: 'StandaloneWindows64',
|
||||||
customJob: `
|
customJob: `
|
||||||
- name: 'step 1'
|
- name: 'step 1'
|
||||||
image: 'ubuntu'
|
image: 'ubuntu'
|
||||||
@ -44,9 +45,12 @@ describe('Cloud Runner Sync Environments', () => {
|
|||||||
`,
|
`,
|
||||||
});
|
});
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
|
if (baseImage.toString().includes('undefined')) {
|
||||||
|
throw new Error(`Base image is undefined`);
|
||||||
|
}
|
||||||
|
|
||||||
// Run the job
|
// Run the job
|
||||||
const file = await CloudRunner.run(buildParameter, baseImage.toString());
|
const file = (await CloudRunner.run(buildParameter, baseImage.toString())).BuildResults;
|
||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
// expect(file).toContain(JSON.stringify(buildParameter));
|
// expect(file).toContain(JSON.stringify(buildParameter));
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
import { BuildParameters } from '../..';
|
||||||
|
import CloudRunner from '../cloud-runner';
|
||||||
|
import UnityVersioning from '../../unity-versioning';
|
||||||
|
import { Cli } from '../../cli/cli';
|
||||||
|
import CloudRunnerOptions from '../options/cloud-runner-options';
|
||||||
|
import setups from './cloud-runner-suite.test';
|
||||||
|
import { OptionValues } from 'commander';
|
||||||
|
import GitHub from '../../github';
|
||||||
|
export const TIMEOUT_INFINITE = 1e9;
|
||||||
|
async function CreateParameters(overrides: OptionValues | undefined) {
|
||||||
|
if (overrides) Cli.options = overrides;
|
||||||
|
|
||||||
|
return BuildParameters.create();
|
||||||
|
}
|
||||||
|
describe('Cloud Runner Github Checks', () => {
|
||||||
|
setups();
|
||||||
|
it('Responds', () => {});
|
||||||
|
|
||||||
|
if (CloudRunnerOptions.cloudRunnerDebug) {
|
||||||
|
it(
|
||||||
|
'Check Handling Direct',
|
||||||
|
async () => {
|
||||||
|
// Setup parameters
|
||||||
|
const buildParameter = await CreateParameters({
|
||||||
|
versioning: 'None',
|
||||||
|
projectPath: 'test-project',
|
||||||
|
unityVersion: UnityVersioning.read('test-project'),
|
||||||
|
asyncCloudRunner: `true`,
|
||||||
|
githubChecks: `true`,
|
||||||
|
});
|
||||||
|
await CloudRunner.setup(buildParameter);
|
||||||
|
CloudRunner.buildParameters.githubCheckId = await GitHub.createGitHubCheck(`direct create`);
|
||||||
|
await GitHub.updateGitHubCheck(`1 ${new Date().toISOString()}`, `direct`);
|
||||||
|
await GitHub.updateGitHubCheck(`2 ${new Date().toISOString()}`, `direct`, `success`, `completed`);
|
||||||
|
},
|
||||||
|
TIMEOUT_INFINITE,
|
||||||
|
);
|
||||||
|
it(
|
||||||
|
'Check Handling Via Async Workflow',
|
||||||
|
async () => {
|
||||||
|
// Setup parameters
|
||||||
|
const buildParameter = await CreateParameters({
|
||||||
|
versioning: 'None',
|
||||||
|
projectPath: 'test-project',
|
||||||
|
unityVersion: UnityVersioning.read('test-project'),
|
||||||
|
asyncCloudRunner: `true`,
|
||||||
|
githubChecks: `true`,
|
||||||
|
});
|
||||||
|
GitHub.forceAsyncTest = true;
|
||||||
|
await CloudRunner.setup(buildParameter);
|
||||||
|
CloudRunner.buildParameters.githubCheckId = await GitHub.createGitHubCheck(`async create`);
|
||||||
|
await GitHub.updateGitHubCheck(`1 ${new Date().toISOString()}`, `async`);
|
||||||
|
await GitHub.updateGitHubCheck(`2 ${new Date().toISOString()}`, `async`, `success`, `completed`);
|
||||||
|
GitHub.forceAsyncTest = false;
|
||||||
|
},
|
||||||
|
TIMEOUT_INFINITE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
@ -30,6 +30,7 @@ commands: echo "test"`;
|
|||||||
projectPath: 'test-project',
|
projectPath: 'test-project',
|
||||||
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||||
targetPlatform: 'StandaloneLinux64',
|
targetPlatform: 'StandaloneLinux64',
|
||||||
|
image: 'ubuntu',
|
||||||
cacheKey: `test-case-${uuidv4()}`,
|
cacheKey: `test-case-${uuidv4()}`,
|
||||||
};
|
};
|
||||||
CloudRunner.setup(await CreateParameters(overrides));
|
CloudRunner.setup(await CreateParameters(overrides));
|
||||||
@ -51,6 +52,7 @@ commands: echo "test"`;
|
|||||||
it('Should be 1 before and 1 after hook', async () => {
|
it('Should be 1 before and 1 after hook', async () => {
|
||||||
const overrides = {
|
const overrides = {
|
||||||
versioning: 'None',
|
versioning: 'None',
|
||||||
|
image: 'ubuntu',
|
||||||
projectPath: 'test-project',
|
projectPath: 'test-project',
|
||||||
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||||
targetPlatform: 'StandaloneLinux64',
|
targetPlatform: 'StandaloneLinux64',
|
||||||
@ -72,6 +74,7 @@ commands: echo "test"`;
|
|||||||
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||||
targetPlatform: 'StandaloneLinux64',
|
targetPlatform: 'StandaloneLinux64',
|
||||||
cacheKey: `test-case-${uuidv4()}`,
|
cacheKey: `test-case-${uuidv4()}`,
|
||||||
|
image: 'ubuntu',
|
||||||
containerHookFiles: `my-test-step-pre-build,my-test-step-post-build`,
|
containerHookFiles: `my-test-step-pre-build,my-test-step-post-build`,
|
||||||
commandHookFiles: `my-test-hook-pre-build,my-test-hook-post-build`,
|
commandHookFiles: `my-test-hook-pre-build,my-test-hook-post-build`,
|
||||||
};
|
};
|
||||||
@ -94,7 +97,8 @@ commands: echo "test"`;
|
|||||||
};
|
};
|
||||||
const buildParameter2 = await CreateParameters(overrides);
|
const buildParameter2 = await CreateParameters(overrides);
|
||||||
const baseImage2 = new ImageTag(buildParameter2);
|
const baseImage2 = new ImageTag(buildParameter2);
|
||||||
const results2 = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
||||||
|
const results2 = results2Object.BuildResults;
|
||||||
CloudRunnerLogger.log(`run 2 succeeded`);
|
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||||
|
|
||||||
const buildContainsBuildSucceeded = results2.includes('Build succeeded');
|
const buildContainsBuildSucceeded = results2.includes('Build succeeded');
|
||||||
|
51
src/model/cloud-runner/tests/cloud-runner-image.test.ts
Normal file
51
src/model/cloud-runner/tests/cloud-runner-image.test.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { BuildParameters, ImageTag } from '../..';
|
||||||
|
import UnityVersioning from '../../unity-versioning';
|
||||||
|
import { Cli } from '../../cli/cli';
|
||||||
|
import GitHub from '../../github';
|
||||||
|
import setups from './cloud-runner-suite.test';
|
||||||
|
|
||||||
|
async function CreateParameters(overrides: any) {
|
||||||
|
if (overrides) {
|
||||||
|
Cli.options = overrides;
|
||||||
|
}
|
||||||
|
const originalValue = GitHub.githubInputEnabled;
|
||||||
|
GitHub.githubInputEnabled = false;
|
||||||
|
const results = await BuildParameters.create();
|
||||||
|
GitHub.githubInputEnabled = originalValue;
|
||||||
|
delete Cli.options;
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Cloud Runner Image', () => {
|
||||||
|
setups();
|
||||||
|
const testSecretName = 'testSecretName';
|
||||||
|
const testSecretValue = 'testSecretValue';
|
||||||
|
it('Can create valid image from normal config', async () => {
|
||||||
|
// Setup parameters
|
||||||
|
const buildParameter = await CreateParameters({
|
||||||
|
versioning: 'None',
|
||||||
|
projectPath: 'test-project',
|
||||||
|
unityVersion: UnityVersioning.read('test-project'),
|
||||||
|
targetPlatform: 'StandaloneWindows64',
|
||||||
|
customJob: `
|
||||||
|
- name: 'step 1'
|
||||||
|
image: 'ubuntu'
|
||||||
|
commands: 'printenv'
|
||||||
|
secrets:
|
||||||
|
- name: '${testSecretName}'
|
||||||
|
value: '${testSecretValue}'
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
const baseImage = new ImageTag(buildParameter);
|
||||||
|
if (buildParameter.targetPlatform === undefined) {
|
||||||
|
throw new Error(`target platform includes undefined`);
|
||||||
|
}
|
||||||
|
if (baseImage.toString().includes('undefined')) {
|
||||||
|
throw new Error(`Base image ${baseImage.toString()} includes undefined`);
|
||||||
|
}
|
||||||
|
if (baseImage.toString().includes('NaN')) {
|
||||||
|
throw new Error(`Base image ${baseImage.toString()} includes nan`);
|
||||||
|
}
|
||||||
|
}, 1_000_000_000);
|
||||||
|
});
|
@ -32,7 +32,8 @@ describe('Cloud Runner pre-built S3 steps', () => {
|
|||||||
};
|
};
|
||||||
const buildParameter2 = await CreateParameters(overrides);
|
const buildParameter2 = await CreateParameters(overrides);
|
||||||
const baseImage2 = new ImageTag(buildParameter2);
|
const baseImage2 = new ImageTag(buildParameter2);
|
||||||
const results2 = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
||||||
|
const results2 = results2Object.BuildResults;
|
||||||
CloudRunnerLogger.log(`run 2 succeeded`);
|
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||||
|
|
||||||
const build2ContainsBuildSucceeded = results2.includes('Build succeeded');
|
const build2ContainsBuildSucceeded = results2.includes('Build succeeded');
|
||||||
|
@ -24,11 +24,13 @@ describe('Cloud Runner Caching', () => {
|
|||||||
it('Run one build it should not use cache, run subsequent build which should use cache', async () => {
|
it('Run one build it should not use cache, run subsequent build which should use cache', async () => {
|
||||||
const overrides = {
|
const overrides = {
|
||||||
versioning: 'None',
|
versioning: 'None',
|
||||||
|
image: 'ubuntu',
|
||||||
projectPath: 'test-project',
|
projectPath: 'test-project',
|
||||||
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||||
targetPlatform: 'StandaloneLinux64',
|
targetPlatform: 'StandaloneLinux64',
|
||||||
cacheKey: `test-case-${uuidv4()}`,
|
cacheKey: `test-case-${uuidv4()}`,
|
||||||
containerHookFiles: `debug-cache`,
|
containerHookFiles: `debug-cache`,
|
||||||
|
cloudRunnerBranch: `cloud-runner-develop`,
|
||||||
};
|
};
|
||||||
if (CloudRunnerOptions.providerStrategy === `k8s`) {
|
if (CloudRunnerOptions.providerStrategy === `k8s`) {
|
||||||
overrides.containerHookFiles += `,aws-s3-pull-cache,aws-s3-upload-cache`;
|
overrides.containerHookFiles += `,aws-s3-pull-cache,aws-s3-upload-cache`;
|
||||||
@ -37,7 +39,8 @@ describe('Cloud Runner Caching', () => {
|
|||||||
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
||||||
|
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
const results = await CloudRunner.run(buildParameter, baseImage.toString());
|
const resultsObject = await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
|
const results = resultsObject.BuildResults;
|
||||||
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
||||||
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
||||||
const buildSucceededString = 'Build succeeded';
|
const buildSucceededString = 'Build succeeded';
|
||||||
@ -63,12 +66,12 @@ describe('Cloud Runner Caching', () => {
|
|||||||
|
|
||||||
buildParameter2.cacheKey = buildParameter.cacheKey;
|
buildParameter2.cacheKey = buildParameter.cacheKey;
|
||||||
const baseImage2 = new ImageTag(buildParameter2);
|
const baseImage2 = new ImageTag(buildParameter2);
|
||||||
const results2 = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
||||||
|
const results2 = results2Object.BuildResults;
|
||||||
CloudRunnerLogger.log(`run 2 succeeded`);
|
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||||
|
|
||||||
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
||||||
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
||||||
const build2NotContainsNoLibraryMessage = !results2.includes(libraryString);
|
|
||||||
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
||||||
'There is 0 files/dir in the cache pulled contents for Library',
|
'There is 0 files/dir in the cache pulled contents for Library',
|
||||||
);
|
);
|
||||||
@ -77,10 +80,13 @@ describe('Cloud Runner Caching', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(build2ContainsCacheKey).toBeTruthy();
|
expect(build2ContainsCacheKey).toBeTruthy();
|
||||||
|
expect(results2).toContain('Activation successful');
|
||||||
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
||||||
|
expect(results2).toContain(buildSucceededString);
|
||||||
|
const splitResults = results2.split('Activation successful');
|
||||||
|
expect(splitResults[splitResults.length - 1]).not.toContain(libraryString);
|
||||||
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
||||||
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
||||||
expect(build2NotContainsNoLibraryMessage).toBeTruthy();
|
|
||||||
}, 1_000_000_000);
|
}, 1_000_000_000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -29,7 +29,8 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||||||
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
||||||
|
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
const results = await CloudRunner.run(buildParameter, baseImage.toString());
|
const resultsObject = await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
|
const results = resultsObject.BuildResults;
|
||||||
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
||||||
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
||||||
const buildSucceededString = 'Build succeeded';
|
const buildSucceededString = 'Build succeeded';
|
||||||
@ -51,7 +52,8 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||||||
|
|
||||||
buildParameter2.cacheKey = buildParameter.cacheKey;
|
buildParameter2.cacheKey = buildParameter.cacheKey;
|
||||||
const baseImage2 = new ImageTag(buildParameter2);
|
const baseImage2 = new ImageTag(buildParameter2);
|
||||||
const results2 = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
const results2Object = await CloudRunner.run(buildParameter2, baseImage2.toString());
|
||||||
|
const results2 = results2Object.BuildResults;
|
||||||
CloudRunnerLogger.log(`run 2 succeeded`);
|
CloudRunnerLogger.log(`run 2 succeeded`);
|
||||||
|
|
||||||
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
const build2ContainsCacheKey = results2.includes(buildParameter.cacheKey);
|
||||||
@ -59,7 +61,6 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||||||
const build2ContainsRetainedWorkspacePhrase = results2.includes(`Retained Workspace:`);
|
const build2ContainsRetainedWorkspacePhrase = results2.includes(`Retained Workspace:`);
|
||||||
const build2ContainsWorkspaceExistsAlreadyPhrase = results2.includes(`Retained Workspace Already Exists!`);
|
const build2ContainsWorkspaceExistsAlreadyPhrase = results2.includes(`Retained Workspace Already Exists!`);
|
||||||
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
const build2ContainsBuildSucceeded = results2.includes(buildSucceededString);
|
||||||
const build2NotContainsNoLibraryMessage = !results2.includes(libraryString);
|
|
||||||
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
const build2NotContainsZeroLibraryCacheFilesMessage = !results2.includes(
|
||||||
'There is 0 files/dir in the cache pulled contents for Library',
|
'There is 0 files/dir in the cache pulled contents for Library',
|
||||||
);
|
);
|
||||||
@ -74,7 +75,8 @@ describe('Cloud Runner Retain Workspace', () => {
|
|||||||
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
expect(build2ContainsBuildSucceeded).toBeTruthy();
|
||||||
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
expect(build2NotContainsZeroLibraryCacheFilesMessage).toBeTruthy();
|
||||||
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
expect(build2NotContainsZeroLFSCacheFilesMessage).toBeTruthy();
|
||||||
expect(build2NotContainsNoLibraryMessage).toBeTruthy();
|
const splitResults = results2.split('Activation successful');
|
||||||
|
expect(splitResults[splitResults.length - 1]).not.toContain(libraryString);
|
||||||
}, 1_000_000_000);
|
}, 1_000_000_000);
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await SharedWorkspaceLocking.CleanupWorkspace(CloudRunner.lockedWorkspace || ``, CloudRunner.buildParameters);
|
await SharedWorkspaceLocking.CleanupWorkspace(CloudRunner.lockedWorkspace || ``, CloudRunner.buildParameters);
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
import CloudRunner from '../../cloud-runner';
|
||||||
|
import UnityVersioning from '../../../unity-versioning';
|
||||||
|
import { Cli } from '../../../cli/cli';
|
||||||
|
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
||||||
|
import setups from '../cloud-runner-suite.test';
|
||||||
|
import BuildParameters from '../../../build-parameters';
|
||||||
|
import ImageTag from '../../../image-tag';
|
||||||
|
|
||||||
|
async function CreateParameters(overrides: any) {
|
||||||
|
if (overrides) {
|
||||||
|
Cli.options = overrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await BuildParameters.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Cloud Runner Kubernetes', () => {
|
||||||
|
it('Responds', () => {});
|
||||||
|
setups();
|
||||||
|
|
||||||
|
if (CloudRunnerOptions.cloudRunnerDebug) {
|
||||||
|
it('Run one build it using K8s without error', async () => {
|
||||||
|
if (CloudRunnerOptions.providerStrategy !== `k8s`) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process.env.USE_IL2CPP = 'false';
|
||||||
|
const overrides = {
|
||||||
|
versioning: 'None',
|
||||||
|
projectPath: 'test-project',
|
||||||
|
unityVersion: UnityVersioning.determineUnityVersion('test-project', UnityVersioning.read('test-project')),
|
||||||
|
targetPlatform: 'StandaloneLinux64',
|
||||||
|
cacheKey: `test-case-${uuidv4()}`,
|
||||||
|
providerStrategy: 'k8s',
|
||||||
|
buildPlatform: 'linux',
|
||||||
|
};
|
||||||
|
const buildParameter = await CreateParameters(overrides);
|
||||||
|
expect(buildParameter.projectPath).toEqual(overrides.projectPath);
|
||||||
|
|
||||||
|
const baseImage = new ImageTag(buildParameter);
|
||||||
|
const resultsObject = await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
|
const results = resultsObject.BuildResults;
|
||||||
|
const libraryString = 'Rebuilding Library because the asset database could not be found!';
|
||||||
|
const cachePushFail = 'Did not push source folder to cache because it was empty Library';
|
||||||
|
const buildSucceededString = 'Build succeeded';
|
||||||
|
|
||||||
|
expect(results).toContain('Collected Logs');
|
||||||
|
expect(results).toContain(libraryString);
|
||||||
|
expect(results).toContain(buildSucceededString);
|
||||||
|
expect(results).not.toContain(cachePushFail);
|
||||||
|
|
||||||
|
CloudRunnerLogger.log(`run 1 succeeded`);
|
||||||
|
}, 1_000_000_000);
|
||||||
|
}
|
||||||
|
});
|
@ -41,6 +41,11 @@ node /builder/dist/index.js -m async-workflow`,
|
|||||||
[
|
[
|
||||||
...secrets,
|
...secrets,
|
||||||
...[
|
...[
|
||||||
|
{
|
||||||
|
ParameterKey: `GITHUB_TOKEN`,
|
||||||
|
EnvironmentVariable: `GITHUB_TOKEN`,
|
||||||
|
ParameterValue: process.env.GITHUB_TOKEN || ``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ParameterKey: `AWS_ACCESS_KEY_ID`,
|
ParameterKey: `AWS_ACCESS_KEY_ID`,
|
||||||
EnvironmentVariable: `AWS_ACCESS_KEY_ID`,
|
EnvironmentVariable: `AWS_ACCESS_KEY_ID`,
|
||||||
|
@ -2,7 +2,6 @@ import CloudRunnerLogger from '../services/core/cloud-runner-logger';
|
|||||||
import { CloudRunnerFolders } from '../options/cloud-runner-folders';
|
import { CloudRunnerFolders } from '../options/cloud-runner-folders';
|
||||||
import { CloudRunnerStepParameters } from '../options/cloud-runner-step-parameters';
|
import { CloudRunnerStepParameters } from '../options/cloud-runner-step-parameters';
|
||||||
import { WorkflowInterface } from './workflow-interface';
|
import { WorkflowInterface } from './workflow-interface';
|
||||||
import * as core from '@actions/core';
|
|
||||||
import { CommandHookService } from '../services/hooks/command-hook-service';
|
import { CommandHookService } from '../services/hooks/command-hook-service';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import CloudRunner from '../cloud-runner';
|
import CloudRunner from '../cloud-runner';
|
||||||
@ -21,8 +20,6 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
|
|||||||
|
|
||||||
output += await ContainerHookService.RunPreBuildSteps(cloudRunnerStepState);
|
output += await ContainerHookService.RunPreBuildSteps(cloudRunnerStepState);
|
||||||
CloudRunnerLogger.logWithTime('Configurable pre build step(s) time');
|
CloudRunnerLogger.logWithTime('Configurable pre build step(s) time');
|
||||||
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('build');
|
|
||||||
CloudRunnerLogger.log(baseImage);
|
CloudRunnerLogger.log(baseImage);
|
||||||
CloudRunnerLogger.logLine(` `);
|
CloudRunnerLogger.logLine(` `);
|
||||||
CloudRunnerLogger.logLine('Starting build automation job');
|
CloudRunnerLogger.logLine('Starting build automation job');
|
||||||
@ -36,7 +33,6 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
|
|||||||
cloudRunnerStepState.environment,
|
cloudRunnerStepState.environment,
|
||||||
cloudRunnerStepState.secrets,
|
cloudRunnerStepState.secrets,
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
|
||||||
CloudRunnerLogger.logWithTime('Build time');
|
CloudRunnerLogger.logWithTime('Build time');
|
||||||
|
|
||||||
output += await ContainerHookService.RunPostBuildSteps(cloudRunnerStepState);
|
output += await ContainerHookService.RunPostBuildSteps(cloudRunnerStepState);
|
||||||
@ -58,11 +54,14 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
|
|||||||
path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', `index.js`),
|
path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', `index.js`),
|
||||||
);
|
);
|
||||||
|
|
||||||
return `apt-get update > /dev/null
|
return `echo "cloud runner build workflow starting"
|
||||||
|
apt-get update > /dev/null
|
||||||
apt-get install -y curl tar tree npm git-lfs jq git > /dev/null
|
apt-get install -y curl tar tree npm git-lfs jq git > /dev/null
|
||||||
npm i -g n > /dev/null
|
|
||||||
n 16.15.1 > /dev/null
|
|
||||||
npm --version
|
npm --version
|
||||||
|
npm i -g n > /dev/null
|
||||||
|
npm i -g semver > /dev/null
|
||||||
|
npm install --global yarn > /dev/null
|
||||||
|
n 20.8.0
|
||||||
node --version
|
node --version
|
||||||
${setupHooks.filter((x) => x.hook.includes(`before`)).map((x) => x.commands) || ' '}
|
${setupHooks.filter((x) => x.hook.includes(`before`)).map((x) => x.commands) || ' '}
|
||||||
export GITHUB_WORKSPACE="${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute)}"
|
export GITHUB_WORKSPACE="${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.repoPathAbsolute)}"
|
||||||
@ -91,6 +90,7 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
|
|||||||
|
|
||||||
return `export GIT_DISCOVERY_ACROSS_FILESYSTEM=1
|
return `export GIT_DISCOVERY_ACROSS_FILESYSTEM=1
|
||||||
${cloneBuilderCommands}
|
${cloneBuilderCommands}
|
||||||
|
echo "log start" >> /home/job-log.txt
|
||||||
node ${builderPath} -m remote-cli-pre-build`;
|
node ${builderPath} -m remote-cli-pre-build`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ node ${builderPath} -m remote-cli-pre-build`;
|
|||||||
const distFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist');
|
const distFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist');
|
||||||
const ubuntuPlatformsFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', 'platforms', 'ubuntu');
|
const ubuntuPlatformsFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', 'platforms', 'ubuntu');
|
||||||
|
|
||||||
return `echo "game ci cloud runner initalized"
|
return `
|
||||||
mkdir -p ${`${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.projectBuildFolderAbsolute)}/build`}
|
mkdir -p ${`${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.projectBuildFolderAbsolute)}/build`}
|
||||||
cd ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.projectPathAbsolute)}
|
cd ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.projectPathAbsolute)}
|
||||||
cp -r "${CloudRunnerFolders.ToLinuxFolder(path.join(distFolder, 'default-build-script'))}" "/UnityBuilderAction"
|
cp -r "${CloudRunnerFolders.ToLinuxFolder(path.join(distFolder, 'default-build-script'))}" "/UnityBuilderAction"
|
||||||
@ -107,9 +107,8 @@ node ${builderPath} -m remote-cli-pre-build`;
|
|||||||
chmod -R +x "/entrypoint.sh"
|
chmod -R +x "/entrypoint.sh"
|
||||||
chmod -R +x "/steps"
|
chmod -R +x "/steps"
|
||||||
echo "game ci start"
|
echo "game ci start"
|
||||||
/entrypoint.sh
|
echo "game ci start" >> /home/job-log.txt
|
||||||
echo "game ci caching results"
|
/entrypoint.sh | node ${builderPath} -m remote-cli-log-stream --logFile /home/job-log.txt
|
||||||
chmod +x ${builderPath}
|
|
||||||
node ${builderPath} -m remote-cli-post-build`;
|
node ${builderPath} -m remote-cli-post-build`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { execWithErrorCheck } from './exec-with-error-check';
|
|
||||||
import ImageEnvironmentFactory from './image-environment-factory';
|
import ImageEnvironmentFactory from './image-environment-factory';
|
||||||
import { existsSync, mkdirSync } from 'node:fs';
|
import { existsSync, mkdirSync } from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { ExecOptions } from '@actions/exec';
|
import { ExecOptions, exec } from '@actions/exec';
|
||||||
import { DockerParameters, StringKeyValuePair } from './shared-types';
|
import { DockerParameters, StringKeyValuePair } from './shared-types';
|
||||||
|
|
||||||
class Docker {
|
class Docker {
|
||||||
@ -12,11 +11,9 @@ class Docker {
|
|||||||
silent: boolean = false,
|
silent: boolean = false,
|
||||||
overrideCommands: string = '',
|
overrideCommands: string = '',
|
||||||
additionalVariables: StringKeyValuePair[] = [],
|
additionalVariables: StringKeyValuePair[] = [],
|
||||||
// eslint-disable-next-line unicorn/no-useless-undefined
|
options: ExecOptions = {},
|
||||||
options: ExecOptions | undefined = undefined,
|
|
||||||
entrypointBash: boolean = false,
|
entrypointBash: boolean = false,
|
||||||
errorWhenMissingUnityBuildResults: boolean = true,
|
): Promise<number> {
|
||||||
) {
|
|
||||||
let runCommand = '';
|
let runCommand = '';
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'linux':
|
case 'linux':
|
||||||
@ -24,13 +21,15 @@ class Docker {
|
|||||||
break;
|
break;
|
||||||
case 'win32':
|
case 'win32':
|
||||||
runCommand = this.getWindowsCommand(image, parameters);
|
runCommand = this.getWindowsCommand(image, parameters);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Operation system, ${process.platform}, is not supported yet.`);
|
||||||
}
|
}
|
||||||
if (options) {
|
|
||||||
options.silent = silent;
|
options.silent = silent;
|
||||||
await execWithErrorCheck(runCommand, undefined, options, errorWhenMissingUnityBuildResults);
|
options.ignoreReturnCode = true;
|
||||||
} else {
|
|
||||||
await execWithErrorCheck(runCommand, undefined, { silent }, errorWhenMissingUnityBuildResults);
|
return await exec(runCommand, undefined, options);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getLinuxCommand(
|
static getLinuxCommand(
|
||||||
@ -48,6 +47,8 @@ class Docker {
|
|||||||
sshPublicKeysDirectoryPath,
|
sshPublicKeysDirectoryPath,
|
||||||
gitPrivateToken,
|
gitPrivateToken,
|
||||||
dockerWorkspacePath,
|
dockerWorkspacePath,
|
||||||
|
dockerCpuLimit,
|
||||||
|
dockerMemoryLimit,
|
||||||
} = parameters;
|
} = parameters;
|
||||||
|
|
||||||
const githubHome = path.join(runnerTempPath, '_github_home');
|
const githubHome = path.join(runnerTempPath, '_github_home');
|
||||||
@ -60,7 +61,6 @@ class Docker {
|
|||||||
--workdir ${dockerWorkspacePath} \
|
--workdir ${dockerWorkspacePath} \
|
||||||
--rm \
|
--rm \
|
||||||
${ImageEnvironmentFactory.getEnvVarString(parameters, additionalVariables)} \
|
${ImageEnvironmentFactory.getEnvVarString(parameters, additionalVariables)} \
|
||||||
--env UNITY_SERIAL \
|
|
||||||
--env GITHUB_WORKSPACE=${dockerWorkspacePath} \
|
--env GITHUB_WORKSPACE=${dockerWorkspacePath} \
|
||||||
--env GIT_CONFIG_EXTENSIONS \
|
--env GIT_CONFIG_EXTENSIONS \
|
||||||
${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \
|
${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \
|
||||||
@ -72,6 +72,9 @@ class Docker {
|
|||||||
--volume "${actionFolder}/platforms/ubuntu/steps:/steps:z" \
|
--volume "${actionFolder}/platforms/ubuntu/steps:/steps:z" \
|
||||||
--volume "${actionFolder}/platforms/ubuntu/entrypoint.sh:/entrypoint.sh:z" \
|
--volume "${actionFolder}/platforms/ubuntu/entrypoint.sh:/entrypoint.sh:z" \
|
||||||
--volume "${actionFolder}/unity-config:/usr/share/unity3d/config/:z" \
|
--volume "${actionFolder}/unity-config:/usr/share/unity3d/config/:z" \
|
||||||
|
--volume "${actionFolder}/BlankProject":"/BlankProject:z" \
|
||||||
|
--cpus=${dockerCpuLimit} \
|
||||||
|
--memory=${dockerMemoryLimit} \
|
||||||
${sshAgent ? `--volume ${sshAgent}:/ssh-agent` : ''} \
|
${sshAgent ? `--volume ${sshAgent}:/ssh-agent` : ''} \
|
||||||
${
|
${
|
||||||
sshAgent && !sshPublicKeysDirectoryPath
|
sshAgent && !sshPublicKeysDirectoryPath
|
||||||
@ -86,23 +89,40 @@ class Docker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getWindowsCommand(image: string, parameters: DockerParameters): string {
|
static getWindowsCommand(image: string, parameters: DockerParameters): string {
|
||||||
const { workspace, actionFolder, unitySerial, gitPrivateToken, dockerWorkspacePath } = parameters;
|
const {
|
||||||
|
workspace,
|
||||||
|
actionFolder,
|
||||||
|
runnerTempPath,
|
||||||
|
gitPrivateToken,
|
||||||
|
dockerWorkspacePath,
|
||||||
|
dockerCpuLimit,
|
||||||
|
dockerMemoryLimit,
|
||||||
|
dockerIsolationMode,
|
||||||
|
} = parameters;
|
||||||
|
|
||||||
|
const githubHome = path.join(runnerTempPath, '_github_home');
|
||||||
|
if (!existsSync(githubHome)) mkdirSync(githubHome);
|
||||||
|
|
||||||
return `docker run \
|
return `docker run \
|
||||||
--workdir c:${dockerWorkspacePath} \
|
--workdir c:${dockerWorkspacePath} \
|
||||||
--rm \
|
--rm \
|
||||||
${ImageEnvironmentFactory.getEnvVarString(parameters)} \
|
${ImageEnvironmentFactory.getEnvVarString(parameters)} \
|
||||||
--env UNITY_SERIAL="${unitySerial}" \
|
|
||||||
--env GITHUB_WORKSPACE=c:${dockerWorkspacePath} \
|
--env GITHUB_WORKSPACE=c:${dockerWorkspacePath} \
|
||||||
${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \
|
${gitPrivateToken ? `--env GIT_PRIVATE_TOKEN="${gitPrivateToken}"` : ''} \
|
||||||
--volume "${workspace}":"c:${dockerWorkspacePath}" \
|
--volume "${workspace}":"c:${dockerWorkspacePath}" \
|
||||||
|
--volume "${githubHome}":"C:/githubhome" \
|
||||||
--volume "c:/regkeys":"c:/regkeys" \
|
--volume "c:/regkeys":"c:/regkeys" \
|
||||||
|
--volume "C:/Program Files/Microsoft Visual Studio":"C:/Program Files/Microsoft Visual Studio" \
|
||||||
--volume "C:/Program Files (x86)/Microsoft Visual Studio":"C:/Program Files (x86)/Microsoft Visual Studio" \
|
--volume "C:/Program Files (x86)/Microsoft Visual Studio":"C:/Program Files (x86)/Microsoft Visual Studio" \
|
||||||
--volume "C:/Program Files (x86)/Windows Kits":"C:/Program Files (x86)/Windows Kits" \
|
--volume "C:/Program Files (x86)/Windows Kits":"C:/Program Files (x86)/Windows Kits" \
|
||||||
--volume "C:/ProgramData/Microsoft/VisualStudio":"C:/ProgramData/Microsoft/VisualStudio" \
|
--volume "C:/ProgramData/Microsoft/VisualStudio":"C:/ProgramData/Microsoft/VisualStudio" \
|
||||||
--volume "${actionFolder}/default-build-script":"c:/UnityBuilderAction" \
|
--volume "${actionFolder}/default-build-script":"c:/UnityBuilderAction" \
|
||||||
--volume "${actionFolder}/platforms/windows":"c:/steps" \
|
--volume "${actionFolder}/platforms/windows":"c:/steps" \
|
||||||
|
--volume "${actionFolder}/unity-config":"C:/ProgramData/Unity/config" \
|
||||||
--volume "${actionFolder}/BlankProject":"c:/BlankProject" \
|
--volume "${actionFolder}/BlankProject":"c:/BlankProject" \
|
||||||
|
--cpus=${dockerCpuLimit} \
|
||||||
|
--memory=${dockerMemoryLimit} \
|
||||||
|
--isolation=${dockerIsolationMode} \
|
||||||
${image} \
|
${image} \
|
||||||
powershell c:/steps/entrypoint.ps1`;
|
powershell c:/steps/entrypoint.ps1`;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import { getExecOutput, ExecOptions } from '@actions/exec';
|
|
||||||
|
|
||||||
export async function execWithErrorCheck(
|
|
||||||
commandLine: string,
|
|
||||||
arguments_?: string[],
|
|
||||||
options?: ExecOptions,
|
|
||||||
errorWhenMissingUnityBuildResults: boolean = true,
|
|
||||||
): Promise<number> {
|
|
||||||
const result = await getExecOutput(commandLine, arguments_, options);
|
|
||||||
|
|
||||||
if (!errorWhenMissingUnityBuildResults) {
|
|
||||||
return result.exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for errors in the Build Results section
|
|
||||||
const match = result.stdout.match(/^#\s*Build results\s*#(.*)^Size:/ms);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
const buildResults = match[1];
|
|
||||||
const errorMatch = buildResults.match(/^Errors:\s*(\d+)$/m);
|
|
||||||
if (errorMatch && Number.parseInt(errorMatch[1], 10) !== 0) {
|
|
||||||
throw new Error(`There was an error building the project. Please read the logs for details.`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error(`There was an error building the project. Please read the logs for details.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.exitCode;
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ class GitHub {
|
|||||||
private static startedDate: string;
|
private static startedDate: string;
|
||||||
private static endedDate: string;
|
private static endedDate: string;
|
||||||
static result: string = ``;
|
static result: string = ``;
|
||||||
|
static forceAsyncTest: boolean;
|
||||||
private static get octokitDefaultToken() {
|
private static get octokitDefaultToken() {
|
||||||
return new Octokit({
|
return new Octokit({
|
||||||
auth: process.env.GITHUB_TOKEN,
|
auth: process.env.GITHUB_TOKEN,
|
||||||
@ -51,7 +52,7 @@ class GitHub {
|
|||||||
}
|
}
|
||||||
GitHub.startedDate = new Date().toISOString();
|
GitHub.startedDate = new Date().toISOString();
|
||||||
|
|
||||||
CloudRunnerLogger.log(`Creating inital github check`);
|
CloudRunnerLogger.log(`Creating github check`);
|
||||||
const data = {
|
const data = {
|
||||||
owner: GitHub.owner,
|
owner: GitHub.owner,
|
||||||
repo: GitHub.repo,
|
repo: GitHub.repo,
|
||||||
@ -78,6 +79,8 @@ class GitHub {
|
|||||||
};
|
};
|
||||||
const result = await GitHub.createGitHubCheckRequest(data);
|
const result = await GitHub.createGitHubCheckRequest(data);
|
||||||
|
|
||||||
|
CloudRunnerLogger.log(`Creating github check ${result.status}`);
|
||||||
|
|
||||||
return result.data.id.toString();
|
return result.data.id.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +130,7 @@ class GitHub {
|
|||||||
data.conclusion = result;
|
data.conclusion = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
await (CloudRunner.isCloudRunnerAsyncEnvironment
|
await (CloudRunner.isCloudRunnerAsyncEnvironment || GitHub.forceAsyncTest
|
||||||
? GitHub.runUpdateAsyncChecksWorkflow(data, `update`)
|
? GitHub.runUpdateAsyncChecksWorkflow(data, `update`)
|
||||||
: GitHub.updateGitHubCheckRequest(data));
|
: GitHub.updateGitHubCheckRequest(data));
|
||||||
}
|
}
|
||||||
@ -174,38 +177,46 @@ class GitHub {
|
|||||||
|
|
||||||
static async triggerWorkflowOnComplete(triggerWorkflowOnComplete: string[]) {
|
static async triggerWorkflowOnComplete(triggerWorkflowOnComplete: string[]) {
|
||||||
const isLocalAsync = CloudRunner.buildParameters.asyncWorkflow && !CloudRunner.isCloudRunnerAsyncEnvironment;
|
const isLocalAsync = CloudRunner.buildParameters.asyncWorkflow && !CloudRunner.isCloudRunnerAsyncEnvironment;
|
||||||
if (isLocalAsync) {
|
if (isLocalAsync || triggerWorkflowOnComplete === undefined || triggerWorkflowOnComplete.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const workflowsResult = await GitHub.octokitPAT.request(`GET /repos/{owner}/{repo}/actions/workflows`, {
|
try {
|
||||||
owner: GitHub.owner,
|
const workflowsResult = await GitHub.octokitPAT.request(`GET /repos/{owner}/{repo}/actions/workflows`, {
|
||||||
repo: GitHub.repo,
|
|
||||||
});
|
|
||||||
const workflows = workflowsResult.data.workflows;
|
|
||||||
CloudRunnerLogger.log(`Got ${workflows.length} workflows`);
|
|
||||||
for (const element of triggerWorkflowOnComplete) {
|
|
||||||
let selectedId = ``;
|
|
||||||
for (let index = 0; index < workflowsResult.data.total_count; index++) {
|
|
||||||
if (workflows[index].name === element) {
|
|
||||||
selectedId = workflows[index].id.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectedId === ``) {
|
|
||||||
core.info(JSON.stringify(workflows));
|
|
||||||
throw new Error(`no workflow with name "${GitHub.asyncChecksApiWorkflowName}"`);
|
|
||||||
}
|
|
||||||
await GitHub.octokitPAT.request(`POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches`, {
|
|
||||||
owner: GitHub.owner,
|
owner: GitHub.owner,
|
||||||
repo: GitHub.repo,
|
repo: GitHub.repo,
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
workflow_id: selectedId,
|
|
||||||
ref: CloudRunnerOptions.branch,
|
|
||||||
inputs: {
|
|
||||||
buildGuid: CloudRunner.buildParameters.buildGuid,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
const workflows = workflowsResult.data.workflows;
|
||||||
|
CloudRunnerLogger.log(`Got ${workflows.length} workflows`);
|
||||||
|
for (const element of triggerWorkflowOnComplete) {
|
||||||
|
let selectedId = ``;
|
||||||
|
for (let index = 0; index < workflowsResult.data.total_count; index++) {
|
||||||
|
if (workflows[index].name === element) {
|
||||||
|
selectedId = workflows[index].id.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedId === ``) {
|
||||||
|
core.info(JSON.stringify(workflows));
|
||||||
|
throw new Error(`no workflow with name "${GitHub.asyncChecksApiWorkflowName}"`);
|
||||||
|
}
|
||||||
|
await GitHub.octokitPAT.request(`POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches`, {
|
||||||
|
owner: GitHub.owner,
|
||||||
|
repo: GitHub.repo,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
workflow_id: selectedId,
|
||||||
|
ref: CloudRunnerOptions.branch,
|
||||||
|
inputs: {
|
||||||
|
buildGuid: CloudRunner.buildParameters.buildGuid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
core.info(`github workflow complete hook not found`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async getCheckStatus() {
|
||||||
|
return await GitHub.octokitDefaultToken.request(`GET /repos/{owner}/{repo}/check-runs/{check_run_id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GitHub;
|
export default GitHub;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { ReadLicense } from './input-readers/test-license-reader';
|
|
||||||
import { DockerParameters, StringKeyValuePair } from './shared-types';
|
import { DockerParameters, StringKeyValuePair } from './shared-types';
|
||||||
|
|
||||||
class ImageEnvironmentFactory {
|
class ImageEnvironmentFactory {
|
||||||
@ -23,32 +22,50 @@ class ImageEnvironmentFactory {
|
|||||||
|
|
||||||
public static getEnvironmentVariables(parameters: DockerParameters, additionalVariables: StringKeyValuePair[] = []) {
|
public static getEnvironmentVariables(parameters: DockerParameters, additionalVariables: StringKeyValuePair[] = []) {
|
||||||
let environmentVariables: StringKeyValuePair[] = [
|
let environmentVariables: StringKeyValuePair[] = [
|
||||||
{ name: 'UNITY_LICENSE', value: process.env.UNITY_LICENSE || ReadLicense() },
|
|
||||||
{ name: 'UNITY_LICENSE_FILE', value: process.env.UNITY_LICENSE_FILE },
|
|
||||||
{ name: 'UNITY_EMAIL', value: process.env.UNITY_EMAIL },
|
{ name: 'UNITY_EMAIL', value: process.env.UNITY_EMAIL },
|
||||||
{ name: 'UNITY_PASSWORD', value: process.env.UNITY_PASSWORD },
|
{ name: 'UNITY_PASSWORD', value: process.env.UNITY_PASSWORD },
|
||||||
{ name: 'UNITY_SERIAL', value: parameters.unitySerial },
|
{ name: 'UNITY_SERIAL', value: parameters.unitySerial },
|
||||||
{ name: 'UNITY_LICENSING_SERVER', value: parameters.unityLicensingServer },
|
{
|
||||||
|
name: 'UNITY_LICENSING_SERVER',
|
||||||
|
value: parameters.unityLicensingServer,
|
||||||
|
},
|
||||||
|
{ name: 'SKIP_ACTIVATION', value: parameters.skipActivation },
|
||||||
{ name: 'UNITY_VERSION', value: parameters.editorVersion },
|
{ name: 'UNITY_VERSION', value: parameters.editorVersion },
|
||||||
{ name: 'USYM_UPLOAD_AUTH_TOKEN', value: process.env.USYM_UPLOAD_AUTH_TOKEN },
|
{
|
||||||
|
name: 'USYM_UPLOAD_AUTH_TOKEN',
|
||||||
|
value: process.env.USYM_UPLOAD_AUTH_TOKEN,
|
||||||
|
},
|
||||||
{ name: 'PROJECT_PATH', value: parameters.projectPath },
|
{ name: 'PROJECT_PATH', value: parameters.projectPath },
|
||||||
|
{ name: 'BUILD_PROFILE', value: parameters.buildProfile },
|
||||||
{ name: 'BUILD_TARGET', value: parameters.targetPlatform },
|
{ name: 'BUILD_TARGET', value: parameters.targetPlatform },
|
||||||
{ name: 'BUILD_NAME', value: parameters.buildName },
|
{ name: 'BUILD_NAME', value: parameters.buildName },
|
||||||
{ name: 'BUILD_PATH', value: parameters.buildPath },
|
{ name: 'BUILD_PATH', value: parameters.buildPath },
|
||||||
{ name: 'BUILD_FILE', value: parameters.buildFile },
|
{ name: 'BUILD_FILE', value: parameters.buildFile },
|
||||||
{ name: 'BUILD_METHOD', value: parameters.buildMethod },
|
{ name: 'BUILD_METHOD', value: parameters.buildMethod },
|
||||||
|
{ name: 'MANUAL_EXIT', value: parameters.manualExit },
|
||||||
|
{ name: 'ENABLE_GPU', value: parameters.enableGpu },
|
||||||
{ name: 'VERSION', value: parameters.buildVersion },
|
{ name: 'VERSION', value: parameters.buildVersion },
|
||||||
{ name: 'ANDROID_VERSION_CODE', value: parameters.androidVersionCode },
|
{ name: 'ANDROID_VERSION_CODE', value: parameters.androidVersionCode },
|
||||||
{ name: 'ANDROID_KEYSTORE_NAME', value: parameters.androidKeystoreName },
|
{ name: 'ANDROID_KEYSTORE_NAME', value: parameters.androidKeystoreName },
|
||||||
{ name: 'ANDROID_KEYSTORE_BASE64', value: parameters.androidKeystoreBase64 },
|
{
|
||||||
|
name: 'ANDROID_KEYSTORE_BASE64',
|
||||||
|
value: parameters.androidKeystoreBase64,
|
||||||
|
},
|
||||||
{ name: 'ANDROID_KEYSTORE_PASS', value: parameters.androidKeystorePass },
|
{ name: 'ANDROID_KEYSTORE_PASS', value: parameters.androidKeystorePass },
|
||||||
{ name: 'ANDROID_KEYALIAS_NAME', value: parameters.androidKeyaliasName },
|
{ name: 'ANDROID_KEYALIAS_NAME', value: parameters.androidKeyaliasName },
|
||||||
{ name: 'ANDROID_KEYALIAS_PASS', value: parameters.androidKeyaliasPass },
|
{ name: 'ANDROID_KEYALIAS_PASS', value: parameters.androidKeyaliasPass },
|
||||||
{ name: 'ANDROID_TARGET_SDK_VERSION', value: parameters.androidTargetSdkVersion },
|
{
|
||||||
{ name: 'ANDROID_SDK_MANAGER_PARAMETERS', value: parameters.androidSdkManagerParameters },
|
name: 'ANDROID_TARGET_SDK_VERSION',
|
||||||
|
value: parameters.androidTargetSdkVersion,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ANDROID_SDK_MANAGER_PARAMETERS',
|
||||||
|
value: parameters.androidSdkManagerParameters,
|
||||||
|
},
|
||||||
{ name: 'ANDROID_EXPORT_TYPE', value: parameters.androidExportType },
|
{ name: 'ANDROID_EXPORT_TYPE', value: parameters.androidExportType },
|
||||||
{ name: 'ANDROID_SYMBOL_TYPE', value: parameters.androidSymbolType },
|
{ name: 'ANDROID_SYMBOL_TYPE', value: parameters.androidSymbolType },
|
||||||
{ name: 'CUSTOM_PARAMETERS', value: parameters.customParameters },
|
{ name: 'CUSTOM_PARAMETERS', value: parameters.customParameters },
|
||||||
|
{ name: 'RUN_AS_HOST_USER', value: parameters.runAsHostUser },
|
||||||
{ name: 'CHOWN_FILES_TO', value: parameters.chownFilesTo },
|
{ name: 'CHOWN_FILES_TO', value: parameters.chownFilesTo },
|
||||||
{ name: 'GITHUB_REF', value: process.env.GITHUB_REF },
|
{ name: 'GITHUB_REF', value: process.env.GITHUB_REF },
|
||||||
{ name: 'GITHUB_SHA', value: process.env.GITHUB_SHA },
|
{ name: 'GITHUB_SHA', value: process.env.GITHUB_SHA },
|
||||||
@ -67,25 +84,19 @@ class ImageEnvironmentFactory {
|
|||||||
];
|
];
|
||||||
if (parameters.providerStrategy === 'local-docker') {
|
if (parameters.providerStrategy === 'local-docker') {
|
||||||
for (const element of additionalVariables) {
|
for (const element of additionalVariables) {
|
||||||
if (
|
if (!environmentVariables.some((x) => element?.name === x?.name)) {
|
||||||
environmentVariables.find(
|
|
||||||
(x) => element !== undefined && element.name !== undefined && x.name === element.name,
|
|
||||||
) === undefined
|
|
||||||
) {
|
|
||||||
environmentVariables.push(element);
|
environmentVariables.push(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const variable of environmentVariables) {
|
for (const variable of environmentVariables) {
|
||||||
if (
|
if (!environmentVariables.some((x) => variable?.name === x?.name)) {
|
||||||
environmentVariables.find(
|
|
||||||
(x) => variable !== undefined && variable.name !== undefined && x.name === variable.name,
|
|
||||||
) === undefined
|
|
||||||
) {
|
|
||||||
environmentVariables = environmentVariables.filter((x) => x !== variable);
|
environmentVariables = environmentVariables.filter((x) => x !== variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (parameters.sshAgent) environmentVariables.push({ name: 'SSH_AUTH_SOCK', value: '/ssh-agent' });
|
if (parameters.sshAgent) {
|
||||||
|
environmentVariables.push({ name: 'SSH_AUTH_SOCK', value: '/ssh-agent' });
|
||||||
|
}
|
||||||
|
|
||||||
return environmentVariables;
|
return environmentVariables;
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ import ImageTag from './image-tag';
|
|||||||
|
|
||||||
describe('ImageTag', () => {
|
describe('ImageTag', () => {
|
||||||
const testImageParameters = {
|
const testImageParameters = {
|
||||||
editorVersion: '2099.9.f9f9',
|
editorVersion: '2099.9.9f9',
|
||||||
targetPlatform: 'Test',
|
targetPlatform: 'Test',
|
||||||
builderPlatform: '',
|
builderPlatform: '',
|
||||||
|
containerRegistryRepository: 'unityci/editor',
|
||||||
|
containerRegistryImageVersion: '3',
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
repository: 'unityci',
|
|
||||||
name: 'editor',
|
|
||||||
image: 'unityci/editor',
|
image: 'unityci/editor',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,16 +21,19 @@ describe('ImageTag', () => {
|
|||||||
it('accepts parameters and sets the right properties', () => {
|
it('accepts parameters and sets the right properties', () => {
|
||||||
const image = new ImageTag(testImageParameters);
|
const image = new ImageTag(testImageParameters);
|
||||||
|
|
||||||
expect(image.repository).toStrictEqual('unityci');
|
expect(image.repository).toStrictEqual('unityci/editor');
|
||||||
expect(image.name).toStrictEqual('editor');
|
|
||||||
expect(image.editorVersion).toStrictEqual(testImageParameters.editorVersion);
|
expect(image.editorVersion).toStrictEqual(testImageParameters.editorVersion);
|
||||||
expect(image.targetPlatform).toStrictEqual(testImageParameters.targetPlatform);
|
expect(image.targetPlatform).toStrictEqual(testImageParameters.targetPlatform);
|
||||||
expect(image.builderPlatform).toStrictEqual(testImageParameters.builderPlatform);
|
expect(image.builderPlatform).toStrictEqual(testImageParameters.builderPlatform);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', (version) => {
|
test.each(['2000.0.0f0', '2011.1.11f1', '6000.0.0f1'])('accepts %p version format', (version) => {
|
||||||
expect(
|
expect(
|
||||||
() => new ImageTag({ editorVersion: version, targetPlatform: testImageParameters.targetPlatform }),
|
() =>
|
||||||
|
new ImageTag({
|
||||||
|
editorVersion: version,
|
||||||
|
targetPlatform: testImageParameters.targetPlatform,
|
||||||
|
}),
|
||||||
).not.toThrow();
|
).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,48 +49,65 @@ describe('ImageTag', () => {
|
|||||||
|
|
||||||
describe('toString', () => {
|
describe('toString', () => {
|
||||||
it('returns the correct version', () => {
|
it('returns the correct version', () => {
|
||||||
const image = new ImageTag({ editorVersion: '2099.1.1111', targetPlatform: testImageParameters.targetPlatform });
|
const image = new ImageTag({
|
||||||
|
editorVersion: '2099.1.1111f1',
|
||||||
|
targetPlatform: testImageParameters.targetPlatform,
|
||||||
|
containerRegistryRepository: 'unityci/editor',
|
||||||
|
containerRegistryImageVersion: '3',
|
||||||
|
});
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2099.1.1111-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2099.1.1111f1-3`);
|
||||||
break;
|
break;
|
||||||
case 'linux':
|
case 'linux':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2099.1.1111-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2099.1.1111f1-3`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('returns customImage if given', () => {
|
it('returns customImage if given', () => {
|
||||||
const image = new ImageTag({
|
const image = new ImageTag({
|
||||||
editorVersion: '2099.1.1111',
|
editorVersion: '2099.1.1111f1',
|
||||||
targetPlatform: testImageParameters.targetPlatform,
|
targetPlatform: testImageParameters.targetPlatform,
|
||||||
customImage: `${defaults.image}:2099.1.1111@347598437689743986`,
|
customImage: `${defaults.image}:2099.1.1111@347598437689743986`,
|
||||||
|
containerRegistryRepository: 'unityci/editor',
|
||||||
|
containerRegistryImageVersion: '3',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(image.toString()).toStrictEqual(image.customImage);
|
expect(image.toString()).toStrictEqual(image.customImage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the specific build platform', () => {
|
it('returns the specific build platform', () => {
|
||||||
const image = new ImageTag({ editorVersion: '2019.2.11f1', targetPlatform: 'WebGL' });
|
const image = new ImageTag({
|
||||||
|
editorVersion: '2019.2.11f1',
|
||||||
|
targetPlatform: 'WebGL',
|
||||||
|
containerRegistryRepository: 'unityci/editor',
|
||||||
|
containerRegistryImageVersion: '3',
|
||||||
|
});
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2019.2.11f1-webgl-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2019.2.11f1-webgl-3`);
|
||||||
break;
|
break;
|
||||||
case 'linux':
|
case 'linux':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-webgl-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-webgl-3`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns no specific build platform for generic targetPlatforms', () => {
|
it('returns no specific build platform for generic targetPlatforms', () => {
|
||||||
const image = new ImageTag({ editorVersion: '2019.2.11f1', targetPlatform: 'NoTarget' });
|
const image = new ImageTag({
|
||||||
|
editorVersion: '2019.2.11f1',
|
||||||
|
targetPlatform: 'NoTarget',
|
||||||
|
containerRegistryRepository: 'unityci/editor',
|
||||||
|
containerRegistryImageVersion: '3',
|
||||||
|
});
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2019.2.11f1-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2019.2.11f1-3`);
|
||||||
break;
|
break;
|
||||||
case 'linux':
|
case 'linux':
|
||||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-2`);
|
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-3`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,6 @@ import Platform from './platform';
|
|||||||
|
|
||||||
class ImageTag {
|
class ImageTag {
|
||||||
public repository: string;
|
public repository: string;
|
||||||
public name: string;
|
|
||||||
public cloudRunnerBuilderPlatform!: string;
|
|
||||||
public editorVersion: string;
|
public editorVersion: string;
|
||||||
public targetPlatform: string;
|
public targetPlatform: string;
|
||||||
public builderPlatform: string;
|
public builderPlatform: string;
|
||||||
@ -12,7 +10,15 @@ class ImageTag {
|
|||||||
public imagePlatformPrefix: string;
|
public imagePlatformPrefix: string;
|
||||||
|
|
||||||
constructor(imageProperties: { [key: string]: string }) {
|
constructor(imageProperties: { [key: string]: string }) {
|
||||||
const { editorVersion, targetPlatform, customImage, cloudRunnerBuilderPlatform } = imageProperties;
|
const {
|
||||||
|
editorVersion,
|
||||||
|
targetPlatform,
|
||||||
|
customImage,
|
||||||
|
buildPlatform,
|
||||||
|
containerRegistryRepository,
|
||||||
|
containerRegistryImageVersion,
|
||||||
|
providerStrategy,
|
||||||
|
} = imageProperties;
|
||||||
|
|
||||||
if (!ImageTag.versionPattern.test(editorVersion)) {
|
if (!ImageTag.versionPattern.test(editorVersion)) {
|
||||||
throw new Error(`Invalid version "${editorVersion}".`);
|
throw new Error(`Invalid version "${editorVersion}".`);
|
||||||
@ -23,21 +29,20 @@ class ImageTag {
|
|||||||
this.customImage = customImage;
|
this.customImage = customImage;
|
||||||
|
|
||||||
// Or
|
// Or
|
||||||
this.repository = 'unityci';
|
this.repository = containerRegistryRepository;
|
||||||
this.name = 'editor';
|
|
||||||
this.editorVersion = editorVersion;
|
this.editorVersion = editorVersion;
|
||||||
this.targetPlatform = targetPlatform;
|
this.targetPlatform = targetPlatform;
|
||||||
this.cloudRunnerBuilderPlatform = cloudRunnerBuilderPlatform;
|
this.builderPlatform = ImageTag.getTargetPlatformToTargetPlatformSuffixMap(
|
||||||
const isCloudRunnerLocal = cloudRunnerBuilderPlatform === 'local' || cloudRunnerBuilderPlatform === undefined;
|
targetPlatform,
|
||||||
this.builderPlatform = ImageTag.getTargetPlatformToTargetPlatformSuffixMap(targetPlatform, editorVersion);
|
editorVersion,
|
||||||
this.imagePlatformPrefix = ImageTag.getImagePlatformPrefixes(
|
providerStrategy,
|
||||||
isCloudRunnerLocal ? process.platform : cloudRunnerBuilderPlatform,
|
|
||||||
);
|
);
|
||||||
this.imageRollingVersion = 2; // Will automatically roll to the latest non-breaking version.
|
this.imagePlatformPrefix = ImageTag.getImagePlatformPrefixes(buildPlatform);
|
||||||
|
this.imageRollingVersion = Number(containerRegistryImageVersion); // Will automatically roll to the latest non-breaking version.
|
||||||
}
|
}
|
||||||
|
|
||||||
static get versionPattern(): RegExp {
|
static get versionPattern(): RegExp {
|
||||||
return /^(20\d{2}\.\d\.\w{3,4}|3)$/;
|
return /^\d+\.\d+\.\d+[a-z]\d+$/;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get targetPlatformSuffixes() {
|
static get targetPlatformSuffixes() {
|
||||||
@ -53,11 +58,16 @@ class ImageTag {
|
|||||||
android: 'android',
|
android: 'android',
|
||||||
ios: 'ios',
|
ios: 'ios',
|
||||||
tvos: 'appletv',
|
tvos: 'appletv',
|
||||||
|
visionos: 'visionos',
|
||||||
facebook: 'facebook',
|
facebook: 'facebook',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static getImagePlatformPrefixes(platform: string): string {
|
static getImagePlatformPrefixes(platform: string): string {
|
||||||
|
if (!platform || platform === '') {
|
||||||
|
platform = process.platform;
|
||||||
|
}
|
||||||
|
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
return 'windows';
|
return 'windows';
|
||||||
@ -68,9 +78,26 @@ class ImageTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getTargetPlatformToTargetPlatformSuffixMap(platform: string, version: string): string {
|
static getTargetPlatformToTargetPlatformSuffixMap(
|
||||||
const { generic, webgl, mac, windows, windowsIl2cpp, wsaPlayer, linux, linuxIl2cpp, android, ios, tvos, facebook } =
|
platform: string,
|
||||||
ImageTag.targetPlatformSuffixes;
|
version: string,
|
||||||
|
providerStrategy: string,
|
||||||
|
): string {
|
||||||
|
const {
|
||||||
|
generic,
|
||||||
|
webgl,
|
||||||
|
mac,
|
||||||
|
windows,
|
||||||
|
windowsIl2cpp,
|
||||||
|
wsaPlayer,
|
||||||
|
linux,
|
||||||
|
linuxIl2cpp,
|
||||||
|
android,
|
||||||
|
ios,
|
||||||
|
tvos,
|
||||||
|
visionos,
|
||||||
|
facebook,
|
||||||
|
} = ImageTag.targetPlatformSuffixes;
|
||||||
|
|
||||||
const [major, minor] = version.split('.').map((digit) => Number(digit));
|
const [major, minor] = version.split('.').map((digit) => Number(digit));
|
||||||
|
|
||||||
@ -86,8 +113,10 @@ class ImageTag {
|
|||||||
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
||||||
return windowsIl2cpp;
|
return windowsIl2cpp;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Windows-based builds are only supported on 2019.3.X+ versions of Unity.
|
throw new Error(
|
||||||
If you are trying to build for windows-mono, please use a Linux based OS.`);
|
`Windows-based builds are only supported on 2019.3.X+ versions of Unity.
|
||||||
|
If you are trying to build for windows-mono, please use a Linux based OS.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +124,11 @@ class ImageTag {
|
|||||||
case Platform.types.StandaloneLinux64: {
|
case Platform.types.StandaloneLinux64: {
|
||||||
// Unity versions before 2019.3 do not support il2cpp
|
// Unity versions before 2019.3 do not support il2cpp
|
||||||
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
||||||
return linuxIl2cpp;
|
if (providerStrategy === 'local') {
|
||||||
|
return linuxIl2cpp;
|
||||||
|
} else {
|
||||||
|
return process.env.USE_IL2CPP === 'true' ? linuxIl2cpp : linux;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return linux;
|
return linux;
|
||||||
@ -117,11 +150,17 @@ class ImageTag {
|
|||||||
case Platform.types.XboxOne:
|
case Platform.types.XboxOne:
|
||||||
return windows;
|
return windows;
|
||||||
case Platform.types.tvOS:
|
case Platform.types.tvOS:
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32' && process.platform !== 'darwin') {
|
||||||
throw new Error(`tvOS can only be built on a windows base OS`);
|
throw new Error(`tvOS can only be built on Windows or macOS base OS`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tvos;
|
return tvos;
|
||||||
|
case Platform.types.VisionOS:
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
throw new Error(`visionOS can only be built on a macOS base OS`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return visionos;
|
||||||
case Platform.types.Switch:
|
case Platform.types.Switch:
|
||||||
return windows;
|
return windows;
|
||||||
|
|
||||||
@ -154,7 +193,7 @@ class ImageTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get image(): string {
|
get image(): string {
|
||||||
return `${this.repository}/${this.name}`.replace(/^\/+/, '');
|
return `${this.repository}`.replace(/^\/+/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
@ -162,7 +201,7 @@ class ImageTag {
|
|||||||
|
|
||||||
if (customImage) return customImage;
|
if (customImage) return customImage;
|
||||||
|
|
||||||
return `${image}:${tag}`; // '0' here represents the docker repo version
|
return `${image}:${tag}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,19 @@ describe('Input', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('buildProfile', () => {
|
||||||
|
it('returns the default value', () => {
|
||||||
|
expect(Input.buildProfile).toStrictEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('takes input from the users workflow', () => {
|
||||||
|
const mockValue = 'path/to/build_profile.asset';
|
||||||
|
const spy = jest.spyOn(core, 'getInput').mockReturnValue(mockValue);
|
||||||
|
expect(Input.buildProfile).toStrictEqual(mockValue);
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('buildName', () => {
|
describe('buildName', () => {
|
||||||
it('returns the default value', () => {
|
it('returns the default value', () => {
|
||||||
expect(Input.buildName).toStrictEqual(Input.targetPlatform);
|
expect(Input.buildName).toStrictEqual(Input.targetPlatform);
|
||||||
@ -104,6 +117,42 @@ describe('Input', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('manualExit', () => {
|
||||||
|
it('returns the default value', () => {
|
||||||
|
expect(Input.manualExit).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when string true is passed', () => {
|
||||||
|
const spy = jest.spyOn(core, 'getInput').mockReturnValue('true');
|
||||||
|
expect(Input.manualExit).toStrictEqual(true);
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when string false is passed', () => {
|
||||||
|
const spy = jest.spyOn(core, 'getInput').mockReturnValue('false');
|
||||||
|
expect(Input.manualExit).toStrictEqual(false);
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('enableGpu', () => {
|
||||||
|
it('returns the default value', () => {
|
||||||
|
expect(Input.enableGpu).toStrictEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when string true is passed', () => {
|
||||||
|
const spy = jest.spyOn(core, 'getInput').mockReturnValue('true');
|
||||||
|
expect(Input.enableGpu).toStrictEqual(true);
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when string false is passed', () => {
|
||||||
|
const spy = jest.spyOn(core, 'getInput').mockReturnValue('false');
|
||||||
|
expect(Input.enableGpu).toStrictEqual(false);
|
||||||
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('versioningStrategy', () => {
|
describe('versioningStrategy', () => {
|
||||||
it('returns the default value', () => {
|
it('returns the default value', () => {
|
||||||
expect(Input.versioningStrategy).toStrictEqual('Semantic');
|
expect(Input.versioningStrategy).toStrictEqual('Semantic');
|
||||||
|
@ -4,6 +4,7 @@ import { Cli } from './cli/cli';
|
|||||||
import CloudRunnerQueryOverride from './cloud-runner/options/cloud-runner-query-override';
|
import CloudRunnerQueryOverride from './cloud-runner/options/cloud-runner-query-override';
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
import GitHub from './github';
|
import GitHub from './github';
|
||||||
|
import os from 'node:os';
|
||||||
|
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
|
||||||
@ -45,11 +46,11 @@ class Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get region(): string {
|
static get region(): string {
|
||||||
return Input.getInput('region') || 'eu-west-2';
|
return Input.getInput('region') ?? 'eu-west-2';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get githubRepo(): string | undefined {
|
static get githubRepo(): string | undefined {
|
||||||
return Input.getInput('GITHUB_REPOSITORY') || Input.getInput('GITHUB_REPO') || undefined;
|
return Input.getInput('GITHUB_REPOSITORY') ?? Input.getInput('GITHUB_REPO') ?? undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get branch(): string {
|
static get branch(): string {
|
||||||
@ -73,19 +74,19 @@ class Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get runNumber(): string {
|
static get runNumber(): string {
|
||||||
return Input.getInput('GITHUB_RUN_NUMBER') || '0';
|
return Input.getInput('GITHUB_RUN_NUMBER') ?? '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get targetPlatform(): string {
|
static get targetPlatform(): string {
|
||||||
return Input.getInput('targetPlatform') || Platform.default;
|
return Input.getInput('targetPlatform') ?? Platform.default;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get unityVersion(): string {
|
static get unityVersion(): string {
|
||||||
return Input.getInput('unityVersion') || 'auto';
|
return Input.getInput('unityVersion') ?? 'auto';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get customImage(): string {
|
static get customImage(): string {
|
||||||
return Input.getInput('customImage') || '';
|
return Input.getInput('customImage') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get projectPath(): string {
|
static get projectPath(): string {
|
||||||
@ -106,104 +107,124 @@ class Input {
|
|||||||
return rawProjectPath.replace(/\/$/, '');
|
return rawProjectPath.replace(/\/$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get buildProfile(): string {
|
||||||
|
return Input.getInput('buildProfile') ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
static get runnerTempPath(): string {
|
static get runnerTempPath(): string {
|
||||||
return Input.getInput('RUNNER_TEMP') || '';
|
return Input.getInput('RUNNER_TEMP') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get buildName(): string {
|
static get buildName(): string {
|
||||||
return Input.getInput('buildName') || Input.targetPlatform;
|
return Input.getInput('buildName') ?? Input.targetPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get buildsPath(): string {
|
static get buildsPath(): string {
|
||||||
return Input.getInput('buildsPath') || 'build';
|
return Input.getInput('buildsPath') ?? 'build';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get unityLicensingServer(): string {
|
static get unityLicensingServer(): string {
|
||||||
return Input.getInput('unityLicensingServer') || '';
|
return Input.getInput('unityLicensingServer') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get buildMethod(): string {
|
static get buildMethod(): string {
|
||||||
return Input.getInput('buildMethod') || ''; // Processed in docker file
|
return Input.getInput('buildMethod') ?? ''; // Processed in docker file
|
||||||
|
}
|
||||||
|
|
||||||
|
static get manualExit(): boolean {
|
||||||
|
const input = Input.getInput('manualExit') ?? false;
|
||||||
|
|
||||||
|
return input === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get enableGpu(): boolean {
|
||||||
|
const input = Input.getInput('enableGpu') ?? false;
|
||||||
|
|
||||||
|
return input === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get customParameters(): string {
|
static get customParameters(): string {
|
||||||
return Input.getInput('customParameters') || '';
|
return Input.getInput('customParameters') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get versioningStrategy(): string {
|
static get versioningStrategy(): string {
|
||||||
return Input.getInput('versioning') || 'Semantic';
|
return Input.getInput('versioning') ?? 'Semantic';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get specifiedVersion(): string {
|
static get specifiedVersion(): string {
|
||||||
return Input.getInput('version') || '';
|
return Input.getInput('version') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidVersionCode(): string {
|
static get androidVersionCode(): string {
|
||||||
return Input.getInput('androidVersionCode') || '';
|
return Input.getInput('androidVersionCode') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidExportType(): string {
|
static get androidExportType(): string {
|
||||||
return Input.getInput('androidExportType') || 'androidPackage';
|
return Input.getInput('androidExportType') ?? 'androidPackage';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidKeystoreName(): string {
|
static get androidKeystoreName(): string {
|
||||||
return Input.getInput('androidKeystoreName') || '';
|
return Input.getInput('androidKeystoreName') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidKeystoreBase64(): string {
|
static get androidKeystoreBase64(): string {
|
||||||
return Input.getInput('androidKeystoreBase64') || '';
|
return Input.getInput('androidKeystoreBase64') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidKeystorePass(): string {
|
static get androidKeystorePass(): string {
|
||||||
return Input.getInput('androidKeystorePass') || '';
|
return Input.getInput('androidKeystorePass') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidKeyaliasName(): string {
|
static get androidKeyaliasName(): string {
|
||||||
return Input.getInput('androidKeyaliasName') || '';
|
return Input.getInput('androidKeyaliasName') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidKeyaliasPass(): string {
|
static get androidKeyaliasPass(): string {
|
||||||
return Input.getInput('androidKeyaliasPass') || '';
|
return Input.getInput('androidKeyaliasPass') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidTargetSdkVersion(): string {
|
static get androidTargetSdkVersion(): string {
|
||||||
return Input.getInput('androidTargetSdkVersion') || '';
|
return Input.getInput('androidTargetSdkVersion') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get androidSymbolType(): string {
|
static get androidSymbolType(): string {
|
||||||
return Input.getInput('androidSymbolType') || 'none';
|
return Input.getInput('androidSymbolType') ?? 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get sshAgent(): string {
|
static get sshAgent(): string {
|
||||||
return Input.getInput('sshAgent') || '';
|
return Input.getInput('sshAgent') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get sshPublicKeysDirectoryPath(): string {
|
static get sshPublicKeysDirectoryPath(): string {
|
||||||
return Input.getInput('sshPublicKeysDirectoryPath') || '';
|
return Input.getInput('sshPublicKeysDirectoryPath') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get gitPrivateToken(): string | undefined {
|
static get gitPrivateToken(): string | undefined {
|
||||||
return Input.getInput('gitPrivateToken');
|
return Input.getInput('gitPrivateToken');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get runAsHostUser(): string {
|
||||||
|
return Input.getInput('runAsHostUser')?.toLowerCase() ?? 'false';
|
||||||
|
}
|
||||||
|
|
||||||
static get chownFilesTo() {
|
static get chownFilesTo() {
|
||||||
return Input.getInput('chownFilesTo') || '';
|
return Input.getInput('chownFilesTo') ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get allowDirtyBuild(): boolean {
|
static get allowDirtyBuild(): boolean {
|
||||||
const input = Input.getInput('allowDirtyBuild') || false;
|
const input = Input.getInput('allowDirtyBuild') ?? false;
|
||||||
|
|
||||||
return input === 'true';
|
return input === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get cacheUnityInstallationOnMac(): boolean {
|
static get cacheUnityInstallationOnMac(): boolean {
|
||||||
const input = Input.getInput('cacheUnityInstallationOnMac') || false;
|
const input = Input.getInput('cacheUnityInstallationOnMac') ?? false;
|
||||||
|
|
||||||
return input === 'true';
|
return input === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get unityHubVersionOnMac(): string {
|
static get unityHubVersionOnMac(): string {
|
||||||
const input = Input.getInput('unityHubVersionOnMac') || '';
|
const input = Input.getInput('unityHubVersionOnMac') ?? '';
|
||||||
|
|
||||||
return input !== '' ? input : '';
|
return input !== '' ? input : '';
|
||||||
}
|
}
|
||||||
@ -217,7 +238,48 @@ class Input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get dockerWorkspacePath(): string {
|
static get dockerWorkspacePath(): string {
|
||||||
return Input.getInput('dockerWorkspacePath') || '/github/workspace';
|
return Input.getInput('dockerWorkspacePath') ?? '/github/workspace';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get dockerCpuLimit(): string {
|
||||||
|
return Input.getInput('dockerCpuLimit') ?? os.cpus().length.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get dockerMemoryLimit(): string {
|
||||||
|
const bytesInMegabyte = 1024 * 1024;
|
||||||
|
|
||||||
|
let memoryMultiplier;
|
||||||
|
switch (os.platform()) {
|
||||||
|
case 'linux':
|
||||||
|
memoryMultiplier = 0.95;
|
||||||
|
break;
|
||||||
|
case 'win32':
|
||||||
|
memoryMultiplier = 0.8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
memoryMultiplier = 0.75;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
Input.getInput('dockerMemoryLimit') ?? `${Math.floor((os.totalmem() / bytesInMegabyte) * memoryMultiplier)}m`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get dockerIsolationMode(): string {
|
||||||
|
return Input.getInput('dockerIsolationMode') ?? 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get containerRegistryRepository(): string {
|
||||||
|
return Input.getInput('containerRegistryRepository') ?? 'unityci/editor';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get containerRegistryImageVersion(): string {
|
||||||
|
return Input.getInput('containerRegistryImageVersion') ?? '3';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get skipActivation(): string {
|
||||||
|
return Input.getInput('skipActivation')?.toLowerCase() ?? 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ToEnvVarFormat(input: string) {
|
public static ToEnvVarFormat(input: string) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { execWithErrorCheck } from './exec-with-error-check';
|
import { exec } from '@actions/exec';
|
||||||
|
|
||||||
class MacBuilder {
|
class MacBuilder {
|
||||||
public static async run(actionFolder: string, silent: boolean = false) {
|
public static async run(actionFolder: string, silent: boolean = false): Promise<number> {
|
||||||
await execWithErrorCheck('bash', [`${actionFolder}/platforms/mac/entrypoint.sh`], {
|
return await exec('bash', [`${actionFolder}/platforms/mac/entrypoint.sh`], {
|
||||||
silent,
|
silent,
|
||||||
|
ignoreReturnCode: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,10 @@ class Output {
|
|||||||
static async setAndroidVersionCode(androidVersionCode: string) {
|
static async setAndroidVersionCode(androidVersionCode: string) {
|
||||||
core.setOutput('androidVersionCode', androidVersionCode);
|
core.setOutput('androidVersionCode', androidVersionCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async setEngineExitCode(exitCode: number) {
|
||||||
|
core.setOutput('engineExitCode', exitCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Output;
|
export default Output;
|
||||||
|
@ -47,7 +47,10 @@ class SetupMac {
|
|||||||
|
|
||||||
// Ignoring return code because the log seems to overflow the internal buffer which triggers
|
// Ignoring return code because the log seems to overflow the internal buffer which triggers
|
||||||
// a false error
|
// a false error
|
||||||
const errorCode = await exec(command, undefined, { silent, ignoreReturnCode: true });
|
const errorCode = await exec(command, undefined, {
|
||||||
|
silent,
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
});
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
|
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
|
||||||
}
|
}
|
||||||
@ -64,7 +67,9 @@ class SetupMac {
|
|||||||
private static async getLatestUnityHubVersion(): Promise<string> {
|
private static async getLatestUnityHubVersion(): Promise<string> {
|
||||||
// Need to check if the latest version available is the same as the one we have cached
|
// Need to check if the latest version available is the same as the one we have cached
|
||||||
const hubVersionCommand = `/bin/bash -c "brew info unity-hub | grep -o '[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+'"`;
|
const hubVersionCommand = `/bin/bash -c "brew info unity-hub | grep -o '[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+'"`;
|
||||||
const result = await getExecOutput(hubVersionCommand, undefined, { silent: true });
|
const result = await getExecOutput(hubVersionCommand, undefined, {
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
if (result.exitCode === 0 && result.stdout !== '') {
|
if (result.exitCode === 0 && result.stdout !== '') {
|
||||||
return result.stdout;
|
return result.stdout;
|
||||||
}
|
}
|
||||||
@ -72,6 +77,23 @@ class SetupMac {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static getArchitectureParameters(): string[] {
|
||||||
|
const architectureArgument = [];
|
||||||
|
|
||||||
|
switch (process.arch) {
|
||||||
|
case 'x64':
|
||||||
|
architectureArgument.push('--architecture', 'x86_64');
|
||||||
|
break;
|
||||||
|
case 'arm64':
|
||||||
|
architectureArgument.push('--architecture', 'arm64');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported architecture: ${process.arch}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return architectureArgument;
|
||||||
|
}
|
||||||
|
|
||||||
private static getModuleParametersForTargetPlatform(targetPlatform: string): string[] {
|
private static getModuleParametersForTargetPlatform(targetPlatform: string): string[] {
|
||||||
const moduleArgument = [];
|
const moduleArgument = [];
|
||||||
switch (targetPlatform) {
|
switch (targetPlatform) {
|
||||||
@ -79,7 +101,10 @@ class SetupMac {
|
|||||||
moduleArgument.push('--module', 'ios');
|
moduleArgument.push('--module', 'ios');
|
||||||
break;
|
break;
|
||||||
case 'tvOS':
|
case 'tvOS':
|
||||||
moduleArgument.push('--module', 'tvos');
|
moduleArgument.push('--module', 'appletv');
|
||||||
|
break;
|
||||||
|
case 'VisionOS':
|
||||||
|
moduleArgument.push('--module', 'visionos');
|
||||||
break;
|
break;
|
||||||
case 'StandaloneOSX':
|
case 'StandaloneOSX':
|
||||||
moduleArgument.push('--module', 'mac-il2cpp');
|
moduleArgument.push('--module', 'mac-il2cpp');
|
||||||
@ -111,6 +136,7 @@ class SetupMac {
|
|||||||
|
|
||||||
const unityChangeset = await getUnityChangeset(buildParameters.editorVersion);
|
const unityChangeset = await getUnityChangeset(buildParameters.editorVersion);
|
||||||
const moduleArguments = SetupMac.getModuleParametersForTargetPlatform(buildParameters.targetPlatform);
|
const moduleArguments = SetupMac.getModuleParametersForTargetPlatform(buildParameters.targetPlatform);
|
||||||
|
const architectureArguments = SetupMac.getArchitectureParameters();
|
||||||
|
|
||||||
const execArguments: string[] = [
|
const execArguments: string[] = [
|
||||||
'--',
|
'--',
|
||||||
@ -119,12 +145,16 @@ class SetupMac {
|
|||||||
...['--version', buildParameters.editorVersion],
|
...['--version', buildParameters.editorVersion],
|
||||||
...['--changeset', unityChangeset.changeset],
|
...['--changeset', unityChangeset.changeset],
|
||||||
...moduleArguments,
|
...moduleArguments,
|
||||||
|
...architectureArguments,
|
||||||
'--childModules',
|
'--childModules',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Ignoring return code because the log seems to overflow the internal buffer which triggers
|
// Ignoring return code because the log seems to overflow the internal buffer which triggers
|
||||||
// a false error
|
// a false error
|
||||||
const errorCode = await exec(this.unityHubExecPath, execArguments, { silent, ignoreReturnCode: true });
|
const errorCode = await exec(this.unityHubExecPath, execArguments, {
|
||||||
|
silent,
|
||||||
|
ignoreReturnCode: true,
|
||||||
|
});
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
|
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
|
||||||
}
|
}
|
||||||
@ -141,7 +171,9 @@ class SetupMac {
|
|||||||
process.env.UNITY_VERSION = buildParameters.editorVersion;
|
process.env.UNITY_VERSION = buildParameters.editorVersion;
|
||||||
process.env.UNITY_SERIAL = buildParameters.unitySerial;
|
process.env.UNITY_SERIAL = buildParameters.unitySerial;
|
||||||
process.env.UNITY_LICENSING_SERVER = buildParameters.unityLicensingServer;
|
process.env.UNITY_LICENSING_SERVER = buildParameters.unityLicensingServer;
|
||||||
|
process.env.SKIP_ACTIVATION = buildParameters.skipActivation;
|
||||||
process.env.PROJECT_PATH = buildParameters.projectPath;
|
process.env.PROJECT_PATH = buildParameters.projectPath;
|
||||||
|
process.env.BUILD_PROFILE = buildParameters.buildProfile;
|
||||||
process.env.BUILD_TARGET = buildParameters.targetPlatform;
|
process.env.BUILD_TARGET = buildParameters.targetPlatform;
|
||||||
process.env.BUILD_NAME = buildParameters.buildName;
|
process.env.BUILD_NAME = buildParameters.buildName;
|
||||||
process.env.BUILD_PATH = buildParameters.buildPath;
|
process.env.BUILD_PATH = buildParameters.buildPath;
|
||||||
@ -160,6 +192,8 @@ class SetupMac {
|
|||||||
process.env.ANDROID_SYMBOL_TYPE = buildParameters.androidSymbolType;
|
process.env.ANDROID_SYMBOL_TYPE = buildParameters.androidSymbolType;
|
||||||
process.env.CUSTOM_PARAMETERS = buildParameters.customParameters;
|
process.env.CUSTOM_PARAMETERS = buildParameters.customParameters;
|
||||||
process.env.CHOWN_FILES_TO = buildParameters.chownFilesTo;
|
process.env.CHOWN_FILES_TO = buildParameters.chownFilesTo;
|
||||||
|
process.env.MANUAL_EXIT = buildParameters.manualExit.toString();
|
||||||
|
process.env.ENABLE_GPU = buildParameters.enableGpu.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,14 @@ import { BuildParameters } from '..';
|
|||||||
class ValidateWindows {
|
class ValidateWindows {
|
||||||
public static validate(buildParameters: BuildParameters) {
|
public static validate(buildParameters: BuildParameters) {
|
||||||
ValidateWindows.validateWindowsPlatformRequirements(buildParameters.targetPlatform);
|
ValidateWindows.validateWindowsPlatformRequirements(buildParameters.targetPlatform);
|
||||||
if (!(process.env.UNITY_EMAIL && process.env.UNITY_PASSWORD)) {
|
|
||||||
throw new Error(`Unity email and password must be set for Windows based builds to
|
const { unityLicensingServer } = buildParameters;
|
||||||
authenticate the license. Make sure to set them inside UNITY_EMAIL
|
const hasLicensingCredentials = process.env.UNITY_EMAIL && process.env.UNITY_PASSWORD;
|
||||||
|
const hasValidLicensingStrategy = hasLicensingCredentials || unityLicensingServer;
|
||||||
|
|
||||||
|
if (!hasValidLicensingStrategy) {
|
||||||
|
throw new Error(`Unity email and password or alternatively a Unity licensing server url must be set for
|
||||||
|
Windows based builds to authenticate the license. Make sure to set them inside UNITY_EMAIL
|
||||||
and UNITY_PASSWORD in Github Secrets and pass them into the environment.`);
|
and UNITY_PASSWORD in Github Secrets and pass them into the environment.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ class Platform {
|
|||||||
PS4: 'PS4',
|
PS4: 'PS4',
|
||||||
XboxOne: 'XboxOne',
|
XboxOne: 'XboxOne',
|
||||||
tvOS: 'tvOS',
|
tvOS: 'tvOS',
|
||||||
|
VisionOS: 'VisionOS',
|
||||||
Switch: 'Switch',
|
Switch: 'Switch',
|
||||||
|
|
||||||
// Unsupported
|
// Unsupported
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user