Compare commits
No commits in common. "main" and "v2.2.0" have entirely different histories.
|
@ -14,8 +14,7 @@
|
||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"jest/globals": true,
|
"jest/globals": true
|
||||||
"es2020": true
|
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
// Error out for code formatting errors
|
// Error out for code formatting errors
|
||||||
|
@ -39,21 +38,9 @@
|
||||||
// Mandatory spacing
|
// Mandatory spacing
|
||||||
"padding-line-between-statements": [
|
"padding-line-between-statements": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{ "blankLine": "always", "prev": "*", "next": "return" },
|
||||||
"blankLine": "always",
|
{ "blankLine": "always", "prev": "directive", "next": "*" },
|
||||||
"prev": "*",
|
{ "blankLine": "any", "prev": "directive", "next": "directive" }
|
||||||
"next": "return"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blankLine": "always",
|
|
||||||
"prev": "directive",
|
|
||||||
"next": "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blankLine": "any",
|
|
||||||
"prev": "directive",
|
|
||||||
"next": "directive"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
// Enforce camelCase
|
// Enforce camelCase
|
||||||
"camelcase": "error",
|
"camelcase": "error",
|
||||||
|
@ -66,17 +53,8 @@
|
||||||
// Unused vars are useful to keep method signatures consistent and documented
|
// Unused vars are useful to keep method signatures consistent and documented
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
// For this project only use kebab-case
|
// For this project only use kebab-case
|
||||||
"unicorn/filename-case": [
|
"unicorn/filename-case": ["error", { "cases": { "kebabCase": true } }],
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"cases": {
|
|
||||||
"kebabCase": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
// Allow Array.from(set) mitigate TS2569 which would require '--downlevelIteration'
|
// Allow Array.from(set) mitigate TS2569 which would require '--downlevelIteration'
|
||||||
"unicorn/prefer-spread": "off",
|
"unicorn/prefer-spread": "off"
|
||||||
// Temp disable to prevent mixing changes with other PRs
|
|
||||||
"i18n-text/no-en": "off"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,28 +2,11 @@
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
#### 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 a PR
|
|
||||||
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)
|
||||||
|
|
|
@ -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@v4
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.requestActivationFile.outputs.filePath }}
|
name: ${{ steps.requestActivationFile.outputs.filePath }}
|
||||||
path: ${{ steps.requestActivationFile.outputs.filePath }}
|
path: ${{ steps.requestActivationFile.outputs.filePath }}
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
name: Builds - MacOS
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
buildForAllPlatformsMacOS:
|
|
||||||
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
|
||||||
runs-on: macos-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
projectPath:
|
|
||||||
- test-project
|
|
||||||
unityVersion:
|
|
||||||
- 2021.3.45f1
|
|
||||||
- 2022.3.13f1
|
|
||||||
- 2023.2.2f1
|
|
||||||
targetPlatform:
|
|
||||||
- StandaloneOSX # Build a MacOS executable
|
|
||||||
- iOS # Build an iOS executable
|
|
||||||
include:
|
|
||||||
# Additionally test enableGpu build for a standalone windows target
|
|
||||||
- unityVersion: 6000.0.36f1
|
|
||||||
targetPlatform: StandaloneOSX
|
|
||||||
- unityVersion: 6000.0.36f1
|
|
||||||
targetPlatform: StandaloneOSX
|
|
||||||
buildProfile: 'Assets/Settings/Build Profiles/Sample macOS Build Profile.asset'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
###########################
|
|
||||||
# Checkout #
|
|
||||||
###########################
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Cache #
|
|
||||||
###########################
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ matrix.projectPath }}/Library
|
|
||||||
key: Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
|
|
||||||
restore-keys: |
|
|
||||||
Library-${{ matrix.projectPath }}-macos-
|
|
||||||
Library-
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Set Scripting Backend #
|
|
||||||
###########################
|
|
||||||
- name: Set Scripting Backend To il2cpp
|
|
||||||
run: |
|
|
||||||
mv -f "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" "./test-project/ProjectSettings/ProjectSettings.asset"
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Build #
|
|
||||||
###########################
|
|
||||||
- uses: ./
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
buildName: 'GameCI Test Build'
|
|
||||||
projectPath: ${{ matrix.projectPath }}
|
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
buildProfile: ${{ matrix.buildProfile }}
|
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
|
||||||
allowDirtyBuild: true
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Upload #
|
|
||||||
###########################
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Build ${{ matrix.targetPlatform }} on MacOS (${{ matrix.unityVersion }})${{ matrix.buildProfile && ' With Build Profile' || '' }}
|
|
||||||
path: build
|
|
||||||
retention-days: 14
|
|
|
@ -1,151 +0,0 @@
|
||||||
name: Builds - Windows
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
buildForAllPlatformsWindows:
|
|
||||||
name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
|
|
||||||
runs-on: windows-2022
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
projectPath:
|
|
||||||
- test-project
|
|
||||||
unityVersion:
|
|
||||||
- 2021.3.32f1
|
|
||||||
- 2022.3.13f1
|
|
||||||
- 2023.2.2f1
|
|
||||||
targetPlatform:
|
|
||||||
- Android # Build an Android apk.
|
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
|
||||||
- WSAPlayer # Build a UWP App
|
|
||||||
- tvOS # Build an Apple TV XCode project
|
|
||||||
enableGpu:
|
|
||||||
- false
|
|
||||||
include:
|
|
||||||
# Additionally test enableGpu build for a standalone windows target
|
|
||||||
- projectPath: test-project
|
|
||||||
unityVersion: 2023.2.2f1
|
|
||||||
targetPlatform: StandaloneWindows64
|
|
||||||
enableGpu: true
|
|
||||||
- unityVersion: 6000.0.36f1
|
|
||||||
targetPlatform: StandaloneWindows64
|
|
||||||
- unityVersion: 6000.0.36f1
|
|
||||||
targetPlatform: StandaloneWindows64
|
|
||||||
buildProfile: 'Assets/Settings/Build Profiles/Sample Windows Build Profile.asset'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
###########################
|
|
||||||
# Checkout #
|
|
||||||
###########################
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Cache #
|
|
||||||
###########################
|
|
||||||
- uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ matrix.projectPath }}/Library
|
|
||||||
key: Library-${{ matrix.projectPath }}-windows-${{ matrix.targetPlatform }}
|
|
||||||
restore-keys: |
|
|
||||||
Library-${{ matrix.projectPath }}-windows-
|
|
||||||
Library-
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Set Scripting Backend #
|
|
||||||
###########################
|
|
||||||
- name: Set Scripting Backend To il2cpp
|
|
||||||
run: |
|
|
||||||
Move-Item -Path "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" -Destination "./test-project/ProjectSettings/ProjectSettings.asset" -Force
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Build #
|
|
||||||
###########################
|
|
||||||
- name: Build
|
|
||||||
uses: ./
|
|
||||||
id: build-1
|
|
||||||
continue-on-error: true
|
|
||||||
timeout-minutes: 30
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
buildName: 'GameCI Test Build'
|
|
||||||
projectPath: ${{ matrix.projectPath }}
|
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
buildProfile: ${{ matrix.buildProfile }}
|
|
||||||
enableGpu: ${{ matrix.enableGpu }}
|
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
|
||||||
allowDirtyBuild: true
|
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
|
||||||
|
|
||||||
- name: Sleep for Retry
|
|
||||||
if: ${{ steps.build-1.outcome == 'failure' }}
|
|
||||||
run: |
|
|
||||||
Start-Sleep -s 120
|
|
||||||
|
|
||||||
- name: Build Retry 1
|
|
||||||
uses: ./
|
|
||||||
id: build-2
|
|
||||||
continue-on-error: true
|
|
||||||
timeout-minutes: 30
|
|
||||||
if: steps.build-1.outcome == 'failure'
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
buildName: 'GameCI Test Build'
|
|
||||||
projectPath: ${{ matrix.projectPath }}
|
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
enableGpu: ${{ matrix.enableGpu }}
|
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
|
||||||
allowDirtyBuild: true
|
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
|
||||||
|
|
||||||
- name: Sleep for Retry
|
|
||||||
if: ${{ steps.build-1.outcome == 'failure' && steps.build-2.outcome == 'failure' }}
|
|
||||||
run: |
|
|
||||||
Start-Sleep -s 240
|
|
||||||
|
|
||||||
- name: Build Retry 2
|
|
||||||
uses: ./
|
|
||||||
id: build-3
|
|
||||||
timeout-minutes: 30
|
|
||||||
if: ${{ steps.build-1.outcome == 'failure' && steps.build-2.outcome == 'failure' }}
|
|
||||||
env:
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
buildName: 'GameCI Test Build'
|
|
||||||
projectPath: ${{ matrix.projectPath }}
|
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
enableGpu: ${{ matrix.enableGpu }}
|
|
||||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
|
||||||
allowDirtyBuild: true
|
|
||||||
# We use dirty build because we are replacing the default project settings file above
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Upload #
|
|
||||||
###########################
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Build ${{ matrix.targetPlatform }} on Windows (${{ matrix.unityVersion }})${{ matrix.enableGpu && ' With GPU' || '' }}${{ matrix.buildProfile && ' With Build Profile' || '' }}
|
|
||||||
path: build
|
|
||||||
retention-days: 14
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
name: Builds
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push: { branches: [main] }
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- '.github/**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE:
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License
|
||||||
|
id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\"
|
||||||
|
Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\"
|
||||||
|
Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID
|
||||||
|
Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash
|
||||||
|
Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\n <Features>\n <Feature
|
||||||
|
Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature
|
||||||
|
Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature
|
||||||
|
Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature
|
||||||
|
Value=\"62\"/>\n </Features>\n <DeveloperData
|
||||||
|
Value=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked
|
||||||
|
Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate
|
||||||
|
Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate
|
||||||
|
Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion
|
||||||
|
Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement
|
||||||
|
Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\"
|
||||||
|
ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\"
|
||||||
|
Type=\"EDITOR_FEATURE\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature
|
||||||
|
xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod
|
||||||
|
Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
buildForAllPlatformsUbuntu:
|
||||||
|
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cloudRunnerCluster:
|
||||||
|
# - local-docker
|
||||||
|
- local
|
||||||
|
projectPath:
|
||||||
|
- test-project
|
||||||
|
unityVersion:
|
||||||
|
- 2018.3.14f1
|
||||||
|
- 2018.4.36f1
|
||||||
|
- 2019.1.14f1
|
||||||
|
- 2019.2.21f1
|
||||||
|
- 2019.3.15f1
|
||||||
|
- 2019.4.40f1
|
||||||
|
- 2020.1.17f1
|
||||||
|
- 2020.2.7f1
|
||||||
|
- 2020.3.44f1
|
||||||
|
- 2021.1.28f1
|
||||||
|
- 2021.2.19f1
|
||||||
|
- 2021.3.18f1
|
||||||
|
- 2022.1.24f1
|
||||||
|
- 2022.2.6f1
|
||||||
|
targetPlatform:
|
||||||
|
- StandaloneOSX # Build a macOS standalone (Intel 64-bit) with mono backend.
|
||||||
|
- StandaloneWindows64 # Build a Windows 64-bit standalone with mono backend.
|
||||||
|
- StandaloneLinux64 # Build a Linux 64-bit standalone with mono backend.
|
||||||
|
- iOS # Build an iOS player.
|
||||||
|
- Android # Build an Android .apk.
|
||||||
|
- WebGL # WebGL.
|
||||||
|
# - StandaloneWindows # Build a Windows standalone.
|
||||||
|
# - WSAPlayer # Build an Windows Store Apps player.
|
||||||
|
# - PS4 # Build a PS4 Standalone.
|
||||||
|
# - XboxOne # Build a Xbox One Standalone.
|
||||||
|
# - tvOS # Build to Apple's tvOS platform.
|
||||||
|
# - Switch # Build a Nintendo Switch player
|
||||||
|
steps:
|
||||||
|
###########################
|
||||||
|
# Checkout #
|
||||||
|
###########################
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Cache #
|
||||||
|
###########################
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ${{ matrix.projectPath }}/Library
|
||||||
|
key: Library-${{ matrix.projectPath }}-ubuntu-${{ matrix.targetPlatform }}
|
||||||
|
restore-keys: |
|
||||||
|
Library-${{ matrix.projectPath }}-ubuntu-
|
||||||
|
Library-
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Build #
|
||||||
|
###########################
|
||||||
|
- uses: ./
|
||||||
|
with:
|
||||||
|
projectPath: ${{ matrix.projectPath }}
|
||||||
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
|
cloudRunnerCluster: ${{ matrix.cloudRunnerCluster }}
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Upload #
|
||||||
|
###########################
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Build Ubuntu (${{ matrix.unityVersion }})
|
||||||
|
path: build
|
||||||
|
retention-days: 14
|
|
@ -15,13 +15,13 @@ jobs:
|
||||||
cleanupCloudRunner:
|
cleanupCloudRunner:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
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@v4
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: 16.x
|
||||||
- run: yarn
|
- run: yarn
|
||||||
- run: yarn run cli --help
|
- run: yarn run cli --help
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -23,7 +23,7 @@ env:
|
||||||
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_DEFAULT_REGION: eu-west-2
|
AWS_DEFAULT_REGION: eu-west-2
|
||||||
AWS_STACK_NAME: game-ci-github-pipelines
|
AWS_BASE_STACK_NAME: game-ci-github-pipelines
|
||||||
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
||||||
CLOUD_RUNNER_DEBUG: true
|
CLOUD_RUNNER_DEBUG: true
|
||||||
CLOUD_RUNNER_DEBUG_TREE: true
|
CLOUD_RUNNER_DEBUG_TREE: true
|
||||||
|
@ -39,21 +39,20 @@ jobs:
|
||||||
if: github.event.event_type != 'pull_request_target'
|
if: github.event.event_type != 'pull_request_target'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- timeout-minutes: 180
|
- name: Checkout (default)
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn run cli -m checks-update
|
||||||
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
PROJECT_PATH: test-project
|
PROJECT_PATH: test-project
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
GIT_PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
TARGET_PLATFORM: StandaloneWindows64
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
cloudRunnerTests: true
|
cloudRunnerTests: true
|
||||||
versioning: None
|
versioning: None
|
||||||
CLOUD_RUNNER_CLUSTER: local-docker
|
CLOUD_RUNNER_CLUSTER: local-docker
|
||||||
AWS_STACK_NAME: game-ci-github-pipelines
|
AWS_BASE_STACK_NAME: game-ci-github-pipelines
|
||||||
CHECKS_UPDATE: ${{ github.event.inputs.checksObject }}
|
CHECKS_UPDATE: ${{ github.event.inputs.checksObject }}
|
||||||
run: |
|
|
||||||
git clone -b cloud-runner-develop https://github.com/game-ci/unity-builder
|
|
||||||
cd unity-builder
|
|
||||||
yarn
|
|
||||||
ls
|
|
||||||
yarn run cli -m checks-update
|
|
||||||
|
|
|
@ -1,231 +0,0 @@
|
||||||
name: Cloud Runner CI Pipeline
|
|
||||||
|
|
||||||
on:
|
|
||||||
push: { branches: [cloud-runner-develop, cloud-runner-preview, main] }
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
runGithubIntegrationTests:
|
|
||||||
description: 'Run GitHub Checks integration tests'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
checks: write
|
|
||||||
contents: read
|
|
||||||
actions: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GKE_ZONE: 'us-central1'
|
|
||||||
GKE_REGION: 'us-central1'
|
|
||||||
GKE_PROJECT: 'unitykubernetesbuilder'
|
|
||||||
GKE_CLUSTER: 'game-ci-github-pipelines'
|
|
||||||
GCP_LOGGING: true
|
|
||||||
GCP_PROJECT: unitykubernetesbuilder
|
|
||||||
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
|
||||||
AWS_REGION: eu-west-2
|
|
||||||
AWS_DEFAULT_REGION: eu-west-2
|
|
||||||
AWS_STACK_NAME: game-ci-team-pipelines
|
|
||||||
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
|
||||||
DEBUG: true
|
|
||||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
|
||||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
|
||||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
|
||||||
PROJECT_PATH: test-project
|
|
||||||
UNITY_VERSION: 2019.3.15f1
|
|
||||||
USE_IL2CPP: false
|
|
||||||
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
tests:
|
|
||||||
name: Tests
|
|
||||||
if: github.event.event_type != 'pull_request_target'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test:
|
|
||||||
- 'cloud-runner-end2end-locking'
|
|
||||||
- 'cloud-runner-end2end-caching'
|
|
||||||
- 'cloud-runner-end2end-retaining'
|
|
||||||
- 'cloud-runner-caching'
|
|
||||||
- 'cloud-runner-environment'
|
|
||||||
- 'cloud-runner-image'
|
|
||||||
- 'cloud-runner-hooks'
|
|
||||||
- 'cloud-runner-local-persistence'
|
|
||||||
- 'cloud-runner-locking-core'
|
|
||||||
- 'cloud-runner-locking-get-locked'
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- name: Configure AWS Credentials
|
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
|
||||||
with:
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
aws-region: eu-west-2
|
|
||||||
- run: yarn
|
|
||||||
- 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: local-docker
|
|
||||||
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 }}
|
|
||||||
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'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test:
|
|
||||||
- 'cloud-runner-end2end-locking'
|
|
||||||
- 'cloud-runner-end2end-caching'
|
|
||||||
- 'cloud-runner-end2end-retaining'
|
|
||||||
- 'cloud-runner-environment'
|
|
||||||
- 'cloud-runner-s3-steps'
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- name: Configure AWS Credentials
|
|
||||||
uses: aws-actions/configure-aws-credentials@v1
|
|
||||||
with:
|
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
aws-region: eu-west-2
|
|
||||||
- run: yarn
|
|
||||||
- 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: 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:
|
|
||||||
name: Local Build Target Tests
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
providerStrategy:
|
|
||||||
#- aws
|
|
||||||
- local-docker
|
|
||||||
#- k8s
|
|
||||||
targetPlatform:
|
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
|
||||||
- WebGL # WebGL.
|
|
||||||
- iOS # Build an iOS player.
|
|
||||||
# - Android # Build an Android .apk.
|
|
||||||
steps:
|
|
||||||
- name: Checkout (default)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
lfs: false
|
|
||||||
- run: yarn
|
|
||||||
- uses: ./
|
|
||||||
id: unity-build
|
|
||||||
timeout-minutes: 30
|
|
||||||
env:
|
|
||||||
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:
|
|
||||||
cloudRunnerTests: true
|
|
||||||
versioning: None
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
|
||||||
- run: |
|
|
||||||
cp ./cloud-runner-cache/cache/${{ steps.unity-build.outputs.CACHE_KEY }}/build/${{ steps.unity-build.outputs.BUILD_ARTIFACT }} ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.providerStrategy }} Build (${{ matrix.targetPlatform }})
|
|
||||||
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
|
||||||
retention-days: 14
|
|
||||||
|
|
||||||
githubChecksIntegration:
|
|
||||||
name: GitHub Checks Integration
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.runGithubIntegrationTests == 'true'
|
|
||||||
env:
|
|
||||||
RUN_GITHUB_INTEGRATION_TESTS: true
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 20
|
|
||||||
cache: 'yarn'
|
|
||||||
- run: yarn install --frozen-lockfile
|
|
||||||
- run: yarn test cloud-runner-github-checks-integration-test --detectOpenHandles --forceExit --runInBand
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
name: Cloud Runner CI Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push: { branches: [cloud-runner-develop, cloud-runner-preview, main] }
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
|
contents: read
|
||||||
|
actions: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
GKE_ZONE: 'us-central1'
|
||||||
|
GKE_REGION: 'us-central1'
|
||||||
|
GKE_PROJECT: 'unitykubernetesbuilder'
|
||||||
|
GKE_CLUSTER: 'game-ci-github-pipelines'
|
||||||
|
GCP_LOGGING: true
|
||||||
|
GCP_PROJECT: unitykubernetesbuilder
|
||||||
|
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
|
||||||
|
AWS_REGION: eu-west-2
|
||||||
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
AWS_DEFAULT_REGION: eu-west-2
|
||||||
|
AWS_BASE_STACK_NAME: game-ci-team-pipelines
|
||||||
|
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
|
||||||
|
CLOUD_RUNNER_DEBUG: true
|
||||||
|
CLOUD_RUNNER_DEBUG_TREE: true
|
||||||
|
DEBUG: true
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
PROJECT_PATH: test-project
|
||||||
|
UNITY_VERSION: 2019.3.15f1
|
||||||
|
USE_IL2CPP: false
|
||||||
|
USE_GKE_GCLOUD_AUTH_PLUGIN: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
integrationTests:
|
||||||
|
name: Integration Tests
|
||||||
|
if: github.event.event_type != 'pull_request_target'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cloudRunnerCluster:
|
||||||
|
- aws
|
||||||
|
- local-docker
|
||||||
|
- k8s
|
||||||
|
steps:
|
||||||
|
- name: Checkout (default)
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
- uses: google-github-actions/auth@v1
|
||||||
|
with:
|
||||||
|
credentials_json: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
|
||||||
|
- name: 'Set up Cloud SDK'
|
||||||
|
uses: 'google-github-actions/setup-gcloud@v1'
|
||||||
|
- name: Get GKE cluster credentials
|
||||||
|
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
|
||||||
|
- name: Configure AWS Credentials
|
||||||
|
uses: aws-actions/configure-aws-credentials@v1
|
||||||
|
with:
|
||||||
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
aws-region: eu-west-2
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn run test "cloud-runner-async-workflow" --detectOpenHandles --forceExit --runInBand
|
||||||
|
if: matrix.CloudRunnerCluster != 'local-docker'
|
||||||
|
timeout-minutes: 180
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
PROJECT_PATH: test-project
|
||||||
|
GIT_PRIVATE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
|
cloudRunnerTests: true
|
||||||
|
versioning: None
|
||||||
|
CLOUD_RUNNER_CLUSTER: ${{ matrix.cloudRunnerCluster }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- run: yarn run test-i --detectOpenHandles --forceExit --runInBand
|
||||||
|
if: matrix.CloudRunnerCluster == 'local-docker'
|
||||||
|
timeout-minutes: 180
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
PROJECT_PATH: test-project
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TARGET_PLATFORM: StandaloneWindows64
|
||||||
|
cloudRunnerTests: true
|
||||||
|
versioning: None
|
||||||
|
CLOUD_RUNNER_CLUSTER: ${{ matrix.cloudRunnerCluster }}
|
||||||
|
localBuildTests:
|
||||||
|
name: Local Build Target Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
cloudRunnerCluster:
|
||||||
|
#- aws
|
||||||
|
- local-docker
|
||||||
|
#- k8s
|
||||||
|
targetPlatform:
|
||||||
|
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
||||||
|
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||||
|
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
||||||
|
- WebGL # WebGL.
|
||||||
|
- iOS # Build an iOS player.
|
||||||
|
- Android # Build an Android .apk.
|
||||||
|
steps:
|
||||||
|
- name: Checkout (default)
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: false
|
||||||
|
- run: yarn
|
||||||
|
- uses: ./
|
||||||
|
id: unity-build
|
||||||
|
timeout-minutes: 90
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||||
|
with:
|
||||||
|
cloudRunnerTests: true
|
||||||
|
versioning: None
|
||||||
|
projectPath: test-project
|
||||||
|
gitPrivateToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
cloudRunnerCluster: ${{ matrix.cloudRunnerCluster }}
|
||||||
|
- run: |
|
||||||
|
cp ./cloud-runner-cache/cache/${{ steps.unity-build.outputs.CACHE_KEY }}/build/${{ steps.unity-build.outputs.BUILD_ARTIFACT }} ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.cloudRunnerCluster }} Build (${{ matrix.targetPlatform }})
|
||||||
|
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
|
||||||
|
retention-days: 14
|
|
@ -7,19 +7,15 @@ on:
|
||||||
env:
|
env:
|
||||||
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
|
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: Tests
|
name: Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '16'
|
||||||
- run: yarn
|
- run: yarn
|
||||||
- run: yarn lint
|
- run: yarn lint
|
||||||
- run: yarn test --coverage
|
- run: yarn test --coverage
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
name: Mac Builds
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE:
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License
|
||||||
|
id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\"
|
||||||
|
Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\"
|
||||||
|
Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID
|
||||||
|
Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash
|
||||||
|
Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\n <Features>\n <Feature
|
||||||
|
Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature
|
||||||
|
Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature
|
||||||
|
Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature
|
||||||
|
Value=\"62\"/>\n </Features>\n <DeveloperData
|
||||||
|
Value=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked
|
||||||
|
Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate
|
||||||
|
Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate
|
||||||
|
Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion
|
||||||
|
Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement
|
||||||
|
Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\"
|
||||||
|
ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\"
|
||||||
|
Type=\"EDITOR_FEATURE\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature
|
||||||
|
xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod
|
||||||
|
Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod
|
||||||
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
buildForAllPlatformsWindows:
|
||||||
|
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
|
runs-on: macos-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
projectPath:
|
||||||
|
- test-project
|
||||||
|
unityVersion:
|
||||||
|
- 2019.4.40f1 # Minimum version for IL2CPP
|
||||||
|
- 2020.1.17f1
|
||||||
|
- 2020.2.7f1
|
||||||
|
- 2020.3.44f1
|
||||||
|
- 2021.1.28f1
|
||||||
|
- 2021.2.19f1
|
||||||
|
- 2021.3.18f1
|
||||||
|
- 2022.1.24f1
|
||||||
|
- 2022.2.6f1
|
||||||
|
targetPlatform:
|
||||||
|
- StandaloneOSX # Build a MacOS executable
|
||||||
|
|
||||||
|
steps:
|
||||||
|
###########################
|
||||||
|
# Checkout #
|
||||||
|
###########################
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Cache #
|
||||||
|
###########################
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ${{ matrix.projectPath }}/Library
|
||||||
|
key: Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
|
||||||
|
restore-keys: |
|
||||||
|
Library-${{ matrix.projectPath }}-macos-
|
||||||
|
Library-
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Set Scripting Backend #
|
||||||
|
###########################
|
||||||
|
- name: Set Scripting Backend To il2cpp
|
||||||
|
run: |
|
||||||
|
mv -f "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" "./test-project/ProjectSettings/ProjectSettings.asset"
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Build #
|
||||||
|
###########################
|
||||||
|
- uses: ./
|
||||||
|
env:
|
||||||
|
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||||
|
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||||
|
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||||
|
with:
|
||||||
|
projectPath: ${{ matrix.projectPath }}
|
||||||
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
|
allowDirtyBuild: true
|
||||||
|
|
||||||
|
###########################
|
||||||
|
# Upload #
|
||||||
|
###########################
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Build MacOS (${{ matrix.unityVersion }})
|
||||||
|
path: build
|
||||||
|
retention-days: 14
|
|
@ -1,12 +1,10 @@
|
||||||
name: Builds - Ubuntu
|
name: Windows Builds
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
concurrency:
|
- main
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE:
|
UNITY_LICENSE:
|
||||||
|
@ -35,100 +33,54 @@ env:
|
||||||
Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
buildForAllPlatformsUbuntu:
|
buildForAllPlatformsWindows:
|
||||||
name:
|
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
"${{ matrix.targetPlatform }} on ${{ matrix.unityVersion}}${{startsWith(matrix.buildProfile, 'Assets') && ' (via Build Profile)' || '' }}"
|
runs-on: windows-2019
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
providerStrategy:
|
|
||||||
# - local-docker
|
|
||||||
- local
|
|
||||||
projectPath:
|
projectPath:
|
||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2021.3.32f1
|
- 2019.3.15f1 # Minimum version for IL2CPP
|
||||||
- 2022.3.13f1
|
- 2019.4.40f1
|
||||||
- 2023.2.2f1
|
- 2020.1.17f1
|
||||||
|
- 2020.2.7f1
|
||||||
|
- 2020.3.44f1
|
||||||
|
- 2021.3.18f1 # 2021.1 and 2021.2 seem to have IL2CPP issues
|
||||||
|
- 2022.1.24f1
|
||||||
|
- 2022.2.6f1
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit) with mono backend.
|
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone with mono backend.
|
- StandaloneWindows # Build a Windows 32-bit standalone.
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone with mono/il2cpp backend.
|
- WSAPlayer # Build a UWP App
|
||||||
- iOS # Build an iOS project.
|
- tvOS # Build an Apple TV XCode project
|
||||||
- Android # Build an Android .apk.
|
|
||||||
- WebGL # WebGL.
|
|
||||||
buildWithIl2cpp:
|
|
||||||
- false
|
|
||||||
- true
|
|
||||||
additionalParameters:
|
|
||||||
- -param value
|
|
||||||
- -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@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
lfs: true
|
lfs: true
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Cache #
|
# Cache #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ matrix.projectPath }}/Library
|
path: ${{ matrix.projectPath }}/Library
|
||||||
key: Library-${{ matrix.projectPath }}-ubuntu-${{ matrix.targetPlatform }}
|
key: Library-${{ matrix.projectPath }}-windows-${{ matrix.targetPlatform }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
Library-${{ matrix.projectPath }}-ubuntu-
|
Library-${{ matrix.projectPath }}-windows-
|
||||||
Library-
|
Library-
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Set Scripting Backend #
|
# Set Scripting Backend #
|
||||||
###########################
|
###########################
|
||||||
- name: Set Scripting Backend To il2cpp
|
- name: Set Scripting Backend To il2cpp
|
||||||
if: matrix.buildWithIl2cpp == true
|
|
||||||
run: |
|
run: |
|
||||||
mv -f "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" "./test-project/ProjectSettings/ProjectSettings.asset"
|
Move-Item -Path "./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset" -Destination "./test-project/ProjectSettings/ProjectSettings.asset" -Force
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Build #
|
# Build #
|
||||||
|
@ -137,70 +89,69 @@ jobs:
|
||||||
uses: ./
|
uses: ./
|
||||||
id: build-1
|
id: build-1
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
timeout-minutes: 60
|
||||||
env:
|
env:
|
||||||
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 }}
|
||||||
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 ${{ matrix.additionalParameters }}
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
|
|
||||||
- name: Sleep for Retry
|
- name: Sleep for Retry
|
||||||
if: ${{ steps.build-1.outcome == 'failure' }}
|
if: ${{ steps.build-1.outcome == 'failure' }}
|
||||||
run: |
|
run: |
|
||||||
sleep 60
|
Start-Sleep -s 120
|
||||||
|
|
||||||
- name: Build (Retry 1)
|
- name: Build Retry 1
|
||||||
uses: ./
|
uses: ./
|
||||||
id: build-2
|
id: build-2
|
||||||
if: ${{ steps.build-1.outcome == 'failure' }}
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
timeout-minutes: 60
|
||||||
|
if: steps.build-1.outcome == 'failure'
|
||||||
env:
|
env:
|
||||||
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 }}
|
||||||
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 ${{ matrix.additionalParameters }}
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
|
|
||||||
- name: Sleep for Retry
|
- name: Sleep for Retry
|
||||||
if: ${{ steps.build-2.outcome == 'failure' }}
|
if: ${{ steps.build-1.outcome == 'failure' && steps.build-2.outcome == 'failure' }}
|
||||||
run: |
|
run: |
|
||||||
sleep 240
|
Start-Sleep -s 240
|
||||||
|
|
||||||
- name: Build (Retry 2)
|
- name: Build Retry 2
|
||||||
uses: ./
|
uses: ./
|
||||||
id: build-3
|
id: build-3
|
||||||
if: ${{ steps.build-2.outcome == 'failure' }}
|
timeout-minutes: 60
|
||||||
|
if: ${{ steps.build-1.outcome == 'failure' && steps.build-2.outcome == 'failure' }}
|
||||||
env:
|
env:
|
||||||
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 }}
|
||||||
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 ${{ matrix.additionalParameters }}
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
providerStrategy: ${{ matrix.providerStrategy }}
|
|
||||||
allowDirtyBuild: true
|
allowDirtyBuild: true
|
||||||
|
# We use dirty build because we are replacing the default project settings file above
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
# Upload #
|
# Upload #
|
||||||
###########################
|
###########################
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name:
|
name: Build Windows (${{ matrix.unityVersion }})
|
||||||
"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
|
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "PowerShell Launch Current File",
|
|
||||||
"type": "PowerShell",
|
|
||||||
"request": "launch",
|
|
||||||
"script": "${file}",
|
|
||||||
"cwd": "${cwd}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug Jest Test",
|
|
||||||
"program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
|
|
||||||
"args": [
|
|
||||||
"--collectCoverage=false",
|
|
||||||
"--colors",
|
|
||||||
"--config",
|
|
||||||
"${workspaceRoot}/jest.config.js",
|
|
||||||
"--runInBand",
|
|
||||||
"--runTestsByPath",
|
|
||||||
"${relativeFile}",
|
|
||||||
"--testPathPattern=${fileDirname}",
|
|
||||||
"--testTimeout=10000000"
|
|
||||||
],
|
|
||||||
"outputCapture": "std",
|
|
||||||
"internalConsoleOptions": "openOnSessionStart",
|
|
||||||
"envFile": "${workspaceRoot}/.env",
|
|
||||||
"skipFiles": ["${workspaceRoot}/../../node_modules/**/*", "<node_internals>/**/*"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -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 v18+ and [Yarn](https://yarnpkg.com/) at v1.22.0+.
|
You have [Node](https://nodejs.org/) installed at v12.2.0+ and [Yarn](https://yarnpkg.com/) at v1.18.0+.
|
||||||
|
|
||||||
Please note that commit hooks will run automatically to perform some tasks;
|
Please note that commit hooks will run automatically to perform some tasks;
|
||||||
|
|
||||||
|
@ -36,8 +36,7 @@ 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. This is because some tests require you to be able to run `sh` and other
|
`Git's Unix tools for Windows` installed. Some tests require you to be able to run `sh` and other unix commands.
|
||||||
unix commands.
|
|
||||||
|
|
||||||
#### License
|
#### License
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,8 @@ Part of the <a href="https://game.ci">GameCI</a> open source project.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
[](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-ubuntu.yml)
|
[](https://github.com/game-ci/unity-builder/actions?query=branch%3Amain+event%3Apush+workflow%3A%22Builds)
|
||||||
[](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-windows.yml)
|
[](https://lgtm.com/projects/g/webbertakken/unity-builder/context:javascript)
|
||||||
[](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-mac.yml)
|
|
||||||
[](https://codecov.io/gh/game-ci/unity-builder)
|
[](https://codecov.io/gh/game-ci/unity-builder)
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
90
action.yml
90
action.yml
|
@ -18,11 +18,7 @@ inputs:
|
||||||
projectPath:
|
projectPath:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Path to the project to be built, relative to the repository root.'
|
description: 'Relative path to the project to be built.'
|
||||||
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: ''
|
||||||
|
@ -35,14 +31,6 @@ 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: ''
|
||||||
|
@ -59,9 +47,12 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'The android versionCode'
|
description: 'The android versionCode'
|
||||||
|
androidAppBundle:
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
description: '[Deprecated] Use androidExportType instead. Whether to build .aab instead of .apk'
|
||||||
androidExportType:
|
androidExportType:
|
||||||
required: false
|
required: false
|
||||||
default: 'androidPackage'
|
|
||||||
description:
|
description:
|
||||||
'The android export type. Should be androidPackage for apk, androidAppBundle for aab, or androidStudioProject for
|
'The android export type. Should be androidPackage for apk, androidAppBundle for aab, or androidStudioProject for
|
||||||
an android studio project.'
|
an android studio project.'
|
||||||
|
@ -95,12 +86,8 @@ inputs:
|
||||||
description: 'The android symbol type to export. Should be "none", "public" or "debugging".'
|
description: 'The android symbol type to export. Should be "none", "public" or "debugging".'
|
||||||
sshAgent:
|
sshAgent:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: 'public'
|
||||||
description: 'SSH Agent path to forward to the container'
|
description: 'SSH Agent path to forward to the container'
|
||||||
sshPublicKeysDirectoryPath:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description: 'Path to a directory containing SSH public keys to forward to the container.'
|
|
||||||
gitPrivateToken:
|
gitPrivateToken:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
|
@ -109,43 +96,11 @@ 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: ''
|
||||||
|
@ -162,7 +117,7 @@ inputs:
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Run a pre build job after the repository setup but before the build job (in yaml format with the
|
'[CloudRunner] Run a pre build job after the repository setup but before the build job (in yaml format with the
|
||||||
keys image, secrets (name, value object array), command line string)'
|
keys image, secrets (name, value object array), command line string)'
|
||||||
containerHookFiles:
|
customStepFiles:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description:
|
description:
|
||||||
|
@ -174,7 +129,7 @@ inputs:
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Specify the names (by file name) of custom hooks to run before or after cloud runner jobs, must
|
'[CloudRunner] Specify the names (by file name) of custom hooks to run before or after cloud runner jobs, must
|
||||||
match a yaml step file inside your repo in the folder .game-ci/hooks/'
|
match a yaml step file inside your repo in the folder .game-ci/hooks/'
|
||||||
customCommandHooks:
|
customJobHooks:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: '[CloudRunner] Specify custom commands and trigger hooks (injects commands into jobs)'
|
description: '[CloudRunner] Specify custom commands and trigger hooks (injects commands into jobs)'
|
||||||
|
@ -184,21 +139,21 @@ inputs:
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Run a custom job instead of the standard build automation for cloud runner (in yaml format with the
|
'[CloudRunner] Run a custom job instead of the standard build automation for cloud runner (in yaml format with the
|
||||||
keys image, secrets (name, value object array), command line string)'
|
keys image, secrets (name, value object array), command line string)'
|
||||||
awsStackName:
|
awsBaseStackName:
|
||||||
default: 'game-ci'
|
default: 'game-ci'
|
||||||
required: false
|
required: false
|
||||||
description: '[CloudRunner] The Cloud Formation stack name that must be setup before using this option.'
|
description: '[CloudRunner] The Cloud Formation stack name that must be setup before using this option.'
|
||||||
providerStrategy:
|
cloudRunnerCluster:
|
||||||
default: 'local'
|
default: 'local'
|
||||||
required: false
|
required: false
|
||||||
description:
|
description:
|
||||||
'[CloudRunner] Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must
|
'[CloudRunner] Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must
|
||||||
be configured.'
|
be configured.'
|
||||||
containerCpu:
|
cloudRunnerCpu:
|
||||||
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'
|
||||||
containerMemory:
|
cloudRunnerMemory:
|
||||||
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'
|
||||||
|
@ -251,20 +206,6 @@ inputs:
|
||||||
description:
|
description:
|
||||||
'The version of Unity Hub to install on MacOS (e.g. 3.4.0). Defaults to latest available on brew if empty string
|
'The version of Unity Hub to install on MacOS (e.g. 3.4.0). Defaults to latest available on brew if empty string
|
||||||
or nothing is specified.'
|
or nothing is specified.'
|
||||||
unityLicensingServer:
|
|
||||||
default: ''
|
|
||||||
required: false
|
|
||||||
description: 'The Unity licensing server address to use for activating Unity.'
|
|
||||||
dockerWorkspacePath:
|
|
||||||
default: '/github/workspace'
|
|
||||||
required: false
|
|
||||||
description:
|
|
||||||
'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'
|
|
||||||
skipActivation:
|
|
||||||
default: 'false'
|
|
||||||
required: false
|
|
||||||
description: 'Skip the activation/deactivation of Unity. This assumes Unity is already activated.'
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
volume:
|
volume:
|
||||||
|
@ -273,14 +214,9 @@ 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: 'node20'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"m_SettingKeys": [
|
||||||
|
"VR Device Disabled",
|
||||||
|
"VR Device User Alert"
|
||||||
|
],
|
||||||
|
"m_SettingValues": [
|
||||||
|
"False",
|
||||||
|
"False"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,709 @@
|
||||||
|
<?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,9 +6,6 @@ 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
|
||||||
|
@ -20,9 +17,36 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define BuildPlayer Options
|
||||||
|
var buildPlayerOptions = new BuildPlayerOptions {
|
||||||
|
scenes = scenes,
|
||||||
|
locationPathName = options["customBuildPath"],
|
||||||
|
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
|
||||||
|
options = buildOptions
|
||||||
|
};
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -39,89 +63,10 @@ namespace UnityBuilderAction
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError("Failed to run default addressables build:\n" + e);
|
Debug.LogError($"Failed to run default addressables build:\n{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all buildOptions from options
|
|
||||||
BuildOptions buildOptions = BuildOptions.None;
|
|
||||||
foreach (string buildOptionString in Enum.GetNames(typeof(BuildOptions))) {
|
|
||||||
if (options.ContainsKey(buildOptionString)) {
|
|
||||||
BuildOptions buildOptionEnum = (BuildOptions) Enum.Parse(typeof(BuildOptions), buildOptionString);
|
|
||||||
buildOptions |= buildOptionEnum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Depending on whether the build is using a build profile, `buildPlayerOptions` will an instance
|
|
||||||
// of either `UnityEditor.BuildPlayerOptions` or `UnityEditor.BuildPlayerWithProfileOptions`
|
|
||||||
dynamic buildPlayerOptions;
|
|
||||||
|
|
||||||
if (options.TryGetValue("activeBuildProfile", out var buildProfilePath)) {
|
|
||||||
if (string.IsNullOrEmpty(buildProfilePath)) {
|
|
||||||
throw new Exception("`-activeBuildProfile` is set but with an empty value; this shouldn't happen");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_6000_0_OR_NEWER
|
|
||||||
// Load build profile from Assets folder
|
|
||||||
var buildProfile = AssetDatabase.LoadAssetAtPath<BuildProfile>(buildProfilePath)
|
|
||||||
?? throw new Exception("Build profile file not found at path: " + buildProfilePath);
|
|
||||||
|
|
||||||
#if !BUILD_PROFILE_LOADED
|
|
||||||
throw new Exception("Build profile's define symbol not present before script execution; shouldn't happen");
|
|
||||||
#endif // BUILD_PROFILE_LOADED
|
|
||||||
|
|
||||||
// no need to set active profile, as already set by `-activeBuildProfile` CLI argument
|
|
||||||
// BuildProfile.SetActiveBuildProfile(buildProfile);
|
|
||||||
Debug.Log($"build profile: {buildProfile.name}");
|
|
||||||
|
|
||||||
// Define BuildPlayerWithProfileOptions
|
|
||||||
buildPlayerOptions = new BuildPlayerWithProfileOptions {
|
|
||||||
buildProfile = buildProfile,
|
|
||||||
locationPathName = options["customBuildPath"],
|
|
||||||
options = buildOptions,
|
|
||||||
};
|
|
||||||
#else // UNITY_6000_0_OR_NEWER
|
|
||||||
throw new Exception("Build profiles are not supported by this version of Unity (" + Application.unityVersion +")");
|
|
||||||
#endif // UNITY_6000_0_OR_NEWER
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
#if BUILD_PROFILE_LOADED
|
|
||||||
throw new Exception("Build profile's define symbol present; shouldn't happen");
|
|
||||||
#endif // BUILD_PROFILE_LOADED
|
|
||||||
|
|
||||||
// Gather values from project
|
|
||||||
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
|
|
||||||
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
|
||||||
// Determine subtarget
|
|
||||||
StandaloneBuildSubtarget buildSubtarget;
|
|
||||||
if (!options.TryGetValue("standaloneBuildSubtarget", out var subtargetValue) || !Enum.TryParse(subtargetValue, out buildSubtarget)) {
|
|
||||||
buildSubtarget = default;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BuildTarget buildTarget = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]);
|
|
||||||
|
|
||||||
// Define BuildPlayerOptions
|
|
||||||
buildPlayerOptions = new BuildPlayerOptions {
|
|
||||||
scenes = scenes,
|
|
||||||
locationPathName = options["customBuildPath"],
|
|
||||||
target = buildTarget,
|
|
||||||
options = buildOptions,
|
|
||||||
#if UNITY_2021_2_OR_NEWER
|
|
||||||
subtarget = (int) buildSubtarget
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply Android settings
|
|
||||||
if (buildTarget == BuildTarget.Android) {
|
|
||||||
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
|
|
||||||
AndroidSettings.Apply(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform build
|
// Perform build
|
||||||
BuildReport buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
BuildReport buildReport = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace UnityBuilderAction.Input
|
namespace UnityBuilderAction.Input
|
||||||
{
|
{
|
||||||
public static class AndroidSettings
|
public class AndroidSettings
|
||||||
{
|
{
|
||||||
public static void Apply(Dictionary<string, string> options)
|
public static void Apply(Dictionary<string, string> options)
|
||||||
{
|
{
|
||||||
|
@ -49,24 +49,24 @@ namespace UnityBuilderAction.Input
|
||||||
if (options.TryGetValue("androidExportType", out androidExportType) && !string.IsNullOrEmpty(androidExportType))
|
if (options.TryGetValue("androidExportType", out androidExportType) && !string.IsNullOrEmpty(androidExportType))
|
||||||
{
|
{
|
||||||
// Only exists in 2018.3 and above
|
// Only exists in 2018.3 and above
|
||||||
PropertyInfo buildAppBundle = typeof(EditorUserBuildSettings)
|
FieldInfo buildAppBundle = typeof(EditorUserBuildSettings)
|
||||||
.GetProperty("buildAppBundle", BindingFlags.Public | BindingFlags.Static);
|
.GetField("buildAppBundle", System.Reflection.BindingFlags.Public | BindingFlags.Instance);
|
||||||
switch (androidExportType)
|
switch (androidExportType)
|
||||||
{
|
{
|
||||||
case "androidStudioProject":
|
case "androidStudioProject":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, false, null);
|
buildAppBundle.SetValue(null, false);
|
||||||
break;
|
break;
|
||||||
case "androidAppBundle":
|
case "androidAppBundle":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, true, null);
|
buildAppBundle.SetValue(null, true);
|
||||||
break;
|
break;
|
||||||
case "androidPackage":
|
case "androidPackage":
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
|
||||||
if (buildAppBundle != null)
|
if (buildAppBundle != null)
|
||||||
buildAppBundle.SetValue(null, false, null);
|
buildAppBundle.SetValue(null, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,20 +74,7 @@ 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_6000_0_OR_NEWER
|
#if UNITY_2021_1_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":
|
||||||
|
@ -114,37 +101,5 @@ namespace UnityBuilderAction.Input
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_6000_0_OR_NEWER
|
|
||||||
private static void SetDebugSymbols(string enumValueName)
|
|
||||||
{
|
|
||||||
// UnityEditor.Android.UserBuildSettings and Unity.Android.Types.DebugSymbolLevel are part of the Unity Android module.
|
|
||||||
// Reflection is used here to ensure the code works even if the module is not installed.
|
|
||||||
|
|
||||||
var debugSymbolsType = Type.GetType("UnityEditor.Android.UserBuildSettings+DebugSymbols, UnityEditor.Android.Extensions");
|
|
||||||
if (debugSymbolsType == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var levelProp = debugSymbolsType.GetProperty("level", BindingFlags.Static | BindingFlags.Public);
|
|
||||||
if (levelProp == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var enumType = Type.GetType("Unity.Android.Types.DebugSymbolLevel, Unity.Android.Types");
|
|
||||||
if (enumType == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Enum.TryParse(enumType, enumValueName, false , out var enumValue))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
levelProp.SetValue(null, enumValue);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,6 @@ namespace UnityBuilderAction.Input
|
||||||
EditorApplication.Exit(110);
|
EditorApplication.Exit(110);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_6000_0_OR_NEWER
|
|
||||||
var buildProfileSupport = true;
|
|
||||||
#else
|
|
||||||
var buildProfileSupport = false;
|
|
||||||
#endif // UNITY_6000_0_OR_NEWER
|
|
||||||
|
|
||||||
string buildProfile;
|
|
||||||
if (buildProfileSupport && validatedOptions.TryGetValue("activeBuildProfile", out buildProfile)) {
|
|
||||||
if (validatedOptions.ContainsKey("buildTarget")) {
|
|
||||||
Console.WriteLine("Extra argument -buildTarget");
|
|
||||||
EditorApplication.Exit(122);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
string buildTarget;
|
string buildTarget;
|
||||||
if (!validatedOptions.TryGetValue("buildTarget", out buildTarget)) {
|
if (!validatedOptions.TryGetValue("buildTarget", out buildTarget)) {
|
||||||
Console.WriteLine("Missing argument -buildTarget");
|
Console.WriteLine("Missing argument -buildTarget");
|
||||||
|
@ -41,10 +28,8 @@ namespace UnityBuilderAction.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
||||||
Console.WriteLine(buildTarget + " is not a defined " + typeof(BuildTarget).Name);
|
|
||||||
EditorApplication.Exit(121);
|
EditorApplication.Exit(121);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
string customBuildPath;
|
string customBuildPath;
|
||||||
if (!validatedOptions.TryGetValue("customBuildPath", out customBuildPath)) {
|
if (!validatedOptions.TryGetValue("customBuildPath", out customBuildPath)) {
|
||||||
|
@ -55,10 +40,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +56,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
|
||||||
|
@ -92,7 +77,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"m_SettingKeys": [
|
||||||
|
"VR Device Disabled",
|
||||||
|
"VR Device User Alert"
|
||||||
|
],
|
||||||
|
"m_SettingValues": [
|
||||||
|
"False",
|
||||||
|
"False"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,3 @@
|
||||||
|
<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>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -1,40 +1,28 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
#
|
||||||
# Perform Activation
|
# Create directories for license activation
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
sudo mkdir /Library/Application\ Support/Unity
|
||||||
UNITY_LICENSE_PATH="/Library/Application Support/Unity"
|
sudo chmod -R 777 /Library/Application\ Support/Unity
|
||||||
|
|
||||||
if [ ! -d "$UNITY_LICENSE_PATH" ]; then
|
ACTIVATE_LICENSE_PATH="$ACTION_FOLDER/BlankProject"
|
||||||
echo "Creating Unity License Directory"
|
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
||||||
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 Build
|
# Run steps
|
||||||
#
|
#
|
||||||
|
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
|
||||||
|
|
||||||
#
|
#
|
||||||
# License Cleanup
|
# Remove license activation directory
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ "$SKIP_ACTIVATION" != "true" ]; then
|
sudo rm -r /Library/Application\ Support/Unity
|
||||||
source $ACTION_FOLDER/platforms/mac/steps/return_license.sh
|
rm -r "$ACTIVATE_LICENSE_PATH"
|
||||||
rm -r "$ACTIVATE_LICENSE_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Instructions for debugging
|
# Instructions for debugging
|
||||||
|
@ -49,7 +37,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 and check for annotations in the summary view."
|
echo "To find the reason for failure: please search for errors in the log above."
|
||||||
echo ""
|
echo ""
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
|
|
@ -4,69 +4,21 @@
|
||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
pushd "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
if [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
echo "Requesting activation"
|
||||||
#
|
|
||||||
# SERIAL LICENSE MODE
|
|
||||||
#
|
|
||||||
# This will activate unity, using the serial activation process.
|
|
||||||
#
|
|
||||||
|
|
||||||
echo "Requesting activation"
|
# Activate license
|
||||||
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
|
-logFile - \
|
||||||
|
-batchmode \
|
||||||
|
-nographics \
|
||||||
|
-quit \
|
||||||
|
-serial "$UNITY_SERIAL" \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
|
-projectPath "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
# Activate license
|
# Store the exit code from the verify command
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
UNITY_EXIT_CODE=$?
|
||||||
-logFile - \
|
|
||||||
-batchmode \
|
|
||||||
-nographics \
|
|
||||||
-quit \
|
|
||||||
-serial "$UNITY_SERIAL" \
|
|
||||||
-username "$UNITY_EMAIL" \
|
|
||||||
-password "$UNITY_PASSWORD" \
|
|
||||||
-projectPath "$ACTIVATE_LICENSE_PATH"
|
|
||||||
|
|
||||||
# Store the exit code from the verify command
|
|
||||||
UNITY_EXIT_CODE=$?
|
|
||||||
|
|
||||||
elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
|
||||||
#
|
|
||||||
# Custom Unity License Server
|
|
||||||
#
|
|
||||||
echo "Adding licensing server config"
|
|
||||||
mkdir -p "$UNITY_LICENSE_PATH/config/"
|
|
||||||
cp "$ACTION_FOLDER/unity-config/services-config.json" "$UNITY_LICENSE_PATH/config/services-config.json"
|
|
||||||
|
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/Frameworks/UnityLicensingClient.app/Contents/MacOS/Unity.Licensing.Client \
|
|
||||||
--acquire-floating > license.txt
|
|
||||||
|
|
||||||
# Store the exit code from the verify command
|
|
||||||
UNITY_EXIT_CODE=$?
|
|
||||||
|
|
||||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
|
||||||
PARSEDFILE=$(grep -oE '\"[^"]*\"' < license.txt | tr -d '"')
|
|
||||||
export FLOATING_LICENSE
|
|
||||||
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
|
||||||
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
|
||||||
|
|
||||||
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
#
|
|
||||||
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
|
||||||
#
|
|
||||||
# This will exit since no activation strategies could be matched.
|
|
||||||
#
|
|
||||||
echo "License activation strategy could not be determined."
|
|
||||||
echo ""
|
|
||||||
echo "Visit https://game.ci/docs/github/activation for more"
|
|
||||||
echo "details on how to set up one of the possible activation strategies."
|
|
||||||
|
|
||||||
echo "::error ::No valid license activation strategy could be determined. Make sure to provide UNITY_EMAIL, UNITY_PASSWORD, and either a UNITY_SERIAL \
|
|
||||||
or UNITY_LICENSE. Otherwise please use UNITY_LICENSING_SERVER. See more info at https://game.ci/docs/github/activation"
|
|
||||||
|
|
||||||
# Immediately exit as no UNITY_EXIT_CODE can be derived.
|
|
||||||
exit 1;
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Display information about the result
|
# Display information about the result
|
||||||
|
@ -78,7 +30,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
|
||||||
|
|
||||||
|
|
|
@ -19,23 +19,6 @@ 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
|
||||||
#
|
#
|
||||||
|
@ -146,16 +129,16 @@ echo ""
|
||||||
|
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
-logFile - \
|
-logFile - \
|
||||||
$( [ "${MANUAL_EXIT}" == "true" ] || echo "-quit" ) \
|
-quit \
|
||||||
-batchmode \
|
-batchmode \
|
||||||
$( [ "${ENABLE_GPU}" == "true" ] || echo "-nographics" ) \
|
-nographics \
|
||||||
|
-username "$UNITY_EMAIL" \
|
||||||
|
-password "$UNITY_PASSWORD" \
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
-projectPath "$UNITY_PROJECT_PATH" \
|
-projectPath "$UNITY_PROJECT_PATH" \
|
||||||
$( [ -z "$BUILD_PROFILE" ] && echo "-buildTarget $BUILD_TARGET") \
|
-buildTarget "$BUILD_TARGET" \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
-customBuildProfile "$BUILD_PROFILE" \
|
|
||||||
${BUILD_PROFILE:+-activeBuildProfile} ${BUILD_PROFILE:+"$BUILD_PROFILE"} \
|
|
||||||
-executeMethod "$BUILD_METHOD" \
|
-executeMethod "$BUILD_METHOD" \
|
||||||
-buildVersion "$VERSION" \
|
-buildVersion "$VERSION" \
|
||||||
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
||||||
|
|
|
@ -4,29 +4,15 @@
|
||||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||||
pushd "$ACTIVATE_LICENSE_PATH"
|
pushd "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
||||||
#
|
-logFile - \
|
||||||
# Return any floating license used.
|
-batchmode \
|
||||||
#
|
-nographics \
|
||||||
echo "Returning floating license: \"$FLOATING_LICENSE\""
|
-quit \
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/Frameworks/UnityLicensingClient.app/Contents/MacOS/Unity.Licensing.Client \
|
-username "$UNITY_EMAIL" \
|
||||||
--return-floating "$FLOATING_LICENSE"
|
-password "$UNITY_PASSWORD" \
|
||||||
elif [[ -n "$UNITY_SERIAL" ]]; then
|
-returnlicense \
|
||||||
#
|
-projectPath "$ACTIVATE_LICENSE_PATH"
|
||||||
# SERIAL LICENSE MODE
|
|
||||||
#
|
|
||||||
# This will return the license that is currently in use.
|
|
||||||
#
|
|
||||||
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
|
|
||||||
-logFile - \
|
|
||||||
-batchmode \
|
|
||||||
-nographics \
|
|
||||||
-quit \
|
|
||||||
-username "$UNITY_EMAIL" \
|
|
||||||
-password "$UNITY_PASSWORD" \
|
|
||||||
-returnlicense \
|
|
||||||
-projectPath "$ACTIVATE_LICENSE_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Return to previous working directory
|
# Return to previous working directory
|
||||||
popd
|
popd
|
||||||
|
|
|
@ -1,83 +1,45 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Ensure machine ID is randomized for personal 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
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Prepare Android SDK, if needed
|
# Create directory for license activation
|
||||||
# We do this here to ensure it has root permissions
|
|
||||||
#
|
#
|
||||||
|
|
||||||
fullProjectPath="$GITHUB_WORKSPACE/$PROJECT_PATH"
|
ACTIVATE_LICENSE_PATH="$GITHUB_WORKSPACE/_activate-license~"
|
||||||
|
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
||||||
|
|
||||||
if [[ "$BUILD_TARGET" == "Android" ]]; then
|
#
|
||||||
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
|
# Run steps
|
||||||
ANDROID_HOME_DIRECTORY="$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
|
#
|
||||||
SDKMANAGER=$(find $ANDROID_HOME_DIRECTORY/cmdline-tools -name sdkmanager)
|
source /steps/set_gitcredential.sh
|
||||||
if [ -z "${SDKMANAGER}" ]
|
source /steps/activate.sh
|
||||||
then
|
source /steps/build.sh
|
||||||
SDKMANAGER=$(find $ANDROID_HOME_DIRECTORY/tools/bin -name sdkmanager)
|
source /steps/return_license.sh
|
||||||
if [ -z "${SDKMANAGER}" ]
|
|
||||||
then
|
|
||||||
echo "No sdkmanager found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
|
#
|
||||||
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
|
# Remove license activation directory
|
||||||
$SDKMANAGER "$ANDROID_SDK_MANAGER_PARAMETERS"
|
#
|
||||||
else
|
|
||||||
echo "Updating Android SDK with auto detected target API version"
|
|
||||||
# Read the line containing AndroidTargetSdkVersion from the file
|
|
||||||
targetAPILine=$(grep 'AndroidTargetSdkVersion' "$fullProjectPath/ProjectSettings/ProjectSettings.asset")
|
|
||||||
|
|
||||||
# Extract the number after the semicolon
|
rm -r "$ACTIVATE_LICENSE_PATH"
|
||||||
targetAPI=$(echo "$targetAPILine" | cut -d':' -f2 | tr -d '[:space:]')
|
|
||||||
|
|
||||||
$SDKMANAGER "platforms;android-$targetAPI"
|
#
|
||||||
fi
|
# Instructions for debugging
|
||||||
|
#
|
||||||
|
|
||||||
echo "Updated Android SDK."
|
if [[ $BUILD_EXIT_CODE -gt 0 ]]; then
|
||||||
else
|
echo ""
|
||||||
echo "Not updating Android SDK."
|
echo "###########################"
|
||||||
fi
|
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."
|
||||||
|
echo ""
|
||||||
|
fi;
|
||||||
|
|
||||||
if [[ "$RUN_AS_HOST_USER" == "true" ]]; then
|
#
|
||||||
echo "Running as host user"
|
# Exit with code from the build step.
|
||||||
|
#
|
||||||
|
|
||||||
# Stop on error if we can't set up the user
|
exit $BUILD_EXIT_CODE
|
||||||
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 $?
|
|
||||||
|
|
|
@ -1,65 +1,78 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# if blankproject folder doesn't exist create it
|
# Run in ACTIVATE_LICENSE_PATH directory
|
||||||
if [ ! -d "/BlankProject" ]; then
|
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||||
mkdir /BlankProject
|
pushd "$ACTIVATE_LICENSE_PATH"
|
||||||
fi
|
|
||||||
# if blankproject folder doesn't exist create it
|
|
||||||
if [ ! -d "/BlankProject/Assets" ]; then
|
|
||||||
mkdir /BlankProject/Assets
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
||||||
#
|
#
|
||||||
# SERIAL LICENSE MODE
|
# PERSONAL LICENSE MODE
|
||||||
#
|
#
|
||||||
# This will activate unity, using the serial activation process.
|
# This will activate Unity, using a license file
|
||||||
#
|
#
|
||||||
echo "Requesting activation"
|
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
|
||||||
|
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
|
||||||
|
#
|
||||||
|
# The license file can be acquired using `webbertakken/request-manual-activation-file` action.
|
||||||
|
echo "Requesting activation (personal license)"
|
||||||
|
|
||||||
# Loop the unity-editor call until the license is activated with exponential backoff and a maximum of 5 retries
|
# Set the license file path
|
||||||
retry_count=0
|
FILE_PATH=UnityLicenseFile.ulf
|
||||||
|
|
||||||
# Initialize delay to 15 seconds
|
if [[ -n "$UNITY_LICENSE" ]]; then
|
||||||
delay=15
|
# Copy license file from Github variables
|
||||||
|
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
|
||||||
|
|
||||||
# Loop until UNITY_EXIT_CODE is 0 or retry count reaches 5
|
# Activate license
|
||||||
while [[ $retry_count -lt 5 ]]
|
ACTIVATION_OUTPUT=$(unity-editor \
|
||||||
do
|
|
||||||
# Activate license
|
|
||||||
unity-editor \
|
|
||||||
-logFile /dev/stdout \
|
-logFile /dev/stdout \
|
||||||
-quit \
|
-quit \
|
||||||
-serial "$UNITY_SERIAL" \
|
-manualLicenseFile $FILE_PATH)
|
||||||
-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=$?
|
||||||
|
|
||||||
# Check if UNITY_EXIT_CODE is 0
|
# The exit code for personal activation is always 1;
|
||||||
if [[ $UNITY_EXIT_CODE -eq 0 ]]
|
# Determine whether activation was successful.
|
||||||
then
|
#
|
||||||
echo "Activation successful"
|
# Successful output should include the following:
|
||||||
break
|
#
|
||||||
else
|
# "LICENSE SYSTEM [2020120 18:51:20] Next license update check is after 2019-11-25T18:23:38"
|
||||||
# Increment retry count
|
#
|
||||||
((retry_count++))
|
ACTIVATION_SUCCESSFUL=$(echo $ACTIVATION_OUTPUT | grep 'Next license update check is after' | wc -l)
|
||||||
|
|
||||||
echo "::warning ::Activation failed, attempting retry #$retry_count"
|
# Set exit code to 0 if activation was successful
|
||||||
echo "Activation failed, retrying in $delay seconds..."
|
if [[ $ACTIVATION_SUCCESSFUL -eq 1 ]]; then
|
||||||
sleep $delay
|
UNITY_EXIT_CODE=0
|
||||||
|
fi;
|
||||||
|
|
||||||
# Double the delay for the next iteration
|
# Remove license file
|
||||||
delay=$((delay * 2))
|
rm -f $FILE_PATH
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $retry_count -eq 5 ]]
|
elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
||||||
then
|
#
|
||||||
echo "Activation failed after 5 retries"
|
# PROFESSIONAL (SERIAL) LICENSE MODE
|
||||||
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
|
||||||
#
|
#
|
||||||
|
@ -68,18 +81,14 @@ elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||||
echo "Adding licensing server config"
|
echo "Adding licensing server config"
|
||||||
|
|
||||||
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --acquire-floating > license.txt #is this accessible in a env variable?
|
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --acquire-floating > license.txt #is this accessible in a env variable?
|
||||||
|
PARSEDFILE=$(grep -oP '\".*?\"' < license.txt | tr -d '"')
|
||||||
|
export FLOATING_LICENSE
|
||||||
|
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
||||||
|
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
||||||
|
|
||||||
|
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
||||||
# Store the exit code from the verify command
|
# Store the exit code from the verify command
|
||||||
UNITY_EXIT_CODE=$?
|
UNITY_EXIT_CODE=$?
|
||||||
|
|
||||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
|
||||||
PARSEDFILE=$(grep -oP '\".*?\"' < license.txt | tr -d '"')
|
|
||||||
export FLOATING_LICENSE
|
|
||||||
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
|
||||||
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
|
||||||
|
|
||||||
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
#
|
#
|
||||||
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||||
|
@ -88,13 +97,10 @@ 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/activation for more"
|
echo "Visit https://game.ci/docs/github/getting-started 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."
|
||||||
|
|
||||||
echo "::error ::No valid license activation strategy could be determined. Make sure to provide UNITY_EMAIL, UNITY_PASSWORD, and either a UNITY_SERIAL \
|
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
|
||||||
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
|
||||||
|
@ -109,6 +115,8 @@ 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
|
||||||
|
|
|
@ -19,22 +19,6 @@ 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
|
||||||
#
|
#
|
||||||
|
@ -78,6 +62,19 @@ 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
|
||||||
#
|
#
|
||||||
|
@ -122,14 +119,12 @@ echo ""
|
||||||
|
|
||||||
unity-editor \
|
unity-editor \
|
||||||
-logfile /dev/stdout \
|
-logfile /dev/stdout \
|
||||||
$( [ "${MANUAL_EXIT}" == "true" ] || echo "-quit" ) \
|
-quit \
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
-projectPath "$UNITY_PROJECT_PATH" \
|
-projectPath "$UNITY_PROJECT_PATH" \
|
||||||
$( [ -z "$BUILD_PROFILE" ] && echo "-buildTarget $BUILD_TARGET" ) \
|
-buildTarget "$BUILD_TARGET" \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
-customBuildProfile "$BUILD_PROFILE" \
|
|
||||||
${BUILD_PROFILE:+-activeBuildProfile} ${BUILD_PROFILE:+"$BUILD_PROFILE"} \
|
|
||||||
-executeMethod "$BUILD_METHOD" \
|
-executeMethod "$BUILD_METHOD" \
|
||||||
-buildVersion "$VERSION" \
|
-buildVersion "$VERSION" \
|
||||||
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
-androidVersionCode "$ANDROID_VERSION_CODE" \
|
||||||
|
@ -158,7 +153,6 @@ fi
|
||||||
|
|
||||||
# Make a given user owner of all artifacts
|
# Make a given user owner of all artifacts
|
||||||
if [[ -n "$CHOWN_FILES_TO" ]]; then
|
if [[ -n "$CHOWN_FILES_TO" ]]; then
|
||||||
echo "Changing ownership of files to $CHOWN_FILES_TO for $BUILD_PATH_FULL and $UNITY_PROJECT_PATH"
|
|
||||||
chown -R "$CHOWN_FILES_TO" "$BUILD_PATH_FULL"
|
chown -R "$CHOWN_FILES_TO" "$BUILD_PATH_FULL"
|
||||||
chown -R "$CHOWN_FILES_TO" "$UNITY_PROJECT_PATH"
|
chown -R "$CHOWN_FILES_TO" "$UNITY_PROJECT_PATH"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
# Run in ACTIVATE_LICENSE_PATH directory
|
||||||
|
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.
|
||||||
#
|
#
|
||||||
|
@ -8,15 +13,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
|
||||||
#
|
#
|
||||||
# SERIAL LICENSE MODE
|
# PROFESSIONAL (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
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,29 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
if [ -z "${GIT_CONFIG_EXTENSIONS}" ]
|
|
||||||
then
|
|
||||||
echo "GIT_CONFIG_EXTENSIONS unset skipping"
|
|
||||||
else
|
|
||||||
echo "GIT_CONFIG_EXTENSIONS is set configuring extra git configs"
|
|
||||||
|
|
||||||
IFS=$'\n'
|
|
||||||
for config in $(echo "${GIT_CONFIG_EXTENSIONS}" | sed 's/\(.*\)=\(.*\)/"\1" "\2"/g'); do
|
|
||||||
if [[ $config =~ \"([^\"]+)\"\ \"([^\"]+)\" ]]; then
|
|
||||||
key="${BASH_REMATCH[1]}"
|
|
||||||
value="${BASH_REMATCH[2]}"
|
|
||||||
else
|
|
||||||
echo "Error parsing config: $config"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Adding extra git config: \"$key\" = \"$value\""
|
|
||||||
git config --global --add "$key" "$value"
|
|
||||||
done
|
|
||||||
unset IFS
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "---------- git config --list -------------"
|
|
||||||
git config --list
|
|
||||||
|
|
||||||
echo "---------- git config --list --show-origin -------------"
|
|
||||||
git config --list --show-origin
|
|
|
@ -9,8 +9,8 @@ else
|
||||||
git config --global credential.helper store
|
git config --global credential.helper store
|
||||||
git config --global --replace-all url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf ssh://git@github.com/
|
git config --global --replace-all url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf ssh://git@github.com/
|
||||||
git config --global --add url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf git@github.com
|
git config --global --add url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf git@github.com
|
||||||
git config --global --add url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
|
|
||||||
|
|
||||||
|
git config --global --add url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
|
||||||
git config --global url."https://ssh:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
git config --global url."https://ssh:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
||||||
git config --global url."https://git:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
|
git config --global url."https://git:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
|
||||||
|
|
||||||
|
|
|
@ -1,93 +1,7 @@
|
||||||
# Activates Unity
|
# Activates Unity
|
||||||
|
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -nographics `
|
||||||
Write-Output ""
|
-username $Env:UNITY_EMAIL `
|
||||||
Write-Output "###########################"
|
-password $Env:UNITY_PASSWORD `
|
||||||
Write-Output "# Activating #"
|
-serial $Env:UNITY_SERIAL `
|
||||||
Write-Output "###########################"
|
-projectPath "c:/BlankProject" `
|
||||||
Write-Output ""
|
-logfile | Out-Host
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,25 +16,6 @@ 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
|
||||||
#
|
#
|
||||||
|
@ -85,26 +66,6 @@ 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
|
||||||
#
|
#
|
||||||
|
@ -148,84 +109,51 @@ Write-Output "# Building project #"
|
||||||
Write-Output "###########################"
|
Write-Output "###########################"
|
||||||
Write-Output ""
|
Write-Output ""
|
||||||
|
|
||||||
$unityGraphics = "-nographics"
|
|
||||||
|
|
||||||
if ($LLVMPIPE_INSTALLED -eq "true")
|
|
||||||
{
|
|
||||||
$unityGraphics = "-force-opengl"
|
|
||||||
}
|
|
||||||
|
|
||||||
# If $Env:CUSTOM_PARAMETERS contains spaces and is passed directly on the command line to Unity, powershell will wrap it
|
# If $Env:CUSTOM_PARAMETERS contains spaces and is passed directly on the command line to Unity, powershell will wrap it
|
||||||
# in double quotes. To avoid this, parse $Env:CUSTOM_PARAMETERS into an array, while respecting any quotations within the string.
|
# in double quotes. To avoid this, parse $Env:CUSTOM_PARAMETERS into an array, while respecting any quotations within the string.
|
||||||
$_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUSTOM_PARAMETERS)
|
$_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUSTOM_PARAMETERS)
|
||||||
$unityArgs = @(
|
|
||||||
"-quit",
|
|
||||||
"-batchmode",
|
|
||||||
$unityGraphics,
|
|
||||||
"-silent-crashes",
|
|
||||||
"-customBuildName", "`"$Env:BUILD_NAME`"",
|
|
||||||
"-projectPath", "`"$Env:UNITY_PROJECT_PATH`"",
|
|
||||||
"-executeMethod", "`"$Env:BUILD_METHOD`"",
|
|
||||||
"-customBuildTarget", "`"$Env:BUILD_TARGET`"",
|
|
||||||
"-customBuildPath", "`"$Env:CUSTOM_BUILD_PATH`"",
|
|
||||||
"-customBuildProfile", "`"$Env:BUILD_PROFILE`"",
|
|
||||||
"-buildVersion", "`"$Env:VERSION`"",
|
|
||||||
"-androidVersionCode", "`"$Env:ANDROID_VERSION_CODE`"",
|
|
||||||
"-androidKeystorePass", "`"$Env:ANDROID_KEYSTORE_PASS`"",
|
|
||||||
"-androidKeyaliasName", "`"$Env:ANDROID_KEYALIAS_NAME`"",
|
|
||||||
"-androidKeyaliasPass", "`"$Env:ANDROID_KEYALIAS_PASS`"",
|
|
||||||
"-androidTargetSdkVersion", "`"$Env:ANDROID_TARGET_SDK_VERSION`"",
|
|
||||||
"-androidExportType", "`"$Env:ANDROID_EXPORT_TYPE`"",
|
|
||||||
"-androidSymbolType", "`"$Env:ANDROID_SYMBOL_TYPE`"",
|
|
||||||
"-logfile", "-"
|
|
||||||
) + $customParametersArray
|
|
||||||
|
|
||||||
if (-not $Env:BUILD_PROFILE) {
|
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -quit -batchmode -nographics `
|
||||||
$unityArgs += @("-buildTarget", "`"$Env:BUILD_TARGET`"")
|
-projectPath $Env:UNITY_PROJECT_PATH `
|
||||||
}
|
-executeMethod $Env:BUILD_METHOD `
|
||||||
if ($Env:BUILD_PROFILE) {
|
-buildTarget $Env:BUILD_TARGET `
|
||||||
$unityArgs += @("-activeBuildProfile", "`"$Env:BUILD_PROFILE`"")
|
-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
|
||||||
|
$Env:BUILD_EXIT_CODE=$LastExitCode
|
||||||
|
|
||||||
|
# Display results
|
||||||
|
if ($Env:BUILD_EXIT_CODE -eq 0)
|
||||||
|
{
|
||||||
|
Write-Output "Build Succeeded!"
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Write-Output "$('Build failed, with exit code ')$($Env:BUILD_EXIT_CODE)$('"')"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove null items as that will fail the Start-Process call
|
# TODO: Determine if we need to set permissions on any files
|
||||||
$unityArgs = $unityArgs | Where-Object { $_ -ne $null }
|
|
||||||
|
|
||||||
$unityProcess = Start-Process -FilePath "$Env:UNITY_PATH/Editor/Unity.exe" `
|
#
|
||||||
-ArgumentList $unityArgs `
|
# Results
|
||||||
-PassThru `
|
#
|
||||||
-NoNewWindow
|
|
||||||
|
|
||||||
# Cache the handle so exit code works properly
|
Write-Output ""
|
||||||
# https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait
|
Write-Output "###########################"
|
||||||
$unityHandle = $unityProcess.Handle
|
Write-Output "# Build output #"
|
||||||
|
Write-Output "###########################"
|
||||||
|
Write-Output ""
|
||||||
|
|
||||||
while ($true) {
|
Get-ChildItem $Env:BUILD_PATH_FULL
|
||||||
if ($unityProcess.HasExited) {
|
Write-Output ""
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,52 +1,15 @@
|
||||||
Get-Process
|
# Activate Unity
|
||||||
|
& "c:\steps\activate.ps1"
|
||||||
# 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-Object { reg import $_.fullname }
|
Get-ChildItem -Path c:\regkeys -File | Foreach {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
|
|
||||||
. "c:\steps\set_gitcredential.ps1"
|
|
||||||
|
|
||||||
if ($env:ENABLE_GPU -eq "true") {
|
|
||||||
# Install LLVMpipe software graphics driver
|
|
||||||
. "c:\steps\install_llvmpipe.ps1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Activate Unity
|
|
||||||
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
|
||||||
if ($env:SKIP_ACTIVATION -ne "true") {
|
& "c:\steps\return_license.ps1"
|
||||||
. "c:\steps\return_license.ps1"
|
|
||||||
}
|
|
||||||
|
|
||||||
Get-Process
|
|
||||||
|
|
||||||
exit $BUILD_EXIT_CODE
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
$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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +1,7 @@
|
||||||
# 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 `
|
||||||
Write-Output ""
|
-username $Env:UNITY_EMAIL `
|
||||||
Write-Output "###########################"
|
-password $Env:UNITY_PASSWORD `
|
||||||
Write-Output "# Return License #"
|
-returnlicense `
|
||||||
Write-Output "###########################"
|
-projectPath "c:/BlankProject" `
|
||||||
Write-Output ""
|
-logfile | Out-Host
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
if ($null -eq ${env:GIT_PRIVATE_TOKEN}) {
|
|
||||||
Write-Host "GIT_PRIVATE_TOKEN unset skipping"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Host "GIT_PRIVATE_TOKEN is set configuring git credentials"
|
|
||||||
|
|
||||||
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 --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 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:"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "---------- git config --list -------------"
|
|
||||||
git config --list
|
|
||||||
|
|
||||||
Write-Host "---------- git config --list --show-origin -------------"
|
|
||||||
git config --list --show-origin
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,60 @@
|
||||||
|
"use strict";
|
||||||
|
/* eslint-disable no-process-exit */
|
||||||
|
const util = require("util");
|
||||||
|
const { JSDOM } = require("../../../..");
|
||||||
|
const { READY_STATES } = require("./xhr-utils");
|
||||||
|
const idlUtils = require("../generated/utils");
|
||||||
|
const tough = require("tough-cookie");
|
||||||
|
|
||||||
|
const dom = new JSDOM();
|
||||||
|
const xhr = new dom.window.XMLHttpRequest();
|
||||||
|
const xhrImpl = idlUtils.implForWrapper(xhr);
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
|
||||||
|
process.stdin.on("data", chunk => {
|
||||||
|
chunks.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stdin.on("end", () => {
|
||||||
|
const buffer = Buffer.concat(chunks);
|
||||||
|
|
||||||
|
const flag = JSON.parse(buffer.toString());
|
||||||
|
if (flag.body && flag.body.type === "Buffer" && flag.body.data) {
|
||||||
|
flag.body = Buffer.from(flag.body.data);
|
||||||
|
}
|
||||||
|
if (flag.cookieJar) {
|
||||||
|
flag.cookieJar = tough.CookieJar.fromJSON(flag.cookieJar);
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.synchronous = false;
|
||||||
|
Object.assign(xhrImpl.flag, flag);
|
||||||
|
const { properties } = xhrImpl;
|
||||||
|
xhrImpl.readyState = READY_STATES.OPENED;
|
||||||
|
try {
|
||||||
|
xhr.addEventListener("loadend", () => {
|
||||||
|
if (properties.error) {
|
||||||
|
properties.error = properties.error.stack || util.inspect(properties.error);
|
||||||
|
}
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
responseURL: xhrImpl.responseURL,
|
||||||
|
status: xhrImpl.status,
|
||||||
|
statusText: xhrImpl.statusText,
|
||||||
|
properties
|
||||||
|
}), () => {
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
xhr.send(flag.body);
|
||||||
|
} catch (error) {
|
||||||
|
properties.error += error.stack || util.inspect(error);
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
responseURL: xhrImpl.responseURL,
|
||||||
|
status: xhrImpl.status,
|
||||||
|
statusText: xhrImpl.statusText,
|
||||||
|
properties
|
||||||
|
}), () => {
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +1,3 @@
|
||||||
hook: after
|
hook: after-build
|
||||||
commands: |
|
commands: |
|
||||||
echo "after-build hook test!"
|
echo "after-build hook test!"
|
|
@ -1,3 +1,3 @@
|
||||||
hook: before
|
hook: before-build
|
||||||
commands: |
|
commands: |
|
||||||
echo "before-build hook test!!"
|
echo "before-build hook test!!"
|
|
@ -18,6 +18,7 @@ module.exports = {
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.ts$': 'ts-jest',
|
'^.+\\.ts$': 'ts-jest',
|
||||||
},
|
},
|
||||||
|
autoRun: false,
|
||||||
|
|
||||||
// Indicates whether each individual test should be reported during the run
|
// Indicates whether each individual test should be reported during the run
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
@ -25,8 +26,6 @@ module.exports = {
|
||||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||||
modulePathIgnorePatterns: ['<rootDir>/lib/', '<rootDir>/dist/'],
|
modulePathIgnorePatterns: ['<rootDir>/lib/', '<rootDir>/dist/'],
|
||||||
|
|
||||||
// Files that will be run before Jest is loaded to set globals like fetch
|
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||||
setupFiles: ['<rootDir>/src/jest.globals.ts'],
|
|
||||||
// A list of paths to modules that run some code to configure or set up the testing framework after the environment is ready
|
|
||||||
setupFilesAfterEnv: ['<rootDir>/src/jest.setup.ts'],
|
setupFilesAfterEnv: ['<rootDir>/src/jest.setup.ts'],
|
||||||
};
|
};
|
||||||
|
|
63
package.json
63
package.json
|
@ -1,69 +1,61 @@
|
||||||
{
|
{
|
||||||
"name": "unity-builder",
|
"name": "unity-builder",
|
||||||
"version": "3.0.0",
|
"version": "2.0.0",
|
||||||
"description": "Build Unity projects for different platforms.",
|
"description": "Build Unity projects for different platforms.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"repository": "git@github.com:game-ci/unity-builder.git",
|
"repository": "git@github.com:game-ci/unity-builder.git",
|
||||||
"author": "Webber <webber@takken.io>",
|
"author": "Webber <webber@takken.io>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "lefthook install",
|
"prepare": "lefthook install && npx husky uninstall -y",
|
||||||
"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 inputPullCommand=\"gcp-secret-manager\" populateOverride=true pullInputList=UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD yarn test -i -t \"cloud runner\"",
|
"gcp-secrets-tests": "cross-env cloudRunnerCluster=aws cloudRunnerTests=true readInputOverrideCommand=\"gcp-secret-manager\" populateOverride=true readInputFromOverrideList=UNITY_EMAIL,UNITY_SERIAL,UNITY_PASSWORD yarn test -i -t \"cloud runner\"",
|
||||||
"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",
|
"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",
|
||||||
"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",
|
"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",
|
||||||
"cli-aws": "cross-env providerStrategy=aws yarn run test-cli",
|
"cli-aws": "cross-env cloudRunnerCluster=aws yarn run test-cli",
|
||||||
"cli-k8s": "cross-env providerStrategy=k8s yarn run test-cli",
|
"cli-k8s": "cross-env cloudRunnerCluster=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",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test-i": "cross-env cloudRunnerTests=true yarn test -i -t \"cloud runner\"",
|
"test-i": "cross-env cloudRunnerTests=true yarn test -i -t \"cloud runner\"",
|
||||||
"test-i-*": "yarn run test-i-aws && yarn run test-i-k8s",
|
"test-i-*": "yarn run test-i-aws && yarn run test-i-k8s",
|
||||||
"test-i-aws": "cross-env cloudRunnerTests=true providerStrategy=aws yarn test -i -t \"cloud runner\"",
|
"test-i-aws": "cross-env cloudRunnerTests=true cloudRunnerCluster=aws yarn test -i -t \"cloud runner\"",
|
||||||
"test-i-k8s": "cross-env cloudRunnerTests=true providerStrategy=k8s yarn test -i -t \"cloud runner\""
|
"test-i-k8s": "cross-env cloudRunnerTests=true cloudRunnerCluster=k8s yarn test -i -t \"cloud runner\""
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.x"
|
"node": ">=16.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^4.0.0",
|
"@actions/cache": "^3.1.3",
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.0",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^5.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": "^5.1.0",
|
"@octokit/core": "^3.5.1",
|
||||||
"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.3.5",
|
||||||
"ts-md5": "^1.3.1",
|
"unity-changeset": "^1.6.0",
|
||||||
"unity-changeset": "^3.1.0",
|
"uuid": "^8.3.2",
|
||||||
"uuid": "^9.0.0",
|
"yaml": "^1.10.2"
|
||||||
"yaml": "^2.2.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/base-64": "^1.0.0",
|
"@arkweid/lefthook": "^0.7.7",
|
||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/node": "^17.0.23",
|
"@types/node": "^17.0.23",
|
||||||
"@types/semver": "^7.3.9",
|
"@types/semver": "^7.3.9",
|
||||||
"@types/uuid": "^9.0.0",
|
|
||||||
"@typescript-eslint/parser": "4.8.1",
|
"@typescript-eslint/parser": "4.8.1",
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.33.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^7.23.0",
|
"eslint": "7.17.0",
|
||||||
"eslint-config-prettier": "8.1.0",
|
"eslint-config-prettier": "8.1.0",
|
||||||
"eslint-plugin-github": "^4.1.1",
|
"eslint-plugin-github": "^4.1.1",
|
||||||
"eslint-plugin-jest": "24.1.3",
|
"eslint-plugin-jest": "24.1.3",
|
||||||
|
@ -71,17 +63,12 @@
|
||||||
"eslint-plugin-unicorn": "28.0.2",
|
"eslint-plugin-unicorn": "28.0.2",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"jest-circus": "^27.5.1",
|
"jest-circus": "^27.5.1",
|
||||||
"jest-fail-on-console": "^3.0.2",
|
"jest-fail-on-console": "^2.3.0",
|
||||||
"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.8.1",
|
"ts-node": "10.4.0",
|
||||||
"typescript": "4.7.4",
|
"typescript": "4.1.3",
|
||||||
"yarn-audit-fix": "^9.3.8"
|
"yarn-audit-fix": "^9.3.8"
|
||||||
},
|
|
||||||
"volta": {
|
|
||||||
"node": "20.5.1",
|
|
||||||
"yarn": "1.22.19"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
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
|
|
29
src/index.ts
29
src/index.ts
|
@ -3,7 +3,6 @@ import { Action, BuildParameters, Cache, CloudRunner, Docker, ImageTag, Output }
|
||||||
import { Cli } from './model/cli/cli';
|
import { Cli } from './model/cli/cli';
|
||||||
import MacBuilder from './model/mac-builder';
|
import MacBuilder from './model/mac-builder';
|
||||||
import PlatformSetup from './model/platform-setup';
|
import PlatformSetup from './model/platform-setup';
|
||||||
|
|
||||||
async function runMain() {
|
async function runMain() {
|
||||||
try {
|
try {
|
||||||
if (Cli.InitCliMode()) {
|
if (Cli.InitCliMode()) {
|
||||||
|
@ -19,35 +18,23 @@ 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.cloudRunnerCluster !== 'local') {
|
||||||
|
await CloudRunner.run(buildParameters, baseImage.toString());
|
||||||
if (buildParameters.providerStrategy === 'local') {
|
} else {
|
||||||
core.info('Building locally');
|
core.info('Building locally');
|
||||||
await PlatformSetup.setup(buildParameters, actionFolder);
|
await PlatformSetup.setup(buildParameters, actionFolder);
|
||||||
exitCode =
|
if (process.platform === 'darwin') {
|
||||||
process.platform === 'darwin'
|
MacBuilder.run(actionFolder);
|
||||||
? await MacBuilder.run(actionFolder)
|
} else {
|
||||||
: await Docker.run(baseImage.toString(), {
|
await Docker.run(baseImage, { workspace, actionFolder, ...buildParameters });
|
||||||
workspace,
|
}
|
||||||
actionFolder,
|
|
||||||
...buildParameters,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
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();
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Integration test for exercising real GitHub check creation and updates.
|
|
||||||
import CloudRunner from '../model/cloud-runner/cloud-runner';
|
|
||||||
import UnityVersioning from '../model/unity-versioning';
|
|
||||||
import GitHub from '../model/github';
|
|
||||||
import { TIMEOUT_INFINITE, createParameters } from '../test-utils/cloud-runner-test-helpers';
|
|
||||||
|
|
||||||
const runIntegration = process.env.RUN_GITHUB_INTEGRATION_TESTS === 'true';
|
|
||||||
const describeOrSkip = runIntegration ? describe : describe.skip;
|
|
||||||
|
|
||||||
describeOrSkip('Cloud Runner Github Checks Integration', () => {
|
|
||||||
it(
|
|
||||||
'creates and updates a real GitHub check',
|
|
||||||
async () => {
|
|
||||||
const buildParameter = await createParameters({
|
|
||||||
versioning: 'None',
|
|
||||||
projectPath: 'test-project',
|
|
||||||
unityVersion: UnityVersioning.read('test-project'),
|
|
||||||
asyncCloudRunner: `true`,
|
|
||||||
githubChecks: `true`,
|
|
||||||
});
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
const checkId = await GitHub.createGitHubCheck(`integration create`);
|
|
||||||
expect(checkId).not.toEqual('');
|
|
||||||
await GitHub.updateGitHubCheck(`1 ${new Date().toISOString()}`, `integration`);
|
|
||||||
await GitHub.updateGitHubCheck(`2 ${new Date().toISOString()}`, `integration`, `success`, `completed`);
|
|
||||||
},
|
|
||||||
TIMEOUT_INFINITE,
|
|
||||||
);
|
|
||||||
});
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { stat } from 'node:fs/promises';
|
import { stat } from 'fs/promises';
|
||||||
|
|
||||||
describe('Integrity tests', () => {
|
describe('Integrity tests', () => {
|
||||||
describe('package-lock.json', () => {
|
describe('package-lock.json', () => {
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { fetch as undiciFetch, Headers, Request, Response } from 'undici';
|
|
||||||
|
|
||||||
Object.assign(globalThis, { fetch: undiciFetch, Headers, Request, Response });
|
|
|
@ -1,5 +1,5 @@
|
||||||
import path from 'node:path';
|
import path from 'path';
|
||||||
import fs from 'node:fs';
|
import fs from 'fs';
|
||||||
import Action from './action';
|
import Action from './action';
|
||||||
|
|
||||||
describe('Action', () => {
|
describe('Action', () => {
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
import path from 'node:path';
|
import path from 'path';
|
||||||
|
|
||||||
class Action {
|
class Action {
|
||||||
static get supportedPlatforms(): string[] {
|
static get supportedPlatforms() {
|
||||||
return ['linux', 'win32', 'darwin'];
|
return ['linux', 'win32', 'darwin'];
|
||||||
}
|
}
|
||||||
|
|
||||||
static get isRunningLocally(): boolean {
|
static get isRunningLocally() {
|
||||||
return process.env.RUNNER_WORKSPACE === undefined;
|
return process.env.RUNNER_WORKSPACE === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get isRunningFromSource(): boolean {
|
static get isRunningFromSource() {
|
||||||
return path.basename(__dirname) === 'model';
|
return path.basename(__dirname) === 'model';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get canonicalName(): string {
|
static get canonicalName() {
|
||||||
if (Action.isRunningFromSource) {
|
|
||||||
return path.basename(path.dirname(path.join(path.dirname(__filename), '/..')));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'unity-builder';
|
return 'unity-builder';
|
||||||
}
|
}
|
||||||
|
|
||||||
static get rootFolder(): string {
|
static get rootFolder() {
|
||||||
if (Action.isRunningFromSource) {
|
if (Action.isRunningFromSource) {
|
||||||
return path.dirname(path.dirname(path.dirname(__filename)));
|
return path.dirname(path.dirname(path.dirname(__filename)));
|
||||||
}
|
}
|
||||||
|
@ -29,12 +25,12 @@ class Action {
|
||||||
return path.dirname(path.dirname(__filename));
|
return path.dirname(path.dirname(__filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
static get actionFolder(): string {
|
static get actionFolder() {
|
||||||
return `${Action.rootFolder}/dist`;
|
return `${Action.rootFolder}/dist`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get workspace(): string {
|
static get workspace() {
|
||||||
return process.env.GITHUB_WORKSPACE!;
|
return process.env.GITHUB_WORKSPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static checkCompatibility() {
|
static checkCompatibility() {
|
||||||
|
|
|
@ -3,15 +3,15 @@ import AndroidVersioning from './android-versioning';
|
||||||
describe('Android Versioning', () => {
|
describe('Android Versioning', () => {
|
||||||
describe('versionToVersionCode', () => {
|
describe('versionToVersionCode', () => {
|
||||||
it('defaults to 0 when versioning strategy is none', () => {
|
it('defaults to 0 when versioning strategy is none', () => {
|
||||||
expect(AndroidVersioning.versionToVersionCode('none')).toBe('0');
|
expect(AndroidVersioning.versionToVersionCode('none')).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('defaults to 1 when version is not a valid semver', () => {
|
it('defaults to 1 when version is not a valid semver', () => {
|
||||||
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe('1');
|
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a number', () => {
|
it('returns a number', () => {
|
||||||
expect(AndroidVersioning.versionToVersionCode('123.456.789')).toBe('123456789');
|
expect(AndroidVersioning.versionToVersionCode('123.456.789')).toBe(123456789);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throw when generated version code is too large', () => {
|
it('throw when generated version code is too large', () => {
|
||||||
|
@ -21,11 +21,11 @@ describe('Android Versioning', () => {
|
||||||
|
|
||||||
describe('determineVersionCode', () => {
|
describe('determineVersionCode', () => {
|
||||||
it('defaults to parsed version', () => {
|
it('defaults to parsed version', () => {
|
||||||
expect(AndroidVersioning.determineVersionCode('1.2.3', '')).toBe('1002003');
|
expect(AndroidVersioning.determineVersionCode('1.2.3', '')).toBe(1002003);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('use specified code', () => {
|
it('use specified code', () => {
|
||||||
expect(AndroidVersioning.determineVersionCode('1.2.3', '2')).toBe('2');
|
expect(AndroidVersioning.determineVersionCode('1.2.3', 2)).toBe(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,19 @@ import * as core from '@actions/core';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
|
||||||
export default class AndroidVersioning {
|
export default class AndroidVersioning {
|
||||||
static determineVersionCode(version: string, inputVersionCode: string): string {
|
static determineVersionCode(version, inputVersionCode) {
|
||||||
if (inputVersionCode === '') {
|
if (!inputVersionCode) {
|
||||||
return AndroidVersioning.versionToVersionCode(version);
|
return AndroidVersioning.versionToVersionCode(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputVersionCode;
|
return inputVersionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static versionToVersionCode(version: string): string {
|
static versionToVersionCode(version) {
|
||||||
if (version === 'none') {
|
if (version === 'none') {
|
||||||
core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
|
core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
|
||||||
|
|
||||||
return '0';
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedVersion = semver.parse(version);
|
const parsedVersion = semver.parse(version);
|
||||||
|
@ -22,7 +22,7 @@ export default class AndroidVersioning {
|
||||||
if (!parsedVersion) {
|
if (!parsedVersion) {
|
||||||
core.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`);
|
core.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`);
|
||||||
|
|
||||||
return '1';
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The greatest value Google Plays allows is 2100000000.
|
// The greatest value Google Plays allows is 2100000000.
|
||||||
|
@ -36,10 +36,10 @@ export default class AndroidVersioning {
|
||||||
}
|
}
|
||||||
core.info(`Using android versionCode ${versionCode}`);
|
core.info(`Using android versionCode ${versionCode}`);
|
||||||
|
|
||||||
return versionCode.toString();
|
return versionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static determineSdkManagerParameters(targetSdkVersion: string) {
|
static determineSdkManagerParameters(targetSdkVersion) {
|
||||||
const parsedVersion = Number.parseInt(targetSdkVersion.slice(-2), 10);
|
const parsedVersion = Number.parseInt(targetSdkVersion.slice(-2), 10);
|
||||||
|
|
||||||
return Number.isNaN(parsedVersion) ? '' : `platforms;android-${parsedVersion}`;
|
return Number.isNaN(parsedVersion) ? '' : `platforms;android-${parsedVersion}`;
|
||||||
|
|
|
@ -33,7 +33,7 @@ describe('BuildParameters', () => {
|
||||||
it('determines the unity version only once', async () => {
|
it('determines the unity version only once', async () => {
|
||||||
jest.spyOn(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
jest.spyOn(UnityVersioning, 'determineUnityVersion').mockImplementation(() => '2019.2.11f1');
|
||||||
await BuildParameters.create();
|
await BuildParameters.create();
|
||||||
expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1);
|
await expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the android version code with provided input', async () => {
|
it('returns the android version code with provided input', async () => {
|
||||||
|
@ -47,15 +47,13 @@ describe('BuildParameters', () => {
|
||||||
it('returns the android version code from version by default', async () => {
|
it('returns the android version code from version by default', async () => {
|
||||||
const mockValue = '';
|
const mockValue = '';
|
||||||
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
|
||||||
await expect(BuildParameters.create()).resolves.toEqual(
|
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidVersionCode: 1003037 }));
|
||||||
expect.objectContaining({ androidVersionCode: '1003037' }),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('determines the android sdk manager parameters only once', async () => {
|
it('determines the android sdk manager parameters only once', async () => {
|
||||||
jest.spyOn(AndroidVersioning, 'determineSdkManagerParameters').mockImplementation(() => 'platforms;android-30');
|
jest.spyOn(AndroidVersioning, 'determineSdkManagerParameters').mockImplementation(() => 'platforms;android-30');
|
||||||
await BuildParameters.create();
|
await BuildParameters.create();
|
||||||
expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1);
|
await expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the targetPlatform', async () => {
|
it('returns the targetPlatform', async () => {
|
||||||
|
@ -71,12 +69,6 @@ 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);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import AndroidVersioning from './android-versioning';
|
import AndroidVersioning from './android-versioning';
|
||||||
import CloudRunnerConstants from './cloud-runner/options/cloud-runner-constants';
|
import CloudRunnerConstants from './cloud-runner/services/cloud-runner-constants';
|
||||||
import CloudRunnerBuildGuid from './cloud-runner/options/cloud-runner-guid';
|
import CloudRunnerBuildGuid from './cloud-runner/services/cloud-runner-guid';
|
||||||
import Input from './input';
|
import Input from './input';
|
||||||
import Platform from './platform';
|
import Platform from './platform';
|
||||||
import UnityVersioning from './unity-versioning';
|
import UnityVersioning from './unity-versioning';
|
||||||
|
@ -10,30 +10,21 @@ import { GitRepoReader } from './input-readers/git-repo';
|
||||||
import { GithubCliReader } from './input-readers/github-cli';
|
import { GithubCliReader } from './input-readers/github-cli';
|
||||||
import { Cli } from './cli/cli';
|
import { Cli } from './cli/cli';
|
||||||
import GitHub from './github';
|
import GitHub from './github';
|
||||||
import CloudRunnerOptions from './cloud-runner/options/cloud-runner-options';
|
import CloudRunnerOptions from './cloud-runner/cloud-runner-options';
|
||||||
import CloudRunner from './cloud-runner/cloud-runner';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
|
|
||||||
class BuildParameters {
|
class BuildParameters {
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
[key: string]: any;
|
|
||||||
|
|
||||||
public editorVersion!: string;
|
public editorVersion!: string;
|
||||||
public customImage!: string;
|
public customImage!: string;
|
||||||
public unitySerial!: string;
|
public unitySerial!: string;
|
||||||
public unityLicensingServer!: string;
|
public unityLicensingServer!: string;
|
||||||
public skipActivation!: string;
|
public runnerTempPath: string | undefined;
|
||||||
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;
|
||||||
|
@ -44,33 +35,27 @@ 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;
|
||||||
public sshPublicKeysDirectoryPath!: string;
|
public cloudRunnerCluster!: string;
|
||||||
public providerStrategy!: string;
|
public awsBaseStackName!: string;
|
||||||
public gitPrivateToken!: string;
|
public gitPrivateToken!: string;
|
||||||
public awsStackName!: string;
|
public awsStackName!: string;
|
||||||
public kubeConfig!: string;
|
public kubeConfig!: string;
|
||||||
public containerMemory!: string;
|
public cloudRunnerMemory!: string;
|
||||||
public containerCpu!: string;
|
public cloudRunnerCpu!: string;
|
||||||
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 customJobHooks!: string;
|
||||||
public pullInputList!: string[];
|
public readInputFromOverrideList!: string;
|
||||||
public inputPullCommand!: string;
|
public readInputOverrideCommand!: string;
|
||||||
public cacheKey!: string;
|
public cacheKey!: string;
|
||||||
|
|
||||||
public postBuildContainerHooks!: string;
|
public postBuildSteps!: string;
|
||||||
public preBuildContainerHooks!: string;
|
public preBuildSteps!: string;
|
||||||
public customJob!: string;
|
public customJob!: string;
|
||||||
public runNumber!: string;
|
public runNumber!: string;
|
||||||
public branch!: string;
|
public branch!: string;
|
||||||
|
@ -79,26 +64,18 @@ class BuildParameters {
|
||||||
public logId!: string;
|
public logId!: string;
|
||||||
public buildGuid!: string;
|
public buildGuid!: string;
|
||||||
public cloudRunnerBranch!: string;
|
public cloudRunnerBranch!: string;
|
||||||
public cloudRunnerDebug!: boolean | undefined;
|
public cloudRunnerDebug!: boolean;
|
||||||
public buildPlatform!: string | undefined;
|
public cloudRunnerBuilderPlatform!: string | undefined;
|
||||||
public isCliMode!: boolean;
|
public isCliMode!: boolean;
|
||||||
|
public retainWorkspace!: boolean;
|
||||||
public maxRetainedWorkspaces!: number;
|
public maxRetainedWorkspaces!: number;
|
||||||
public useLargePackages!: boolean;
|
public useSharedLargePackages!: boolean;
|
||||||
public useCompressionStrategy!: boolean;
|
public useLz4Compression!: boolean;
|
||||||
public garbageMaxAge!: number;
|
public garbageCollectionMaxAge!: number;
|
||||||
|
public constantGarbageCollection!: boolean;
|
||||||
public githubChecks!: boolean;
|
public githubChecks!: boolean;
|
||||||
public asyncWorkflow!: boolean;
|
|
||||||
public githubCheckId!: string;
|
|
||||||
public finalHooks!: string[];
|
|
||||||
public skipLfs!: boolean;
|
|
||||||
public skipCache!: boolean;
|
|
||||||
public cacheUnityInstallationOnMac!: boolean;
|
public cacheUnityInstallationOnMac!: boolean;
|
||||||
public unityHubVersionOnMac!: string;
|
public unityHubVersionOnMac!: string;
|
||||||
public dockerWorkspacePath!: string;
|
|
||||||
|
|
||||||
public static shouldUseRetainedWorkspaceMode(buildParameters: BuildParameters) {
|
|
||||||
return buildParameters.maxRetainedWorkspaces > 0 && CloudRunner.lockedWorkspace !== ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async create(): Promise<BuildParameters> {
|
static async create(): Promise<BuildParameters> {
|
||||||
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidExportType);
|
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidExportType);
|
||||||
|
@ -121,46 +98,37 @@ class BuildParameters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Todo - Don't use process.env directly, that's what the input model class is for.
|
||||||
|
// ---
|
||||||
let unitySerial = '';
|
let unitySerial = '';
|
||||||
if (Input.unityLicensingServer === '') {
|
if (Input.unityLicensingServer === '') {
|
||||||
if (!Input.unitySerial && GitHub.githubInputEnabled) {
|
if (!process.env.UNITY_SERIAL && 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 (!process.env.UNITY_LICENSE) {
|
||||||
throw new Error(
|
throw new Error(`Missing Unity License File and no Serial was found. If this
|
||||||
`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(process.env.UNITY_LICENSE);
|
||||||
} else {
|
} else {
|
||||||
unitySerial = Input.unitySerial!;
|
unitySerial = process.env.UNITY_SERIAL!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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: process.env.RUNNER_TEMP,
|
||||||
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,
|
||||||
|
@ -173,53 +141,43 @@ class BuildParameters {
|
||||||
androidSymbolType: androidSymbolExportType,
|
androidSymbolType: androidSymbolExportType,
|
||||||
customParameters: Input.customParameters,
|
customParameters: Input.customParameters,
|
||||||
sshAgent: Input.sshAgent,
|
sshAgent: Input.sshAgent,
|
||||||
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,
|
cloudRunnerCluster: CloudRunnerOptions.cloudRunnerCluster,
|
||||||
dockerMemoryLimit: Input.dockerMemoryLimit,
|
cloudRunnerBuilderPlatform: CloudRunnerOptions.cloudRunnerBuilderPlatform,
|
||||||
dockerIsolationMode: Input.dockerIsolationMode,
|
awsBaseStackName: CloudRunnerOptions.awsBaseStackName,
|
||||||
containerRegistryRepository: Input.containerRegistryRepository,
|
|
||||||
containerRegistryImageVersion: Input.containerRegistryImageVersion,
|
|
||||||
providerStrategy: CloudRunnerOptions.providerStrategy,
|
|
||||||
buildPlatform: CloudRunnerOptions.buildPlatform,
|
|
||||||
kubeConfig: CloudRunnerOptions.kubeConfig,
|
kubeConfig: CloudRunnerOptions.kubeConfig,
|
||||||
containerMemory: CloudRunnerOptions.containerMemory,
|
cloudRunnerMemory: CloudRunnerOptions.cloudRunnerMemory,
|
||||||
containerCpu: CloudRunnerOptions.containerCpu,
|
cloudRunnerCpu: CloudRunnerOptions.cloudRunnerCpu,
|
||||||
kubeVolumeSize: CloudRunnerOptions.kubeVolumeSize,
|
kubeVolumeSize: CloudRunnerOptions.kubeVolumeSize,
|
||||||
kubeVolume: CloudRunnerOptions.kubeVolume,
|
kubeVolume: CloudRunnerOptions.kubeVolume,
|
||||||
postBuildContainerHooks: CloudRunnerOptions.postBuildContainerHooks,
|
postBuildSteps: CloudRunnerOptions.postBuildSteps,
|
||||||
preBuildContainerHooks: CloudRunnerOptions.preBuildContainerHooks,
|
preBuildSteps: CloudRunnerOptions.preBuildSteps,
|
||||||
customJob: CloudRunnerOptions.customJob,
|
customJob: CloudRunnerOptions.customJob,
|
||||||
runNumber: Input.runNumber,
|
runNumber: Input.runNumber,
|
||||||
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
branch: Input.branch.replace('/head', '') || (await GitRepoReader.GetBranch()),
|
||||||
cloudRunnerBranch: CloudRunnerOptions.cloudRunnerBranch.split('/').reverse()[0],
|
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.awsBaseStackName,
|
||||||
gitSha: Input.gitSha,
|
gitSha: Input.gitSha,
|
||||||
logId: customAlphabet(CloudRunnerConstants.alphabet, 9)(),
|
logId: customAlphabet(CloudRunnerConstants.alphabet, 9)(),
|
||||||
buildGuid: CloudRunnerBuildGuid.generateGuid(Input.runNumber, Input.targetPlatform),
|
buildGuid: CloudRunnerBuildGuid.generateGuid(Input.runNumber, Input.targetPlatform),
|
||||||
commandHooks: CloudRunnerOptions.commandHooks,
|
customJobHooks: CloudRunnerOptions.customJobHooks(),
|
||||||
inputPullCommand: CloudRunnerOptions.inputPullCommand,
|
readInputOverrideCommand: CloudRunnerOptions.readInputOverrideCommand(),
|
||||||
pullInputList: CloudRunnerOptions.pullInputList,
|
readInputFromOverrideList: CloudRunnerOptions.readInputFromOverrideList(),
|
||||||
kubeStorageClass: CloudRunnerOptions.kubeStorageClass,
|
kubeStorageClass: CloudRunnerOptions.kubeStorageClass,
|
||||||
cacheKey: CloudRunnerOptions.cacheKey,
|
cacheKey: CloudRunnerOptions.cacheKey,
|
||||||
maxRetainedWorkspaces: Number.parseInt(CloudRunnerOptions.maxRetainedWorkspaces),
|
retainWorkspace: CloudRunnerOptions.retainWorkspaces,
|
||||||
useLargePackages: CloudRunnerOptions.useLargePackages,
|
useSharedLargePackages: CloudRunnerOptions.useSharedLargePackages,
|
||||||
useCompressionStrategy: CloudRunnerOptions.useCompressionStrategy,
|
useLz4Compression: CloudRunnerOptions.useLz4Compression,
|
||||||
garbageMaxAge: CloudRunnerOptions.garbageMaxAge,
|
maxRetainedWorkspaces: CloudRunnerOptions.maxRetainedWorkspaces,
|
||||||
|
constantGarbageCollection: CloudRunnerOptions.constantGarbageCollection,
|
||||||
|
garbageCollectionMaxAge: CloudRunnerOptions.garbageCollectionMaxAge,
|
||||||
githubChecks: CloudRunnerOptions.githubChecks,
|
githubChecks: CloudRunnerOptions.githubChecks,
|
||||||
asyncWorkflow: CloudRunnerOptions.asyncCloudRunner,
|
|
||||||
githubCheckId: CloudRunnerOptions.githubCheckId,
|
|
||||||
finalHooks: CloudRunnerOptions.finalHooks,
|
|
||||||
skipLfs: CloudRunnerOptions.skipLfs,
|
|
||||||
skipCache: CloudRunnerOptions.skipCache,
|
|
||||||
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
|
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
|
||||||
unityHubVersionOnMac: Input.unityHubVersionOnMac,
|
unityHubVersionOnMac: Input.unityHubVersionOnMac,
|
||||||
dockerWorkspacePath: Input.dockerWorkspacePath,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import fs from 'node:fs';
|
import fs from 'fs';
|
||||||
import Action from './action';
|
import Action from './action';
|
||||||
import Project from './project';
|
import Project from './project';
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ export class CliFunctionsRepository {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GetCliFunctions(key: any) {
|
public static GetCliFunctions(key) {
|
||||||
const results = CliFunctionsRepository.targets.find((x) => x.key === key);
|
const results = CliFunctionsRepository.targets.find((x) => x.key === key);
|
||||||
if (results === undefined || results.length === 0) {
|
if (results === undefined || results.length === 0) {
|
||||||
throw new Error(`no CLI mode found for ${key}`);
|
throw new Error(`no CLI mode found for ${key}`);
|
||||||
|
|
|
@ -2,23 +2,24 @@ import { Command } from 'commander-ts';
|
||||||
import { BuildParameters, CloudRunner, ImageTag, Input } from '..';
|
import { BuildParameters, CloudRunner, ImageTag, Input } from '..';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { ActionYamlReader } from '../input-readers/action-yaml';
|
import { ActionYamlReader } from '../input-readers/action-yaml';
|
||||||
import CloudRunnerLogger from '../cloud-runner/services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../cloud-runner/services/cloud-runner-logger';
|
||||||
import CloudRunnerQueryOverride from '../cloud-runner/options/cloud-runner-query-override';
|
import CloudRunnerQueryOverride from '../cloud-runner/services/cloud-runner-query-override';
|
||||||
import { CliFunction, CliFunctionsRepository } from './cli-functions-repository';
|
import { CliFunction, CliFunctionsRepository } from './cli-functions-repository';
|
||||||
import { Caching } from '../cloud-runner/remote-client/caching';
|
import { Caching } from '../cloud-runner/remote-client/caching';
|
||||||
import { LfsHashing } from '../cloud-runner/services/utility/lfs-hashing';
|
import { LfsHashing } from '../cloud-runner/services/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/services/cloud-runner-options-reader';
|
||||||
import GitHub from '../github';
|
import GitHub from '../github';
|
||||||
import { OptionValues } from 'commander';
|
import { TaskParameterSerializer } from '../cloud-runner/services/task-parameter-serializer';
|
||||||
import { InputKey } from '../input';
|
import { CloudRunnerFolders } from '../cloud-runner/services/cloud-runner-folders';
|
||||||
|
import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system';
|
||||||
|
|
||||||
export class Cli {
|
export class Cli {
|
||||||
public static options: OptionValues | undefined;
|
public static options;
|
||||||
static get isCliMode() {
|
static get isCliMode() {
|
||||||
return Cli.options !== undefined && Cli.options.mode !== undefined && Cli.options.mode !== '';
|
return Cli.options !== undefined && Cli.options.mode !== undefined && Cli.options.mode !== '';
|
||||||
}
|
}
|
||||||
public static query(key: string, alternativeKey: string) {
|
public static query(key, alternativeKey) {
|
||||||
if (Cli.options && Cli.options[key] !== undefined) {
|
if (Cli.options && Cli.options[key] !== undefined) {
|
||||||
return Cli.options[key];
|
return Cli.options[key];
|
||||||
}
|
}
|
||||||
|
@ -52,7 +53,6 @@ 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();
|
||||||
|
|
||||||
|
@ -61,24 +61,22 @@ export class Cli {
|
||||||
|
|
||||||
static async RunCli(): Promise<void> {
|
static async RunCli(): Promise<void> {
|
||||||
GitHub.githubInputEnabled = false;
|
GitHub.githubInputEnabled = false;
|
||||||
if (Cli.options!['populateOverride'] === `true`) {
|
if (Cli.options['populateOverride'] === `true`) {
|
||||||
await CloudRunnerQueryOverride.PopulateQueryOverrideInput();
|
await CloudRunnerQueryOverride.PopulateQueryOverrideInput();
|
||||||
}
|
}
|
||||||
if (Cli.options!['logInput']) {
|
if (Cli.options['logInput']) {
|
||||||
Cli.logInput();
|
Cli.logInput();
|
||||||
}
|
}
|
||||||
const results = CliFunctionsRepository.GetCliFunctions(Cli.options?.mode);
|
const results = CliFunctionsRepository.GetCliFunctions(Cli.options.mode);
|
||||||
CloudRunnerLogger.log(`Entrypoint: ${results.key}`);
|
CloudRunnerLogger.log(`Entrypoint: ${results.key}`);
|
||||||
Cli.options!.versioning = 'None';
|
Cli.options.versioning = 'None';
|
||||||
|
|
||||||
CloudRunner.buildParameters = await BuildParameters.create();
|
const buildParameter = TaskParameterSerializer.readBuildParameterFromEnvironment();
|
||||||
CloudRunner.buildParameters.buildGuid = process.env.BUILD_GUID || ``;
|
|
||||||
CloudRunnerLogger.log(`Build Params:
|
CloudRunnerLogger.log(`Build Params:
|
||||||
${JSON.stringify(CloudRunner.buildParameters, undefined, 4)}
|
${JSON.stringify(buildParameter, undefined, 4)}
|
||||||
`);
|
`);
|
||||||
CloudRunner.lockedWorkspace = process.env.LOCKED_WORKSPACE || ``;
|
CloudRunner.buildParameters = buildParameter;
|
||||||
CloudRunnerLogger.log(`Locked Workspace: ${CloudRunner.lockedWorkspace}`);
|
CloudRunner.lockedWorkspace = process.env.LOCKED_WORKSPACE;
|
||||||
await CloudRunner.setup(CloudRunner.buildParameters);
|
|
||||||
|
|
||||||
return await results.target[results.propertyKey](Cli.options);
|
return await results.target[results.propertyKey](Cli.options);
|
||||||
}
|
}
|
||||||
|
@ -90,15 +88,14 @@ export class Cli {
|
||||||
const properties = CloudRunnerOptionsReader.GetProperties();
|
const properties = CloudRunnerOptionsReader.GetProperties();
|
||||||
for (const element of properties) {
|
for (const element of properties) {
|
||||||
if (
|
if (
|
||||||
element in Input &&
|
Input[element] !== undefined &&
|
||||||
Input[element as InputKey] !== undefined &&
|
Input[element] !== '' &&
|
||||||
Input[element as InputKey] !== '' &&
|
typeof Input[element] !== `function` &&
|
||||||
typeof Input[element as InputKey] !== `function` &&
|
|
||||||
element !== 'length' &&
|
element !== 'length' &&
|
||||||
element !== 'cliOptions' &&
|
element !== 'cliOptions' &&
|
||||||
element !== 'prototype'
|
element !== 'prototype'
|
||||||
) {
|
) {
|
||||||
core.info(`${element} ${Input[element as InputKey]}`);
|
core.info(`${element} ${Input[element]}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.info(`\n`);
|
core.info(`\n`);
|
||||||
|
@ -109,23 +106,19 @@ 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())).BuildResults;
|
return await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@CliFunction(`async-workflow`, `runs a cloud runner build`)
|
@CliFunction(`async-workflow`, `runs a cloud runner build`)
|
||||||
public static async asyncronousWorkflow(): Promise<string> {
|
public static async asyncronousWorkflow(): Promise<string> {
|
||||||
const buildParameter = await BuildParameters.create();
|
const buildParameter = await BuildParameters.create();
|
||||||
const baseImage = new ImageTag(buildParameter);
|
const baseImage = new ImageTag(buildParameter);
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
|
|
||||||
return (await CloudRunner.run(buildParameter, baseImage.toString())).BuildResults;
|
return await CloudRunner.run(buildParameter, baseImage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
@CliFunction(`checks-update`, `runs a cloud runner build`)
|
||||||
public static async checksUpdate() {
|
public static async checksUpdate() {
|
||||||
const buildParameter = await BuildParameters.create();
|
|
||||||
|
|
||||||
await CloudRunner.setup(buildParameter);
|
|
||||||
const input = JSON.parse(process.env.CHECKS_UPDATE || ``);
|
const input = JSON.parse(process.env.CHECKS_UPDATE || ``);
|
||||||
core.info(`Checks Update ${process.env.CHECKS_UPDATE}`);
|
core.info(`Checks Update ${process.env.CHECKS_UPDATE}`);
|
||||||
if (input.mode === `create`) {
|
if (input.mode === `create`) {
|
||||||
|
@ -172,4 +165,46 @@ 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 (!CloudRunner.buildParameters.retainWorkspace) {
|
||||||
|
await CloudRunnerSystem.Run(
|
||||||
|
`rm -r ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.uniqueCloudRunnerJobFolderAbsolute)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await RemoteClient.runCustomHookFiles(`after-build`);
|
||||||
|
|
||||||
|
const parameters = await BuildParameters.create();
|
||||||
|
CloudRunner.setup(parameters);
|
||||||
|
if (parameters.constantGarbageCollection) {
|
||||||
|
await CloudRunnerSystem.Run(
|
||||||
|
`find /${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.buildVolumeFolder)}/ -name '*.*' -mmin +${
|
||||||
|
parameters.garbageCollectionMaxAge * 60
|
||||||
|
} -delete`,
|
||||||
|
);
|
||||||
|
await CloudRunnerSystem.Run(
|
||||||
|
`find ${CloudRunnerFolders.ToLinuxFolder(CloudRunnerFolders.cacheFolderForAllFull)} -name '*.*' -mmin +${
|
||||||
|
parameters.garbageCollectionMaxAge * 60
|
||||||
|
} -delete`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((result) => result(``));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
import { Cli } from '../cli/cli';
|
||||||
|
import CloudRunnerQueryOverride from './services/cloud-runner-query-override';
|
||||||
|
import GitHub from '../github';
|
||||||
|
const core = require('@actions/core');
|
||||||
|
|
||||||
|
class CloudRunnerOptions {
|
||||||
|
// ### ### ###
|
||||||
|
// Input Handling
|
||||||
|
// ### ### ###
|
||||||
|
public static getInput(query) {
|
||||||
|
if (GitHub.githubInputEnabled) {
|
||||||
|
const coreInput = core.getInput(query);
|
||||||
|
if (coreInput && coreInput !== '') {
|
||||||
|
return coreInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const alternativeQuery = CloudRunnerOptions.ToEnvVarFormat(query);
|
||||||
|
|
||||||
|
// Query input sources
|
||||||
|
if (Cli.query(query, alternativeQuery)) {
|
||||||
|
return Cli.query(query, alternativeQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CloudRunnerQueryOverride.query(query, alternativeQuery)) {
|
||||||
|
return CloudRunnerQueryOverride.query(query, alternativeQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env[query] !== undefined) {
|
||||||
|
return process.env[query];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alternativeQuery !== query && process.env[alternativeQuery] !== undefined) {
|
||||||
|
return process.env[alternativeQuery];
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ToEnvVarFormat(input: string) {
|
||||||
|
if (input.toUpperCase() === input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
return input
|
||||||
|
.replace(/([A-Z])/g, ' $1')
|
||||||
|
.trim()
|
||||||
|
.toUpperCase()
|
||||||
|
.replace(/ /g, '_');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Provider parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get region(): string {
|
||||||
|
return CloudRunnerOptions.getInput('region') || 'eu-west-2';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// GitHub parameters
|
||||||
|
// ### ### ###
|
||||||
|
static get githubChecks(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput('githubChecks') || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get githubOwner() {
|
||||||
|
return CloudRunnerOptions.getInput('githubOwner') || CloudRunnerOptions.githubRepo.split(`/`)[0] || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get githubRepoName() {
|
||||||
|
return CloudRunnerOptions.getInput('githubRepoName') || CloudRunnerOptions.githubRepo.split(`/`)[1] || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Git syncronization parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get githubRepo() {
|
||||||
|
return CloudRunnerOptions.getInput('GITHUB_REPOSITORY') || CloudRunnerOptions.getInput('GITHUB_REPO') || undefined;
|
||||||
|
}
|
||||||
|
static get branch() {
|
||||||
|
if (CloudRunnerOptions.getInput(`GITHUB_REF`)) {
|
||||||
|
return CloudRunnerOptions.getInput(`GITHUB_REF`).replace('refs/', '').replace(`head/`, '').replace(`heads/`, '');
|
||||||
|
} else if (CloudRunnerOptions.getInput('branch')) {
|
||||||
|
return CloudRunnerOptions.getInput('branch');
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get gitSha() {
|
||||||
|
if (CloudRunnerOptions.getInput(`GITHUB_SHA`)) {
|
||||||
|
return CloudRunnerOptions.getInput(`GITHUB_SHA`);
|
||||||
|
} else if (CloudRunnerOptions.getInput(`GitSHA`)) {
|
||||||
|
return CloudRunnerOptions.getInput(`GitSHA`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Cloud Runner parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get cloudRunnerBuilderPlatform() {
|
||||||
|
const input = CloudRunnerOptions.getInput('cloudRunnerBuilderPlatform');
|
||||||
|
if (input) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
if (CloudRunnerOptions.cloudRunnerCluster !== 'local') {
|
||||||
|
return 'linux';
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get cloudRunnerBranch() {
|
||||||
|
return CloudRunnerOptions.getInput('cloudRunnerBranch') || 'main';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get cloudRunnerCluster() {
|
||||||
|
if (Cli.isCliMode) {
|
||||||
|
return CloudRunnerOptions.getInput('cloudRunnerCluster') || 'aws';
|
||||||
|
}
|
||||||
|
|
||||||
|
return CloudRunnerOptions.getInput('cloudRunnerCluster') || 'local';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get cloudRunnerCpu() {
|
||||||
|
return CloudRunnerOptions.getInput('cloudRunnerCpu');
|
||||||
|
}
|
||||||
|
|
||||||
|
static get cloudRunnerMemory() {
|
||||||
|
return CloudRunnerOptions.getInput('cloudRunnerMemory');
|
||||||
|
}
|
||||||
|
|
||||||
|
static get customJob() {
|
||||||
|
return CloudRunnerOptions.getInput('customJob') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Custom commands from files parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get customStepFiles() {
|
||||||
|
return CloudRunnerOptions.getInput('customStepFiles')?.split(`,`) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get customHookFiles() {
|
||||||
|
return CloudRunnerOptions.getInput('customHookFiles')?.split(`,`) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Custom commands from yaml parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static customJobHooks() {
|
||||||
|
return CloudRunnerOptions.getInput('customJobHooks') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get postBuildSteps() {
|
||||||
|
return CloudRunnerOptions.getInput('postBuildSteps') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get preBuildSteps() {
|
||||||
|
return CloudRunnerOptions.getInput('preBuildSteps') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Input override handling
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static readInputFromOverrideList() {
|
||||||
|
return CloudRunnerOptions.getInput('readInputFromOverrideList') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static readInputOverrideCommand() {
|
||||||
|
const value = CloudRunnerOptions.getInput('readInputOverrideCommand');
|
||||||
|
|
||||||
|
if (value === 'gcp-secret-manager') {
|
||||||
|
return 'gcloud secrets versions access 1 --secret="{0}"';
|
||||||
|
} else if (value === 'aws-secret-manager') {
|
||||||
|
return 'aws secretsmanager get-secret-value --secret-id {0}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return value || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Aws
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get awsBaseStackName() {
|
||||||
|
return CloudRunnerOptions.getInput('awsBaseStackName') || 'game-ci';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// K8s
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get kubeConfig() {
|
||||||
|
return CloudRunnerOptions.getInput('kubeConfig') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get kubeVolume() {
|
||||||
|
return CloudRunnerOptions.getInput('kubeVolume') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get kubeVolumeSize() {
|
||||||
|
return CloudRunnerOptions.getInput('kubeVolumeSize') || '5Gi';
|
||||||
|
}
|
||||||
|
|
||||||
|
static get kubeStorageClass(): string {
|
||||||
|
return CloudRunnerOptions.getInput('kubeStorageClass') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Caching
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get cacheKey(): string {
|
||||||
|
return CloudRunnerOptions.getInput('cacheKey') || CloudRunnerOptions.branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Utility Parameters
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get cloudRunnerDebug(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput(`cloudRunnerTests`) || CloudRunnerOptions.getInput(`cloudRunnerDebug`) || false;
|
||||||
|
}
|
||||||
|
static get cloudRunnerDebugTree(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput(`cloudRunnerDebugTree`) || false;
|
||||||
|
}
|
||||||
|
static get cloudRunnerDebugEnv(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput(`cloudRunnerDebugEnv`) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get watchCloudRunnerToEnd(): boolean {
|
||||||
|
if (CloudRunnerOptions.asyncCloudRunner) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CloudRunnerOptions.getInput(`watchToEnd`) || true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get asyncCloudRunner(): boolean {
|
||||||
|
return (CloudRunnerOptions.getInput('asyncCloudRunner') || `false`) === `true` || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get useSharedLargePackages(): boolean {
|
||||||
|
return (CloudRunnerOptions.getInput(`useSharedLargePackages`) || 'false') === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get useSharedBuilder(): boolean {
|
||||||
|
return (CloudRunnerOptions.getInput(`useSharedBuilder`) || 'true') === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get useLz4Compression(): boolean {
|
||||||
|
return (CloudRunnerOptions.getInput(`useLz4Compression`) || 'false') === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get useCleanupCron(): boolean {
|
||||||
|
return (CloudRunnerOptions.getInput(`useCleanupCron`) || 'true') === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Retained Workspace
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
public static get retainWorkspaces(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput(`retainWorkspaces`) || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get maxRetainedWorkspaces(): number {
|
||||||
|
return Number(CloudRunnerOptions.getInput(`maxRetainedWorkspaces`)) || 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ### ### ###
|
||||||
|
// Garbage Collection
|
||||||
|
// ### ### ###
|
||||||
|
|
||||||
|
static get constantGarbageCollection(): boolean {
|
||||||
|
return CloudRunnerOptions.getInput(`constantGarbageCollection`) || true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get garbageCollectionMaxAge(): number {
|
||||||
|
return Number(CloudRunnerOptions.getInput(`garbageCollectionMaxAge`)) || 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CloudRunnerOptions;
|
|
@ -1,7 +1,7 @@
|
||||||
import CloudRunnerEnvironmentVariable from './cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from './services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerSecret from './cloud-runner-secret';
|
import CloudRunnerSecret from './services/cloud-runner-secret';
|
||||||
|
|
||||||
export class CloudRunnerStepParameters {
|
export class CloudRunnerStepState {
|
||||||
public image: string;
|
public image: string;
|
||||||
public environment: CloudRunnerEnvironmentVariable[];
|
public environment: CloudRunnerEnvironmentVariable[];
|
||||||
public secrets: CloudRunnerSecret[];
|
public secrets: CloudRunnerSecret[];
|
|
@ -1,43 +1,33 @@
|
||||||
import AwsBuildPlatform from './providers/aws';
|
import AwsBuildPlatform from './providers/aws';
|
||||||
import { BuildParameters, Input } from '..';
|
import { BuildParameters, Input } from '..';
|
||||||
import Kubernetes from './providers/k8s';
|
import Kubernetes from './providers/k8s';
|
||||||
import CloudRunnerLogger from './services/core/cloud-runner-logger';
|
import CloudRunnerLogger from './services/cloud-runner-logger';
|
||||||
import { CloudRunnerStepParameters } from './options/cloud-runner-step-parameters';
|
import { CloudRunnerStepState } from './cloud-runner-step-state';
|
||||||
import { WorkflowCompositionRoot } from './workflows/workflow-composition-root';
|
import { WorkflowCompositionRoot } from './workflows/workflow-composition-root';
|
||||||
import { CloudRunnerError } from './error/cloud-runner-error';
|
import { CloudRunnerError } from './error/cloud-runner-error';
|
||||||
import { TaskParameterSerializer } from './services/core/task-parameter-serializer';
|
import { TaskParameterSerializer } from './services/task-parameter-serializer';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import CloudRunnerSecret from './options/cloud-runner-secret';
|
import CloudRunnerSecret from './services/cloud-runner-secret';
|
||||||
import { ProviderInterface } from './providers/provider-interface';
|
import { ProviderInterface } from './providers/provider-interface';
|
||||||
import CloudRunnerEnvironmentVariable from './options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from './services/cloud-runner-environment-variable';
|
||||||
import TestCloudRunner from './providers/test';
|
import TestCloudRunner from './providers/test';
|
||||||
import LocalCloudRunner from './providers/local';
|
import LocalCloudRunner from './providers/local';
|
||||||
import LocalDockerCloudRunner from './providers/docker';
|
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/shared-workspace-locking';
|
||||||
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;
|
||||||
public static buildParameters: BuildParameters;
|
public static buildParameters: BuildParameters;
|
||||||
private static defaultSecrets: CloudRunnerSecret[];
|
private static defaultSecrets: CloudRunnerSecret[];
|
||||||
private static cloudRunnerEnvironmentVariables: CloudRunnerEnvironmentVariable[];
|
private static cloudRunnerEnvironmentVariables: CloudRunnerEnvironmentVariable[];
|
||||||
static lockedWorkspace: string = ``;
|
static lockedWorkspace: string | undefined;
|
||||||
public static readonly retainedWorkspacePrefix: string = `retained-workspace`;
|
public static readonly retainedWorkspacePrefix: string = `retained-workspace`;
|
||||||
public static get isCloudRunnerEnvironment() {
|
public static githubCheckId;
|
||||||
return process.env[`GITHUB_ACTIONS`] !== `true`;
|
public static setup(buildParameters: BuildParameters) {
|
||||||
}
|
|
||||||
public static get isCloudRunnerAsyncEnvironment() {
|
|
||||||
return process.env[`ASYNC_WORKFLOW`] === `true`;
|
|
||||||
}
|
|
||||||
public static async setup(buildParameters: BuildParameters) {
|
|
||||||
CloudRunnerLogger.setup();
|
CloudRunnerLogger.setup();
|
||||||
CloudRunnerLogger.log(`Setting up cloud runner`);
|
CloudRunnerLogger.log(`Setting up cloud runner`);
|
||||||
CloudRunner.buildParameters = buildParameters;
|
CloudRunner.buildParameters = buildParameters;
|
||||||
if (CloudRunner.buildParameters.githubCheckId === ``) {
|
|
||||||
CloudRunner.buildParameters.githubCheckId = await GitHub.createGitHubCheck(CloudRunner.buildParameters.buildGuid);
|
|
||||||
}
|
|
||||||
CloudRunner.setupSelectedBuildPlatform();
|
CloudRunner.setupSelectedBuildPlatform();
|
||||||
CloudRunner.defaultSecrets = TaskParameterSerializer.readDefaultSecrets();
|
CloudRunner.defaultSecrets = TaskParameterSerializer.readDefaultSecrets();
|
||||||
CloudRunner.cloudRunnerEnvironmentVariables =
|
CloudRunner.cloudRunnerEnvironmentVariables =
|
||||||
|
@ -55,16 +45,15 @@ class CloudRunner {
|
||||||
core.setOutput(
|
core.setOutput(
|
||||||
Input.ToEnvVarFormat(`buildArtifact`),
|
Input.ToEnvVarFormat(`buildArtifact`),
|
||||||
`build-${CloudRunner.buildParameters.buildGuid}.tar${
|
`build-${CloudRunner.buildParameters.buildGuid}.tar${
|
||||||
CloudRunner.buildParameters.useCompressionStrategy ? '.lz4' : ''
|
CloudRunner.buildParameters.useLz4Compression ? '.lz4' : ''
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
FollowLogStreamService.Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static setupSelectedBuildPlatform() {
|
private static setupSelectedBuildPlatform() {
|
||||||
CloudRunnerLogger.log(`Cloud Runner platform selected ${CloudRunner.buildParameters.providerStrategy}`);
|
CloudRunnerLogger.log(`Cloud Runner platform selected ${CloudRunner.buildParameters.cloudRunnerCluster}`);
|
||||||
switch (CloudRunner.buildParameters.providerStrategy) {
|
switch (CloudRunner.buildParameters.cloudRunnerCluster) {
|
||||||
case 'k8s':
|
case 'k8s':
|
||||||
CloudRunner.Provider = new Kubernetes(CloudRunner.buildParameters);
|
CloudRunner.Provider = new Kubernetes(CloudRunner.buildParameters);
|
||||||
break;
|
break;
|
||||||
|
@ -84,21 +73,14 @@ class CloudRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async run(buildParameters: BuildParameters, baseImage: string) {
|
static async run(buildParameters: BuildParameters, baseImage: string) {
|
||||||
if (baseImage.includes(`undefined`)) {
|
CloudRunner.setup(buildParameters);
|
||||||
throw new Error(`baseImage is undefined`);
|
|
||||||
}
|
|
||||||
await CloudRunner.setup(buildParameters);
|
|
||||||
await CloudRunner.Provider.setupWorkflow(
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
CloudRunner.buildParameters,
|
|
||||||
CloudRunner.buildParameters.branch,
|
|
||||||
CloudRunner.defaultSecrets,
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
if (buildParameters.maxRetainedWorkspaces > 0) {
|
CloudRunner.githubCheckId = await GitHub.createGitHubCheck(CloudRunner.buildParameters.buildGuid);
|
||||||
CloudRunner.lockedWorkspace = SharedWorkspaceLocking.NewWorkspaceName();
|
|
||||||
|
|
||||||
const result = await SharedWorkspaceLocking.GetLockedWorkspace(
|
if (buildParameters.retainWorkspace) {
|
||||||
|
CloudRunner.lockedWorkspace = `${CloudRunner.retainedWorkspacePrefix}-${CloudRunner.buildParameters.buildGuid}`;
|
||||||
|
|
||||||
|
const result = await SharedWorkspaceLocking.GetOrCreateLockedWorkspace(
|
||||||
CloudRunner.lockedWorkspace,
|
CloudRunner.lockedWorkspace,
|
||||||
CloudRunner.buildParameters.buildGuid,
|
CloudRunner.buildParameters.buildGuid,
|
||||||
CloudRunner.buildParameters,
|
CloudRunner.buildParameters,
|
||||||
|
@ -112,76 +94,53 @@ class CloudRunner {
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
CloudRunnerLogger.log(`Max retained workspaces reached ${buildParameters.maxRetainedWorkspaces}`);
|
CloudRunnerLogger.log(`Max retained workspaces reached ${buildParameters.maxRetainedWorkspaces}`);
|
||||||
buildParameters.maxRetainedWorkspaces = 0;
|
buildParameters.retainWorkspace = false;
|
||||||
CloudRunner.lockedWorkspace = ``;
|
CloudRunner.lockedWorkspace = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await CloudRunner.updateStatusWithBuildParameters();
|
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Setup shared cloud runner resources');
|
||||||
const output = await new WorkflowCompositionRoot().run(
|
await CloudRunner.Provider.setupWorkflow(
|
||||||
new CloudRunnerStepParameters(
|
CloudRunner.buildParameters.buildGuid,
|
||||||
baseImage,
|
|
||||||
CloudRunner.cloudRunnerEnvironmentVariables,
|
|
||||||
CloudRunner.defaultSecrets,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
await CloudRunner.Provider.cleanupWorkflow(
|
|
||||||
CloudRunner.buildParameters,
|
CloudRunner.buildParameters,
|
||||||
CloudRunner.buildParameters.branch,
|
CloudRunner.buildParameters.branch,
|
||||||
CloudRunner.defaultSecrets,
|
CloudRunner.defaultSecrets,
|
||||||
);
|
);
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
||||||
if (buildParameters.asyncWorkflow && this.isCloudRunnerEnvironment && this.isCloudRunnerAsyncEnvironment) {
|
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, CloudRunner.buildParameters.buildGuid);
|
||||||
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, `success`, `success`, `completed`);
|
const output = await new WorkflowCompositionRoot().run(
|
||||||
}
|
new CloudRunnerStepState(baseImage, CloudRunner.cloudRunnerEnvironmentVariables, CloudRunner.defaultSecrets),
|
||||||
|
);
|
||||||
|
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('Cleanup shared cloud runner resources');
|
||||||
|
await CloudRunner.Provider.cleanupWorkflow(
|
||||||
|
CloudRunner.buildParameters.buildGuid,
|
||||||
|
CloudRunner.buildParameters,
|
||||||
|
CloudRunner.buildParameters.branch,
|
||||||
|
CloudRunner.defaultSecrets,
|
||||||
|
);
|
||||||
|
CloudRunnerLogger.log(`Cleanup complete`);
|
||||||
|
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
||||||
|
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, `success`, `success`, `completed`);
|
||||||
|
|
||||||
if (BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
if (CloudRunner.buildParameters.retainWorkspace) {
|
||||||
const workspace = CloudRunner.lockedWorkspace || ``;
|
|
||||||
await SharedWorkspaceLocking.ReleaseWorkspace(
|
await SharedWorkspaceLocking.ReleaseWorkspace(
|
||||||
workspace,
|
CloudRunner.lockedWorkspace || ``,
|
||||||
CloudRunner.buildParameters.buildGuid,
|
CloudRunner.buildParameters.buildGuid,
|
||||||
CloudRunner.buildParameters,
|
CloudRunner.buildParameters,
|
||||||
);
|
);
|
||||||
const isLocked = await SharedWorkspaceLocking.IsWorkspaceLocked(workspace, CloudRunner.buildParameters);
|
CloudRunner.lockedWorkspace = undefined;
|
||||||
if (isLocked) {
|
|
||||||
throw new Error(
|
|
||||||
`still locked after releasing ${await SharedWorkspaceLocking.GetAllLocksForWorkspace(
|
|
||||||
workspace,
|
|
||||||
buildParameters,
|
|
||||||
)}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
CloudRunner.lockedWorkspace = ``;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await GitHub.triggerWorkflowOnComplete(CloudRunner.buildParameters.finalHooks);
|
|
||||||
|
|
||||||
if (buildParameters.constantGarbageCollection) {
|
if (buildParameters.constantGarbageCollection) {
|
||||||
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageMaxAge, true, true);
|
CloudRunner.Provider.garbageCollect(``, true, buildParameters.garbageCollectionMaxAge, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CloudRunnerResult(buildParameters, output, true, true, false);
|
return output;
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
CloudRunnerLogger.log(JSON.stringify(error, undefined, 4));
|
await GitHub.updateGitHubCheck(CloudRunner.buildParameters.buildGuid, error, `failure`, `completed`);
|
||||||
await GitHub.updateGitHubCheck(
|
|
||||||
CloudRunner.buildParameters.buildGuid,
|
|
||||||
`Failed - Error ${error?.message || error}`,
|
|
||||||
`failure`,
|
|
||||||
`completed`,
|
|
||||||
);
|
|
||||||
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
if (!CloudRunner.buildParameters.isCliMode) core.endGroup();
|
||||||
await CloudRunnerError.handleException(error, CloudRunner.buildParameters, CloudRunner.defaultSecrets);
|
await CloudRunnerError.handleException(error, CloudRunner.buildParameters, CloudRunner.defaultSecrets);
|
||||||
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;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import CloudRunnerLogger from '../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../services/cloud-runner-logger';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import CloudRunner from '../cloud-runner';
|
import CloudRunner from '../cloud-runner';
|
||||||
import CloudRunnerSecret from '../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../services/cloud-runner-secret';
|
||||||
import BuildParameters from '../../build-parameters';
|
import BuildParameters from '../../build-parameters';
|
||||||
|
|
||||||
export class CloudRunnerError {
|
export class CloudRunnerError {
|
||||||
|
@ -9,7 +9,12 @@ 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(buildParameters, buildParameters.branch, secrets);
|
await CloudRunner.Provider.cleanupWorkflow(
|
||||||
|
buildParameters.buildGuid,
|
||||||
|
buildParameters,
|
||||||
|
buildParameters.branch,
|
||||||
|
secrets,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
import { Cli } from '../../cli/cli';
|
|
||||||
import CloudRunnerQueryOverride from './cloud-runner-query-override';
|
|
||||||
import GitHub from '../../github';
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
|
|
||||||
class CloudRunnerOptions {
|
|
||||||
// ### ### ###
|
|
||||||
// Input Handling
|
|
||||||
// ### ### ###
|
|
||||||
public static getInput(query: string): string | undefined {
|
|
||||||
if (GitHub.githubInputEnabled) {
|
|
||||||
const coreInput = core.getInput(query);
|
|
||||||
if (coreInput && coreInput !== '') {
|
|
||||||
return coreInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const alternativeQuery = CloudRunnerOptions.ToEnvVarFormat(query);
|
|
||||||
|
|
||||||
// Query input sources
|
|
||||||
if (Cli.query(query, alternativeQuery)) {
|
|
||||||
return Cli.query(query, alternativeQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CloudRunnerQueryOverride.query(query, alternativeQuery)) {
|
|
||||||
return CloudRunnerQueryOverride.query(query, alternativeQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env[query] !== undefined) {
|
|
||||||
return process.env[query];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alternativeQuery !== query && process.env[alternativeQuery] !== undefined) {
|
|
||||||
return process.env[alternativeQuery];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ToEnvVarFormat(input: string): string {
|
|
||||||
if (input.toUpperCase() === input) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
return input
|
|
||||||
.replace(/([A-Z])/g, ' $1')
|
|
||||||
.trim()
|
|
||||||
.toUpperCase()
|
|
||||||
.replace(/ /g, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Provider parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get region(): string {
|
|
||||||
return CloudRunnerOptions.getInput('region') || 'eu-west-2';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// GitHub parameters
|
|
||||||
// ### ### ###
|
|
||||||
static get githubChecks(): boolean {
|
|
||||||
const value = CloudRunnerOptions.getInput('githubChecks');
|
|
||||||
|
|
||||||
return value === `true` || false;
|
|
||||||
}
|
|
||||||
static get githubCheckId(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubCheckId') || ``;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get githubOwner(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubOwner') || CloudRunnerOptions.githubRepo?.split(`/`)[0] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get githubRepoName(): string {
|
|
||||||
return CloudRunnerOptions.getInput('githubRepoName') || CloudRunnerOptions.githubRepo?.split(`/`)[1] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get finalHooks(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('finalHooks')?.split(',') || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Git syncronization parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get githubRepo(): string | undefined {
|
|
||||||
return CloudRunnerOptions.getInput('GITHUB_REPOSITORY') || CloudRunnerOptions.getInput('GITHUB_REPO') || undefined;
|
|
||||||
}
|
|
||||||
static get branch(): string {
|
|
||||||
if (CloudRunnerOptions.getInput(`GITHUB_REF`)) {
|
|
||||||
return (
|
|
||||||
CloudRunnerOptions.getInput(`GITHUB_REF`)?.replace('refs/', '').replace(`head/`, '').replace(`heads/`, '') || ``
|
|
||||||
);
|
|
||||||
} else if (CloudRunnerOptions.getInput('branch')) {
|
|
||||||
return CloudRunnerOptions.getInput('branch') || ``;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Cloud Runner parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get buildPlatform(): string {
|
|
||||||
const input = CloudRunnerOptions.getInput('buildPlatform');
|
|
||||||
if (input && input !== '') {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
if (CloudRunnerOptions.providerStrategy !== 'local') {
|
|
||||||
return 'linux';
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get cloudRunnerBranch(): string {
|
|
||||||
return CloudRunnerOptions.getInput('cloudRunnerBranch') || 'main';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get providerStrategy(): string {
|
|
||||||
const provider =
|
|
||||||
CloudRunnerOptions.getInput('cloudRunnerCluster') || CloudRunnerOptions.getInput('providerStrategy');
|
|
||||||
if (Cli.isCliMode) {
|
|
||||||
return provider || 'aws';
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider || 'local';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get containerCpu(): string {
|
|
||||||
return CloudRunnerOptions.getInput('containerCpu') || `1024`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get containerMemory(): string {
|
|
||||||
return CloudRunnerOptions.getInput('containerMemory') || `3072`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get customJob(): string {
|
|
||||||
return CloudRunnerOptions.getInput('customJob') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Custom commands from files parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get containerHookFiles(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('containerHookFiles')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
static get commandHookFiles(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('commandHookFiles')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Custom commands from yaml parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get commandHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('commandHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get postBuildContainerHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('postBuildContainerHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get preBuildContainerHooks(): string {
|
|
||||||
return CloudRunnerOptions.getInput('preBuildContainerHooks') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Input override handling
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get pullInputList(): string[] {
|
|
||||||
return CloudRunnerOptions.getInput('pullInputList')?.split(`,`) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
static get inputPullCommand(): string {
|
|
||||||
const value = CloudRunnerOptions.getInput('inputPullCommand');
|
|
||||||
|
|
||||||
if (value === 'gcp-secret-manager') {
|
|
||||||
return 'gcloud secrets versions access 1 --secret="{0}"';
|
|
||||||
} else if (value === 'aws-secret-manager') {
|
|
||||||
return 'aws secretsmanager get-secret-value --secret-id {0}';
|
|
||||||
}
|
|
||||||
|
|
||||||
return value || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Aws
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get awsStackName() {
|
|
||||||
return CloudRunnerOptions.getInput('awsStackName') || 'game-ci';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// K8s
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get kubeConfig(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeConfig') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeVolume(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeVolume') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeVolumeSize(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeVolumeSize') || '25Gi';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get kubeStorageClass(): string {
|
|
||||||
return CloudRunnerOptions.getInput('kubeStorageClass') || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Caching
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get cacheKey(): string {
|
|
||||||
return CloudRunnerOptions.getInput('cacheKey') || CloudRunnerOptions.branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Utility Parameters
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get cloudRunnerDebug(): boolean {
|
|
||||||
return (
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerTests`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebug`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebugTree`) === `true` ||
|
|
||||||
CloudRunnerOptions.getInput(`cloudRunnerDebugEnv`) === `true` ||
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static get skipLfs(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`skipLfs`) === `true`;
|
|
||||||
}
|
|
||||||
static get skipCache(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`skipCache`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get asyncCloudRunner(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput('asyncCloudRunner') === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useLargePackages(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useLargePackages`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useSharedBuilder(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useSharedBuilder`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useCompressionStrategy(): boolean {
|
|
||||||
return CloudRunnerOptions.getInput(`useCompressionStrategy`) === `true`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get useCleanupCron(): boolean {
|
|
||||||
return (CloudRunnerOptions.getInput(`useCleanupCron`) || 'true') === 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Retained Workspace
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
public static get maxRetainedWorkspaces(): string {
|
|
||||||
return CloudRunnerOptions.getInput(`maxRetainedWorkspaces`) || `0`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ### ### ###
|
|
||||||
// Garbage Collection
|
|
||||||
// ### ### ###
|
|
||||||
|
|
||||||
static get garbageMaxAge(): number {
|
|
||||||
return Number(CloudRunnerOptions.getInput(`garbageMaxAge`)) || 24;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CloudRunnerOptions;
|
|
|
@ -1,20 +1,8 @@
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import {
|
import * as SDK from 'aws-sdk';
|
||||||
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';
|
const crypto = require('crypto');
|
||||||
|
|
||||||
export class AWSBaseStack {
|
export class AWSBaseStack {
|
||||||
constructor(baseStackName: string) {
|
constructor(baseStackName: string) {
|
||||||
|
@ -22,49 +10,51 @@ export class AWSBaseStack {
|
||||||
}
|
}
|
||||||
private baseStackName: string;
|
private baseStackName: string;
|
||||||
|
|
||||||
async setupBaseStack(CF: CloudFormation) {
|
async setupBaseStack(CF: SDK.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: DescribeStacksCommandInput = {
|
const describeStackInput: SDK.CloudFormation.DescribeStacksInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
};
|
};
|
||||||
const parametersWithoutHash: Parameter[] = [{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName }];
|
const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [
|
||||||
|
{ 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: Parameter[] = [
|
const parameters: SDK.CloudFormation.Parameter[] = [
|
||||||
...parametersWithoutHash,
|
...parametersWithoutHash,
|
||||||
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
|
||||||
];
|
];
|
||||||
const updateInput: UpdateStackCommandInput = {
|
const updateInput: SDK.CloudFormation.UpdateStackInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
const createStackInput: CreateStackCommandInput = {
|
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
||||||
StackName: baseStackName,
|
StackName: baseStackName,
|
||||||
TemplateBody: baseStack,
|
TemplateBody: baseStack,
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const stacks = await CF.send(
|
const stacks = await CF.listStacks({
|
||||||
new ListStacksCommand({ StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'] }),
|
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.send(new DescribeStacksCommand(describeStackInput));
|
return await CF.describeStacks(describeStackInput).promise();
|
||||||
};
|
};
|
||||||
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.send(new CreateStackCommand(createStackInput));
|
await CF.createStack(createStackInput).promise();
|
||||||
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
|
||||||
}
|
}
|
||||||
const CFState = await describeStack();
|
const CFState = await describeStack();
|
||||||
|
@ -75,13 +65,7 @@ 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 waitUntilStackCreateComplete(
|
await CF.waitFor('stackCreateComplete', describeStackInput).promise();
|
||||||
{
|
|
||||||
client: CF,
|
|
||||||
maxWaitTime: 200,
|
|
||||||
},
|
|
||||||
describeStackInput,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackExists) {
|
if (stackExists) {
|
||||||
|
@ -89,7 +73,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.send(new UpdateStackCommand(updateInput));
|
await CF.updateStack(updateInput).promise();
|
||||||
} 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`);
|
||||||
|
@ -109,13 +93,7 @@ export class AWSBaseStack {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
|
||||||
await waitUntilStackUpdateComplete(
|
await CF.waitFor('stackUpdateComplete', describeStackInput).promise();
|
||||||
{
|
|
||||||
client: CF,
|
|
||||||
maxWaitTime: 200,
|
|
||||||
},
|
|
||||||
describeStackInput,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloudRunnerLogger.log('base stack is now ready');
|
CloudRunnerLogger.log('base stack is now ready');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
||||||
|
|
||||||
export class AWSCloudFormationTemplates {
|
export class AWSCloudFormationTemplates {
|
||||||
public static getParameterTemplate(p1: string) {
|
public static getParameterTemplate(p1) {
|
||||||
return `
|
return `
|
||||||
${p1}:
|
${p1}:
|
||||||
Type: String
|
Type: String
|
||||||
|
@ -9,7 +9,7 @@ export class AWSCloudFormationTemplates {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getSecretTemplate(p1: string) {
|
public static getSecretTemplate(p1) {
|
||||||
return `
|
return `
|
||||||
${p1}Secret:
|
${p1}Secret:
|
||||||
Type: AWS::SecretsManager::Secret
|
Type: AWS::SecretsManager::Secret
|
||||||
|
@ -19,14 +19,14 @@ export class AWSCloudFormationTemplates {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getSecretDefinitionTemplate(p1: string, p2: string) {
|
public static getSecretDefinitionTemplate(p1, p2) {
|
||||||
return `
|
return `
|
||||||
- Name: '${p1}'
|
- Name: '${p1}'
|
||||||
ValueFrom: !Ref ${p2}Secret
|
ValueFrom: !Ref ${p2}Secret
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static insertAtTemplate(template: string, insertionKey: string, insertion: string) {
|
public static insertAtTemplate(template, insertionKey, insertion) {
|
||||||
const index = template.search(insertionKey) + insertionKey.length + '\n'.length;
|
const index = template.search(insertionKey) + insertionKey.length + '\n'.length;
|
||||||
template = [template.slice(0, index), insertion, template.slice(index)].join('');
|
template = [template.slice(0, index), insertion, template.slice(index)].join('');
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { CloudFormation, DescribeStackEventsCommand } from '@aws-sdk/client-cloudformation';
|
import * as SDK from 'aws-sdk';
|
||||||
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: CloudFormation, taskDefStackName: string) {
|
static async handleStackCreationFailure(error: any, CF: SDK.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.send(new DescribeStackEventsCommand({ StackName: taskDefStackName }))).StackEvents;
|
const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents;
|
||||||
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
import {
|
import * as SDK from 'aws-sdk';
|
||||||
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 '../../services/cloud-runner-secret';
|
||||||
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
import { AWSCloudFormationTemplates } from './aws-cloud-formation-templates';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { AWSError } from './aws-error';
|
import { AWSError } from './aws-error';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
import { CleanupCronFormation } from './cloud-formations/cleanup-cron-formation';
|
import { CleanupCronFormation } from './cloud-formations/cleanup-cron-formation';
|
||||||
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
import CloudRunnerOptions from '../../cloud-runner-options';
|
||||||
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
import { TaskDefinitionFormation } from './cloud-formations/task-definition-formation';
|
||||||
|
|
||||||
export class AWSJobStack {
|
export class AWSJobStack {
|
||||||
|
@ -24,7 +16,7 @@ export class AWSJobStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setupCloudFormations(
|
public async setupCloudFormations(
|
||||||
CF: CloudFormation,
|
CF: SDK.CloudFormation,
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
image: string,
|
image: string,
|
||||||
entrypoint: string[],
|
entrypoint: string[],
|
||||||
|
@ -35,19 +27,21 @@ export class AWSJobStack {
|
||||||
): Promise<CloudRunnerAWSTaskDef> {
|
): Promise<CloudRunnerAWSTaskDef> {
|
||||||
const taskDefStackName = `${this.baseStackName}-${buildGuid}`;
|
const taskDefStackName = `${this.baseStackName}-${buildGuid}`;
|
||||||
let taskDefCloudFormation = AWSCloudFormationTemplates.readTaskCloudFormationTemplate();
|
let taskDefCloudFormation = AWSCloudFormationTemplates.readTaskCloudFormationTemplate();
|
||||||
|
const cpu = CloudRunner.buildParameters.cloudRunnerCpu || '1024';
|
||||||
|
const memory = CloudRunner.buildParameters.cloudRunnerMemory || '3072';
|
||||||
taskDefCloudFormation = taskDefCloudFormation.replace(
|
taskDefCloudFormation = taskDefCloudFormation.replace(
|
||||||
`ContainerCpu:
|
`ContainerCpu:
|
||||||
Default: 1024`,
|
Default: 1024`,
|
||||||
`ContainerCpu:
|
`ContainerCpu:
|
||||||
Default: ${Number.parseInt(CloudRunner.buildParameters.containerCpu)}`,
|
Default: ${Number.parseInt(cpu)}`,
|
||||||
);
|
);
|
||||||
taskDefCloudFormation = taskDefCloudFormation.replace(
|
taskDefCloudFormation = taskDefCloudFormation.replace(
|
||||||
`ContainerMemory:
|
`ContainerMemory:
|
||||||
Default: 2048`,
|
Default: 2048`,
|
||||||
`ContainerMemory:
|
`ContainerMemory:
|
||||||
Default: ${Number.parseInt(CloudRunner.buildParameters.containerMemory)}`,
|
Default: ${Number.parseInt(memory)}`,
|
||||||
);
|
);
|
||||||
if (!CloudRunnerOptions.asyncCloudRunner) {
|
if (CloudRunnerOptions.watchCloudRunnerToEnd) {
|
||||||
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
taskDefCloudFormation = AWSCloudFormationTemplates.insertAtTemplate(
|
||||||
taskDefCloudFormation,
|
taskDefCloudFormation,
|
||||||
'# template resources logstream',
|
'# template resources logstream',
|
||||||
|
@ -122,12 +116,12 @@ export class AWSJobStack {
|
||||||
...secretsMappedToCloudFormationParameters,
|
...secretsMappedToCloudFormationParameters,
|
||||||
];
|
];
|
||||||
CloudRunnerLogger.log(
|
CloudRunnerLogger.log(
|
||||||
`Starting AWS job with memory: ${CloudRunner.buildParameters.containerMemory} cpu: ${CloudRunner.buildParameters.containerCpu}`,
|
`Starting AWS job with memory: ${CloudRunner.buildParameters.cloudRunnerMemory} cpu: ${CloudRunner.buildParameters.cloudRunnerCpu}`,
|
||||||
);
|
);
|
||||||
let previousStackExists = true;
|
let previousStackExists = true;
|
||||||
while (previousStackExists) {
|
while (previousStackExists) {
|
||||||
previousStackExists = false;
|
previousStackExists = false;
|
||||||
const stacks = await CF.send(new ListStacksCommand({}));
|
const stacks = await CF.listStacks().promise();
|
||||||
if (!stacks.StackSummaries) {
|
if (!stacks.StackSummaries) {
|
||||||
throw new Error('Faild to get stacks');
|
throw new Error('Faild to get stacks');
|
||||||
}
|
}
|
||||||
|
@ -140,34 +134,23 @@ export class AWSJobStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const createStackInput: CreateStackCommandInput = {
|
const createStackInput: SDK.CloudFormation.CreateStackInput = {
|
||||||
StackName: taskDefStackName,
|
StackName: taskDefStackName,
|
||||||
TemplateBody: taskDefCloudFormation,
|
TemplateBody: taskDefCloudFormation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
Parameters: parameters,
|
Parameters: parameters,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
CloudRunnerLogger.log(`Creating job aws formation ${taskDefStackName}`);
|
||||||
await CF.send(new CreateStackCommand(createStackInput));
|
await CF.createStack(createStackInput).promise();
|
||||||
await waitUntilStackCreateComplete(
|
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
|
||||||
{
|
|
||||||
client: CF,
|
|
||||||
maxWaitTime: 200,
|
|
||||||
},
|
|
||||||
{ StackName: taskDefStackName },
|
|
||||||
);
|
|
||||||
const describeStack = await CF.send(new DescribeStacksCommand({ StackName: taskDefStackName }));
|
|
||||||
for (const parameter of parameters) {
|
|
||||||
if (!describeStack.Stacks?.[0].Parameters?.some((x) => x.ParameterKey === parameter.ParameterKey)) {
|
|
||||||
throw new Error(`Parameter ${parameter.ParameterKey} not found in stack`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await AWSError.handleStackCreationFailure(error, CF, taskDefStackName);
|
await AWSError.handleStackCreationFailure(error, CF, taskDefStackName);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCleanupStackInput: CreateStackCommandInput = {
|
const createCleanupStackInput: SDK.CloudFormation.CreateStackInput = {
|
||||||
StackName: `${taskDefStackName}-cleanup`,
|
StackName: `${taskDefStackName}-cleanup`,
|
||||||
TemplateBody: CleanupCronFormation.formation,
|
TemplateBody: CleanupCronFormation.formation,
|
||||||
Capabilities: ['CAPABILITY_IAM'],
|
Capabilities: ['CAPABILITY_IAM'],
|
||||||
|
@ -197,7 +180,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.send(new CreateStackCommand(createCleanupStackInput));
|
CF.createStack(createCleanupStackInput).promise();
|
||||||
|
|
||||||
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
// await CF.waitFor('stackCreateComplete', { StackName: createCleanupStackInput.StackName }).promise();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -207,15 +190,12 @@ export class AWSJobStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskDefResources = (
|
const taskDefResources = (
|
||||||
await CF.send(
|
await CF.describeStackResources({
|
||||||
new DescribeStackResourcesCommand({
|
StackName: taskDefStackName,
|
||||||
StackName: taskDefStackName,
|
}).promise()
|
||||||
}),
|
|
||||||
)
|
|
||||||
).StackResources;
|
).StackResources;
|
||||||
|
|
||||||
const baseResources = (await CF.send(new DescribeStackResourcesCommand({ StackName: this.baseStackName })))
|
const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources;
|
||||||
.StackResources;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
taskDefStackName,
|
taskDefStackName,
|
||||||
|
|
|
@ -1,34 +1,19 @@
|
||||||
import {
|
import * as AWS from 'aws-sdk';
|
||||||
DescribeTasksCommand,
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
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 * 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';
|
||||||
import * as zlib from 'node:zlib';
|
import * as zlib from 'zlib';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { Input } from '../../..';
|
import { Input } from '../../..';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
import { CommandHookService } from '../../services/hooks/command-hook-service';
|
import { CloudRunnerCustomHooks } from '../../services/cloud-runner-custom-hooks';
|
||||||
import { FollowLogStreamService } from '../../services/core/follow-log-stream-service';
|
import { FollowLogStreamService } from '../../services/follow-log-stream-service';
|
||||||
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
import CloudRunnerOptions from '../../cloud-runner-options';
|
||||||
import GitHub from '../../../github';
|
import GitHub from '../../../github';
|
||||||
|
|
||||||
class AWSTaskRunner {
|
class AWSTaskRunner {
|
||||||
public static ECS: ECS;
|
public static ECS: AWS.ECS;
|
||||||
public static Kinesis: Kinesis;
|
public static Kinesis: AWS.Kinesis;
|
||||||
private static readonly encodedUnderscore = `$252F`;
|
private static readonly encodedUnderscore = `$252F`;
|
||||||
static async runTask(
|
static async runTask(
|
||||||
taskDef: CloudRunnerAWSTaskDef,
|
taskDef: CloudRunnerAWSTaskDef,
|
||||||
|
@ -47,7 +32,7 @@ class AWSTaskRunner {
|
||||||
const streamName =
|
const streamName =
|
||||||
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'KinesisStream')?.PhysicalResourceId || '';
|
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'KinesisStream')?.PhysicalResourceId || '';
|
||||||
|
|
||||||
const runParameters = {
|
const task = await AWSTaskRunner.ECS.runTask({
|
||||||
cluster,
|
cluster,
|
||||||
taskDefinition,
|
taskDefinition,
|
||||||
platformVersion: '1.4.0',
|
platformVersion: '1.4.0',
|
||||||
|
@ -56,7 +41,7 @@ class AWSTaskRunner {
|
||||||
{
|
{
|
||||||
name: taskDef.taskDefStackName,
|
name: taskDef.taskDefStackName,
|
||||||
environment,
|
environment,
|
||||||
command: ['-c', CommandHookService.ApplyHooksToCommands(commands, CloudRunner.buildParameters)],
|
command: ['-c', CloudRunnerCustomHooks.ApplyHooksToCommands(commands, CloudRunner.buildParameters)],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -68,23 +53,16 @@ class AWSTaskRunner {
|
||||||
securityGroups: [ContainerSecurityGroup],
|
securityGroups: [ContainerSecurityGroup],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}).promise();
|
||||||
|
|
||||||
if (JSON.stringify(runParameters.overrides.containerOverrides).length > 8192) {
|
|
||||||
CloudRunnerLogger.log(JSON.stringify(runParameters.overrides.containerOverrides, undefined, 4));
|
|
||||||
throw new Error(`Container Overrides length must be at most 8192`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const task = await AWSTaskRunner.ECS.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);
|
||||||
CloudRunnerLogger.log(
|
CloudRunnerLogger.log(
|
||||||
`Cloud runner job status is running ${(await AWSTaskRunner.describeTasks(cluster, taskArn))?.lastStatus} Async:${
|
`Cloud runner job status is running ${(await AWSTaskRunner.describeTasks(cluster, taskArn))?.lastStatus} Watch:${
|
||||||
CloudRunnerOptions.asyncCloudRunner
|
CloudRunnerOptions.watchCloudRunnerToEnd
|
||||||
}`,
|
} Async:${CloudRunnerOptions.asyncCloudRunner}`,
|
||||||
);
|
);
|
||||||
if (CloudRunnerOptions.asyncCloudRunner) {
|
if (!CloudRunnerOptions.watchCloudRunnerToEnd) {
|
||||||
const shouldCleanup: boolean = false;
|
const shouldCleanup: boolean = false;
|
||||||
const output: string = '';
|
const output: string = '';
|
||||||
CloudRunnerLogger.log(`Watch Cloud Runner To End: false`);
|
CloudRunnerLogger.log(`Watch Cloud Runner To End: false`);
|
||||||
|
@ -94,42 +72,31 @@ class AWSTaskRunner {
|
||||||
|
|
||||||
CloudRunnerLogger.log(`Streaming...`);
|
CloudRunnerLogger.log(`Streaming...`);
|
||||||
const { output, shouldCleanup } = await this.streamLogsUntilTaskStops(cluster, taskArn, streamName);
|
const { output, shouldCleanup } = await this.streamLogsUntilTaskStops(cluster, taskArn, streamName);
|
||||||
let exitCode;
|
await new Promise((resolve) => resolve(5000));
|
||||||
let containerState;
|
const taskData = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
||||||
let taskData;
|
const containerState = taskData.containers?.[0];
|
||||||
while (exitCode === undefined) {
|
const exitCode = containerState?.exitCode || undefined;
|
||||||
await new Promise((resolve) => resolve(10000));
|
|
||||||
taskData = await AWSTaskRunner.describeTasks(cluster, taskArn);
|
|
||||||
containerState = taskData.containers?.[0];
|
|
||||||
exitCode = containerState?.exitCode;
|
|
||||||
}
|
|
||||||
CloudRunnerLogger.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
CloudRunnerLogger.log(`Container State: ${JSON.stringify(containerState, undefined, 4)}`);
|
||||||
if (exitCode === undefined) {
|
const wasSuccessful = exitCode === 0 || (exitCode === undefined && taskData.lastStatus === 'RUNNING');
|
||||||
CloudRunnerLogger.logWarning(`Undefined exitcode for container`);
|
|
||||||
}
|
|
||||||
const wasSuccessful = exitCode === 0;
|
|
||||||
if (wasSuccessful) {
|
if (wasSuccessful) {
|
||||||
CloudRunnerLogger.log(`Cloud runner job has finished successfully`);
|
CloudRunnerLogger.log(`Cloud runner job has finished successfully`);
|
||||||
|
|
||||||
return { output, shouldCleanup };
|
return { output, shouldCleanup };
|
||||||
|
} else {
|
||||||
|
if (taskData.stoppedReason === 'Essential container in task exited' && exitCode === 1) {
|
||||||
|
throw new Error('Container exited with code 1');
|
||||||
|
}
|
||||||
|
const message = `Cloud runner job exit code ${exitCode}`;
|
||||||
|
taskData.overrides = undefined;
|
||||||
|
taskData.attachments = undefined;
|
||||||
|
CloudRunnerLogger.log(`${message} ${JSON.stringify(taskData, undefined, 4)}`);
|
||||||
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskData?.stoppedReason === 'Essential container in task exited' && exitCode === 1) {
|
|
||||||
throw new Error('Container exited with code 1');
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Task failed`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
private static async waitUntilTaskRunning(taskArn: string, cluster: string) {
|
||||||
try {
|
try {
|
||||||
await waitUntilTasksRunning(
|
await AWSTaskRunner.ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
|
||||||
{
|
|
||||||
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));
|
||||||
|
@ -145,7 +112,10 @@ class AWSTaskRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async describeTasks(clusterName: string, taskArn: string) {
|
static async describeTasks(clusterName: string, taskArn: string) {
|
||||||
const tasks = await AWSTaskRunner.ECS.send(new DescribeTasksCommand({ cluster: clusterName, tasks: [taskArn] }));
|
const tasks = await AWSTaskRunner.ECS.describeTasks({
|
||||||
|
cluster: clusterName,
|
||||||
|
tasks: [taskArn],
|
||||||
|
}).promise();
|
||||||
if (tasks.tasks?.[0]) {
|
if (tasks.tasks?.[0]) {
|
||||||
return tasks.tasks?.[0];
|
return tasks.tasks?.[0];
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,7 +129,7 @@ class AWSTaskRunner {
|
||||||
const stream = await AWSTaskRunner.getLogStream(kinesisStreamName);
|
const stream = await AWSTaskRunner.getLogStream(kinesisStreamName);
|
||||||
let iterator = await AWSTaskRunner.getLogIterator(stream);
|
let iterator = await AWSTaskRunner.getLogIterator(stream);
|
||||||
|
|
||||||
const logBaseUrl = `https://${Input.region}.console.aws.amazon.com/cloudwatch/home?region=${Input.region}#logsV2:log-groups/log-group/${CloudRunner.buildParameters.awsStackName}${AWSTaskRunner.encodedUnderscore}${CloudRunner.buildParameters.awsStackName}-${CloudRunner.buildParameters.buildGuid}`;
|
const logBaseUrl = `https://${Input.region}.console.aws.amazon.com/cloudwatch/home?region=${Input.region}#logsV2:log-groups/log-group/${CloudRunner.buildParameters.awsBaseStackName}${AWSTaskRunner.encodedUnderscore}${CloudRunner.buildParameters.awsBaseStackName}-${CloudRunner.buildParameters.buildGuid}`;
|
||||||
CloudRunnerLogger.log(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`);
|
CloudRunnerLogger.log(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`);
|
||||||
await GitHub.updateGitHubCheck(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`, ``);
|
await GitHub.updateGitHubCheck(`You view the log stream on AWS Cloud Watch: ${logBaseUrl}`, ``);
|
||||||
let shouldReadLogs = true;
|
let shouldReadLogs = true;
|
||||||
|
@ -187,7 +157,9 @@ class AWSTaskRunner {
|
||||||
output: string,
|
output: string,
|
||||||
shouldCleanup: boolean,
|
shouldCleanup: boolean,
|
||||||
) {
|
) {
|
||||||
const records = await AWSTaskRunner.Kinesis.send(new GetRecordsCommand({ ShardIterator: iterator }));
|
const records = await AWSTaskRunner.Kinesis.getRecords({
|
||||||
|
ShardIterator: iterator,
|
||||||
|
}).promise();
|
||||||
iterator = records.NextShardIterator || '';
|
iterator = records.NextShardIterator || '';
|
||||||
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
({ shouldReadLogs, output, shouldCleanup } = AWSTaskRunner.logRecords(
|
||||||
records,
|
records,
|
||||||
|
@ -200,7 +172,7 @@ class AWSTaskRunner {
|
||||||
return { iterator, shouldReadLogs, output, shouldCleanup };
|
return { iterator, shouldReadLogs, output, shouldCleanup };
|
||||||
}
|
}
|
||||||
|
|
||||||
private static checkStreamingShouldContinue(taskData: Task, timestamp: number, shouldReadLogs: boolean) {
|
private static checkStreamingShouldContinue(taskData: AWS.ECS.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');
|
||||||
}
|
}
|
||||||
|
@ -220,21 +192,22 @@ class AWSTaskRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static logRecords(
|
private static logRecords(
|
||||||
records: GetRecordsCommandOutput,
|
records,
|
||||||
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 (let index = 0; index < records.Records.length; index++) {
|
||||||
const json = JSON.parse(
|
const json = JSON.parse(
|
||||||
zlib.gunzipSync(Buffer.from(record.Data as unknown as string, 'base64')).toString('utf8'),
|
zlib.gunzipSync(Buffer.from(records.Records[index].Data as string, 'base64')).toString('utf8'),
|
||||||
);
|
);
|
||||||
if (json.messageType === 'DATA_MESSAGE') {
|
if (json.messageType === 'DATA_MESSAGE') {
|
||||||
for (const logEvent of json.logEvents) {
|
for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) {
|
||||||
|
const message = json.logEvents[logEventsIndex].message;
|
||||||
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
||||||
logEvent.message,
|
message,
|
||||||
shouldReadLogs,
|
shouldReadLogs,
|
||||||
shouldCleanup,
|
shouldCleanup,
|
||||||
output,
|
output,
|
||||||
|
@ -248,19 +221,19 @@ class AWSTaskRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogStream(kinesisStreamName: string) {
|
private static async getLogStream(kinesisStreamName: string) {
|
||||||
return await AWSTaskRunner.Kinesis.send(new DescribeStreamCommand({ StreamName: kinesisStreamName }));
|
return await AWSTaskRunner.Kinesis.describeStream({
|
||||||
|
StreamName: kinesisStreamName,
|
||||||
|
}).promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async getLogIterator(stream: DescribeStreamCommandOutput) {
|
private static async getLogIterator(stream) {
|
||||||
return (
|
return (
|
||||||
(
|
(
|
||||||
await AWSTaskRunner.Kinesis.send(
|
await AWSTaskRunner.Kinesis.getShardIterator({
|
||||||
new GetShardIteratorCommand({
|
ShardIteratorType: 'TRIM_HORIZON',
|
||||||
ShardIteratorType: 'TRIM_HORIZON',
|
StreamName: stream.StreamDescription.StreamName,
|
||||||
StreamName: stream.StreamDescription?.StreamName ?? '',
|
ShardId: stream.StreamDescription.Shards[0].ShardId,
|
||||||
ShardId: stream.StreamDescription?.Shards?.[0]?.ShardId || '',
|
}).promise()
|
||||||
}),
|
|
||||||
)
|
|
||||||
).ShardIterator || ''
|
).ShardIterator || ''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
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 get formation(): string {
|
public static readonly formation: string = `AWSTemplateFormatVersion: 2010-09-09
|
||||||
return `AWSTemplateFormatVersion: 2010-09-09
|
|
||||||
Description: ${TaskDefinitionFormation.description}
|
Description: ${TaskDefinitionFormation.description}
|
||||||
Parameters:
|
Parameters:
|
||||||
EnvironmentName:
|
EnvironmentName:
|
||||||
|
@ -29,11 +26,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: ${CloudRunner.buildParameters.containerCpu}
|
Default: 1024
|
||||||
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: ${CloudRunner.buildParameters.containerMemory}
|
Default: 2048
|
||||||
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:
|
||||||
|
@ -95,7 +92,7 @@ Resources:
|
||||||
EFSVolumeConfiguration:
|
EFSVolumeConfiguration:
|
||||||
FilesystemId:
|
FilesystemId:
|
||||||
'Fn::ImportValue': !Sub '${'${EnvironmentName}'}:EfsFileStorageId'
|
'Fn::ImportValue': !Sub '${'${EnvironmentName}'}:EfsFileStorageId'
|
||||||
TransitEncryption: DISABLED
|
TransitEncryption: ENABLED
|
||||||
RequiresCompatibilities:
|
RequiresCompatibilities:
|
||||||
- FARGATE
|
- FARGATE
|
||||||
ExecutionRoleArn:
|
ExecutionRoleArn:
|
||||||
|
@ -138,7 +135,6 @@ 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 { StackResource } from '@aws-sdk/client-cloudformation';
|
import * as AWS from 'aws-sdk';
|
||||||
|
|
||||||
class CloudRunnerAWSTaskDef {
|
class CloudRunnerAWSTaskDef {
|
||||||
public taskDefStackName!: string;
|
public taskDefStackName!: string;
|
||||||
public taskDefCloudFormation!: string;
|
public taskDefCloudFormation!: string;
|
||||||
public taskDefResources: StackResource[] | undefined;
|
public taskDefResources: AWS.CloudFormation.StackResources | undefined;
|
||||||
public baseResources: StackResource[] | undefined;
|
public baseResources: AWS.CloudFormation.StackResources | undefined;
|
||||||
}
|
}
|
||||||
export default CloudRunnerAWSTaskDef;
|
export default CloudRunnerAWSTaskDef;
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import { CloudFormation, DeleteStackCommand, waitUntilStackDeleteComplete } from '@aws-sdk/client-cloudformation';
|
import * as SDK from 'aws-sdk';
|
||||||
import { ECS as ECSClient } from '@aws-sdk/client-ecs';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import { Kinesis } from '@aws-sdk/client-kinesis';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
|
||||||
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
|
||||||
import AwsTaskRunner from './aws-task-runner';
|
import AwsTaskRunner from './aws-task-runner';
|
||||||
import { ProviderInterface } from '../provider-interface';
|
import { ProviderInterface } from '../provider-interface';
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { AWSJobStack as AwsJobStack } from './aws-job-stack';
|
import { AWSJobStack as AwsJobStack } from './aws-job-stack';
|
||||||
import { AWSBaseStack as AwsBaseStack } from './aws-base-stack';
|
import { AWSBaseStack as AwsBaseStack } from './aws-base-stack';
|
||||||
import { Input } from '../../..';
|
import { Input } from '../../..';
|
||||||
|
@ -15,13 +13,13 @@ import { GarbageCollectionService } from './services/garbage-collection-service'
|
||||||
import { ProviderResource } from '../provider-resource';
|
import { ProviderResource } from '../provider-resource';
|
||||||
import { ProviderWorkflow } from '../provider-workflow';
|
import { ProviderWorkflow } from '../provider-workflow';
|
||||||
import { TaskService } from './services/task-service';
|
import { TaskService } from './services/task-service';
|
||||||
import CloudRunnerOptions from '../../options/cloud-runner-options';
|
import CloudRunnerOptions from '../../cloud-runner-options';
|
||||||
|
|
||||||
class AWSBuildEnvironment implements ProviderInterface {
|
class AWSBuildEnvironment implements ProviderInterface {
|
||||||
private baseStackName: string;
|
private baseStackName: string;
|
||||||
|
|
||||||
constructor(buildParameters: BuildParameters) {
|
constructor(buildParameters: BuildParameters) {
|
||||||
this.baseStackName = buildParameters.awsStackName;
|
this.baseStackName = buildParameters.awsBaseStackName;
|
||||||
}
|
}
|
||||||
async listResources(): Promise<ProviderResource[]> {
|
async listResources(): Promise<ProviderResource[]> {
|
||||||
await TaskService.getCloudFormationJobStacks();
|
await TaskService.getCloudFormationJobStacks();
|
||||||
|
@ -59,6 +57,8 @@ 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
|
||||||
|
@ -75,11 +75,7 @@ class AWSBuildEnvironment implements ProviderInterface {
|
||||||
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 }[],
|
||||||
) {
|
) {}
|
||||||
process.env.AWS_REGION = Input.region;
|
|
||||||
const CF = new CloudFormation({ region: Input.region });
|
|
||||||
await new AwsBaseStack(this.baseStackName).setupBaseStack(CF);
|
|
||||||
}
|
|
||||||
|
|
||||||
async runTaskInWorkflow(
|
async runTaskInWorkflow(
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
|
@ -91,13 +87,15 @@ 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 ECSClient({ region: Input.region });
|
const ECS = new SDK.ECS();
|
||||||
const CF = new CloudFormation({ region: Input.region });
|
const CF = new SDK.CloudFormation();
|
||||||
AwsTaskRunner.ECS = ECS;
|
AwsTaskRunner.ECS = ECS;
|
||||||
AwsTaskRunner.Kinesis = new Kinesis({ region: Input.region });
|
AwsTaskRunner.Kinesis = new SDK.Kinesis();
|
||||||
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();
|
||||||
|
|
||||||
|
await new AwsBaseStack(this.baseStackName).setupBaseStack(CF);
|
||||||
const taskDef = await new AwsJobStack(this.baseStackName).setupCloudFormations(
|
const taskDef = await new AwsJobStack(this.baseStackName).setupCloudFormations(
|
||||||
CF,
|
CF,
|
||||||
buildGuid,
|
buildGuid,
|
||||||
|
@ -131,31 +129,20 @@ class AWSBuildEnvironment implements ProviderInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async cleanupResources(CF: CloudFormation, taskDef: CloudRunnerAWSTaskDef) {
|
async cleanupResources(CF: SDK.CloudFormation, taskDef: CloudRunnerAWSTaskDef) {
|
||||||
CloudRunnerLogger.log('Cleanup starting');
|
CloudRunnerLogger.log('Cleanup starting');
|
||||||
await CF.send(new DeleteStackCommand({ StackName: taskDef.taskDefStackName }));
|
await CF.deleteStack({
|
||||||
|
StackName: taskDef.taskDefStackName,
|
||||||
|
}).promise();
|
||||||
if (CloudRunnerOptions.useCleanupCron) {
|
if (CloudRunnerOptions.useCleanupCron) {
|
||||||
await CF.send(new DeleteStackCommand({ StackName: `${taskDef.taskDefStackName}-cleanup` }));
|
await CF.deleteStack({
|
||||||
|
StackName: `${taskDef.taskDefStackName}-cleanup`,
|
||||||
|
}).promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitUntilStackDeleteComplete(
|
await CF.waitFor('stackDeleteComplete', {
|
||||||
{
|
StackName: taskDef.taskDefStackName,
|
||||||
client: CF,
|
}).promise();
|
||||||
maxWaitTime: 200,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,17 +1,10 @@
|
||||||
import {
|
import AWS from 'aws-sdk';
|
||||||
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/cloud-runner-logger';
|
||||||
import { TaskService } from './task-service';
|
import { TaskService } from './task-service';
|
||||||
|
|
||||||
export class GarbageCollectionService {
|
export class GarbageCollectionService {
|
||||||
static isOlderThan1day(date: Date) {
|
static isOlderThan1day(date: any) {
|
||||||
const ageDate = new Date(date.getTime() - Date.now());
|
const ageDate = new Date(date.getTime() - Date.now());
|
||||||
|
|
||||||
return ageDate.getDay() > 0;
|
return ageDate.getDay() > 0;
|
||||||
|
@ -19,25 +12,23 @@ 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 CloudFormation({ region: Input.region });
|
const CF = new AWS.CloudFormation();
|
||||||
const ecs = new ECS({ region: Input.region });
|
const ecs = new AWS.ECS();
|
||||||
const cwl = new CloudWatchLogs({ region: Input.region });
|
const cwl = new AWS.CloudWatchLogs();
|
||||||
const taskDefinitionsInUse = new Array();
|
const taskDefinitionsInUse = new Array();
|
||||||
const tasks = await TaskService.getTasks();
|
const tasks = await TaskService.getTasks();
|
||||||
|
|
||||||
for (const task of tasks) {
|
for (const task of tasks) {
|
||||||
const { taskElement, element } = task;
|
const { taskElement, element } = task;
|
||||||
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.send(new StopTaskCommand({ task: taskElement.taskArn || '', cluster: element }));
|
await ecs.stopTask({ task: taskElement.taskArn || '', cluster: element }).promise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const jobStacks = await TaskService.getCloudFormationJobStacks();
|
const jobStacks = await TaskService.getCloudFormationJobStacks();
|
||||||
for (const element of jobStacks) {
|
for (const element of jobStacks) {
|
||||||
if (
|
if (
|
||||||
(await CF.send(new DescribeStackResourcesCommand({ StackName: element.StackName }))).StackResources?.some(
|
(await CF.describeStackResources({ StackName: element.StackName }).promise()).StackResources?.some(
|
||||||
(x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId),
|
(x) => x.ResourceType === 'AWS::ECS::TaskDefinition' && taskDefinitionsInUse.includes(x.PhysicalResourceId),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -45,30 +36,25 @@ 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`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
|
||||||
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();
|
||||||
for (const element of logGroups) {
|
for (const element of logGroups) {
|
||||||
if (
|
if (
|
||||||
deleteResources &&
|
deleteResources &&
|
||||||
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!)))
|
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.createdAt)))
|
||||||
) {
|
) {
|
||||||
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
|
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
|
||||||
await cwl.send(new DeleteLogGroupCommand({ logGroupName: element.logGroupName || '' }));
|
await cwl.deleteLogGroup({ logGroupName: element.logGroupName || '' }).promise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,9 @@
|
||||||
import {
|
import AWS from 'aws-sdk';
|
||||||
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/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';
|
||||||
|
|
||||||
export class TaskService {
|
export class TaskService {
|
||||||
|
@ -39,24 +18,20 @@ export class TaskService {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
public static async getCloudFormationJobStacks() {
|
public static async getCloudFormationJobStacks() {
|
||||||
const result: StackSummary[] = [];
|
const result: any[] = [];
|
||||||
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 CloudFormation({ region: Input.region });
|
const CF = new AWS.CloudFormation();
|
||||||
const stacks =
|
const stacks =
|
||||||
(await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
|
(await CF.listStacks().promise()).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) {
|
||||||
if (!element.CreationTime) {
|
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime());
|
||||||
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(
|
||||||
|
@ -66,18 +41,14 @@ export class TaskService {
|
||||||
result.push(element);
|
result.push(element);
|
||||||
}
|
}
|
||||||
const baseStacks =
|
const baseStacks =
|
||||||
(await CF.send(new ListStacksCommand({}))).StackSummaries?.filter(
|
(await CF.listStacks().promise()).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) {
|
||||||
if (!element.CreationTime) {
|
const ageDate: Date = new Date(Date.now() - element.CreationTime.getTime());
|
||||||
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(
|
||||||
|
@ -91,22 +62,22 @@ export class TaskService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static async getTasks() {
|
public static async getTasks() {
|
||||||
const result: { taskElement: Task; element: string }[] = [];
|
const result: any[] = [];
|
||||||
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 ECS({ region: Input.region });
|
const ecs = new AWS.ECS();
|
||||||
const clusters = (await ecs.send(new ListClustersCommand({}))).clusterArns || [];
|
const clusters = (await ecs.listClusters().promise()).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: ListTasksCommandInput = {
|
const input: AWS.ECS.ListTasksRequest = {
|
||||||
cluster: element,
|
cluster: element,
|
||||||
};
|
};
|
||||||
|
|
||||||
const list = (await ecs.send(new ListTasksCommand(input))).taskArns || [];
|
const list = (await ecs.listTasks(input).promise()).taskArns || [];
|
||||||
if (list.length > 0) {
|
if (list.length > 0) {
|
||||||
const describeInput: DescribeTasksCommandInput = { tasks: list, cluster: element };
|
const describeInput: AWS.ECS.DescribeTasksRequest = { tasks: list, cluster: element };
|
||||||
const describeList = (await ecs.send(new DescribeTasksCommand(describeInput))).tasks || [];
|
const describeList = (await ecs.describeTasks(describeInput).promise()).tasks || [];
|
||||||
if (describeList.length === 0) {
|
if (describeList.length === 0) {
|
||||||
CloudRunnerLogger.log(`No Tasks`);
|
CloudRunnerLogger.log(`No Tasks`);
|
||||||
continue;
|
continue;
|
||||||
|
@ -132,48 +103,37 @@ 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 CloudFormation({ region: Input.region });
|
const CF = new AWS.CloudFormation();
|
||||||
try {
|
const stack = (await CF.listStacks().promise()).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
|
||||||
const stack =
|
const stackInfo = (await CF.describeStackResources({ StackName: job }).promise()) || undefined;
|
||||||
(await CF.send(new ListStacksCommand({}))).StackSummaries?.find((_x) => _x.StackName === job) || undefined;
|
const stackInfo2 = (await CF.describeStacks({ StackName: job }).promise()) || undefined;
|
||||||
const stackInfo = (await CF.send(new DescribeStackResourcesCommand({ StackName: job }))) || undefined;
|
if (stack === undefined) {
|
||||||
const stackInfo2 = (await CF.send(new DescribeStacksCommand({ StackName: job }))) || undefined;
|
throw new Error('stack not defined');
|
||||||
if (stack === undefined) {
|
}
|
||||||
throw new Error('stack not defined');
|
const ageDate: Date = new Date(Date.now() - stack.CreationTime.getTime());
|
||||||
}
|
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: Array<LogGroup> = [];
|
const result: any[] = [];
|
||||||
process.env.AWS_REGION = Input.region;
|
process.env.AWS_REGION = Input.region;
|
||||||
const ecs = new CloudWatchLogs();
|
const ecs = new AWS.CloudWatchLogs();
|
||||||
let logStreamInput: DescribeLogGroupsCommandInput = {
|
let logStreamInput: AWS.CloudWatchLogs.DescribeLogGroupsRequest = {
|
||||||
/* logGroupNamePrefix: 'game-ci' */
|
/* logGroupNamePrefix: 'game-ci' */
|
||||||
};
|
};
|
||||||
let logGroupsDescribe = await ecs.send(new DescribeLogGroupsCommand(logStreamInput));
|
let logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise();
|
||||||
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.send(new DescribeLogGroupsCommand(logStreamInput));
|
logGroupsDescribe = await ecs.describeLogGroups(logStreamInput).promise();
|
||||||
logGroups.push(...(logGroupsDescribe?.logGroups || []));
|
logGroups.push(...(logGroupsDescribe?.logGroups || []));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,12 +157,11 @@ 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 S3({ region: Input.region });
|
const s3 = new AWS.S3();
|
||||||
const listRequest: ListObjectsCommandInput = {
|
const listRequest: ListObjectsRequest = {
|
||||||
Bucket: CloudRunner.buildParameters.awsStackName,
|
Bucket: CloudRunner.buildParameters.awsBaseStackName,
|
||||||
};
|
};
|
||||||
|
const results = await s3.listObjects(listRequest).promise();
|
||||||
const results = await s3.send(new ListObjectsCommand(listRequest));
|
|
||||||
|
|
||||||
return results.Contents || [];
|
return results.Contents || [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { ProviderInterface } from '../provider-interface';
|
import { ProviderInterface } from '../provider-interface';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import Docker from '../../../docker';
|
import Docker from '../../../docker';
|
||||||
import { Action } from '../../..';
|
import { Action } from '../../..';
|
||||||
import { writeFileSync } from 'node:fs';
|
import { writeFileSync } from 'fs';
|
||||||
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 { CloudRunnerSystem } from '../../services/core/cloud-runner-system';
|
import { CloudRunnerSystem } from '../../services/cloud-runner-system';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'fs';
|
||||||
import { CommandHookService } from '../../services/hooks/command-hook-service';
|
|
||||||
import { StringKeyValuePair } from '../../../shared-types';
|
|
||||||
|
|
||||||
class LocalDockerCloudRunner implements ProviderInterface {
|
class LocalDockerCloudRunner implements ProviderInterface {
|
||||||
public buildParameters!: BuildParameters;
|
public buildParameters: BuildParameters | undefined;
|
||||||
|
|
||||||
listResources(): Promise<ProviderResource[]> {
|
listResources(): Promise<ProviderResource[]> {
|
||||||
return new Promise((resolve) => resolve([]));
|
return new Promise((resolve) => resolve([]));
|
||||||
|
@ -41,6 +39,7 @@ 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,
|
||||||
|
@ -51,14 +50,14 @@ class LocalDockerCloudRunner implements ProviderInterface {
|
||||||
if (
|
if (
|
||||||
fs.existsSync(
|
fs.existsSync(
|
||||||
`${workspace}/cloud-runner-cache/cache/build/build-${buildParameters.buildGuid}.tar${
|
`${workspace}/cloud-runner-cache/cache/build/build-${buildParameters.buildGuid}.tar${
|
||||||
CloudRunner.buildParameters.useCompressionStrategy ? '.lz4' : ''
|
CloudRunner.buildParameters.useLz4Compression ? '.lz4' : ''
|
||||||
}`,
|
}`,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
await CloudRunnerSystem.Run(`ls ${workspace}/cloud-runner-cache/cache/build/`);
|
await CloudRunnerSystem.Run(`ls ${workspace}/cloud-runner-cache/cache/build/`);
|
||||||
await CloudRunnerSystem.Run(
|
await CloudRunnerSystem.Run(
|
||||||
`rm -r ${workspace}/cloud-runner-cache/cache/build/build-${buildParameters.buildGuid}.tar${
|
`rm -r ${workspace}/cloud-runner-cache/cache/build/build-${buildParameters.buildGuid}.tar${
|
||||||
CloudRunner.buildParameters.useCompressionStrategy ? '.lz4' : ''
|
CloudRunner.buildParameters.useLz4Compression ? '.lz4' : ''
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +86,7 @@ class LocalDockerCloudRunner implements ProviderInterface {
|
||||||
CloudRunnerLogger.log(commands);
|
CloudRunnerLogger.log(commands);
|
||||||
|
|
||||||
const { workspace, actionFolder } = Action;
|
const { workspace, actionFolder } = Action;
|
||||||
const content: StringKeyValuePair[] = [];
|
const content: any[] = [];
|
||||||
for (const x of secrets) {
|
for (const x of secrets) {
|
||||||
content.push({ name: x.EnvironmentVariable, value: x.ParameterValue });
|
content.push({ name: x.EnvironmentVariable, value: x.ParameterValue });
|
||||||
}
|
}
|
||||||
|
@ -118,7 +117,7 @@ set -e
|
||||||
mkdir -p /github/workspace/cloud-runner-cache
|
mkdir -p /github/workspace/cloud-runner-cache
|
||||||
mkdir -p /data/cache
|
mkdir -p /data/cache
|
||||||
cp -a /github/workspace/cloud-runner-cache/. ${sharedFolder}
|
cp -a /github/workspace/cloud-runner-cache/. ${sharedFolder}
|
||||||
${CommandHookService.ApplyHooksToCommands(commands, this.buildParameters)}
|
${commands}
|
||||||
cp -a ${sharedFolder}. /github/workspace/cloud-runner-cache/
|
cp -a ${sharedFolder}. /github/workspace/cloud-runner-cache/
|
||||||
`;
|
`;
|
||||||
writeFileSync(`${workspace}/${entrypointFilePath}`, fileContents, {
|
writeFileSync(`${workspace}/${entrypointFilePath}`, fileContents, {
|
||||||
|
@ -132,7 +131,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`);
|
||||||
}
|
}
|
||||||
const exitCode = await Docker.run(
|
await Docker.run(
|
||||||
image,
|
image,
|
||||||
{ workspace, actionFolder, ...this.buildParameters },
|
{ workspace, actionFolder, ...this.buildParameters },
|
||||||
false,
|
false,
|
||||||
|
@ -151,12 +150,6 @@ cp -a ${sharedFolder}. /github/workspace/cloud-runner-cache/
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,29 +2,25 @@ import * as k8s from '@kubernetes/client-node';
|
||||||
import { BuildParameters } from '../../..';
|
import { BuildParameters } from '../../..';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import { ProviderInterface } from '../provider-interface';
|
import { ProviderInterface } from '../provider-interface';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import KubernetesStorage from './kubernetes-storage';
|
import KubernetesStorage from './kubernetes-storage';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import KubernetesTaskRunner from './kubernetes-task-runner';
|
import KubernetesTaskRunner from './kubernetes-task-runner';
|
||||||
import KubernetesSecret from './kubernetes-secret';
|
import KubernetesSecret from './kubernetes-secret';
|
||||||
import KubernetesJobSpecFactory from './kubernetes-job-spec-factory';
|
import KubernetesJobSpecFactory from './kubernetes-job-spec-factory';
|
||||||
import KubernetesServiceAccount from './kubernetes-service-account';
|
import KubernetesServiceAccount from './kubernetes-service-account';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { CoreV1Api } from '@kubernetes/client-node';
|
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 KubernetesPods from './kubernetes-pods';
|
||||||
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 = '';
|
||||||
|
@ -35,7 +31,6 @@ 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) {
|
||||||
|
@ -43,30 +38,11 @@ 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);
|
||||||
|
@ -118,8 +94,16 @@ class Kubernetes implements ProviderInterface {
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
this.buildParameters = buildParameters;
|
this.buildParameters = buildParameters;
|
||||||
this.cleanupCronJobName = `unity-builder-cronjob-${buildParameters.buildGuid}`;
|
const id = buildParameters.retainWorkspace ? CloudRunner.lockedWorkspace : buildParameters.buildGuid;
|
||||||
|
this.pvcName = `unity-builder-pvc-${id}`;
|
||||||
|
this.cleanupCronJobName = `unity-builder-cronjob-${id}`;
|
||||||
this.serviceAccountName = `service-account-${buildParameters.buildGuid}`;
|
this.serviceAccountName = `service-account-${buildParameters.buildGuid}`;
|
||||||
|
await KubernetesStorage.createPersistentVolumeClaim(
|
||||||
|
buildParameters,
|
||||||
|
this.pvcName,
|
||||||
|
this.kubeClient,
|
||||||
|
this.namespace,
|
||||||
|
);
|
||||||
|
|
||||||
await KubernetesServiceAccount.createServiceAccount(this.serviceAccountName, this.namespace, this.kubeClient);
|
await KubernetesServiceAccount.createServiceAccount(this.serviceAccountName, this.namespace, this.kubeClient);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -140,97 +124,74 @@ class Kubernetes implements ProviderInterface {
|
||||||
CloudRunnerLogger.log('Cloud Runner K8s workflow!');
|
CloudRunnerLogger.log('Cloud Runner K8s workflow!');
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
const id =
|
|
||||||
BuildParameters && BuildParameters.shouldUseRetainedWorkspaceMode(this.buildParameters)
|
|
||||||
? CloudRunner.lockedWorkspace
|
|
||||||
: this.buildParameters.buildGuid;
|
|
||||||
this.pvcName = `unity-builder-pvc-${id}`;
|
|
||||||
await KubernetesStorage.createPersistentVolumeClaim(
|
|
||||||
this.buildParameters,
|
|
||||||
this.pvcName,
|
|
||||||
this.kubeClient,
|
|
||||||
this.namespace,
|
|
||||||
);
|
|
||||||
this.buildGuid = buildGuid;
|
this.buildGuid = buildGuid;
|
||||||
this.secretName = `build-credentials-${this.buildGuid}`;
|
this.secretName = `build-credentials-${this.buildGuid}`;
|
||||||
this.jobName = `unity-builder-job-${this.buildGuid}`;
|
this.jobName = `unity-builder-job-${this.buildGuid}`;
|
||||||
this.containerName = `main`;
|
this.containerName = `main`;
|
||||||
await KubernetesSecret.createSecret(secrets, this.secretName, this.namespace, this.kubeClient);
|
await KubernetesSecret.createSecret(secrets, this.secretName, this.namespace, this.kubeClient);
|
||||||
|
await this.createNamespacedJob(commands, image, mountdir, workingdir, environment, secrets);
|
||||||
|
this.setPodNameAndContainerName(await Kubernetes.findPodFromJob(this.kubeClient, this.jobName, this.namespace));
|
||||||
|
CloudRunnerLogger.log('Watching pod until running');
|
||||||
|
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
||||||
let output = '';
|
let output = '';
|
||||||
try {
|
// eslint-disable-next-line no-constant-condition
|
||||||
CloudRunnerLogger.log('Job does not exist');
|
while (true) {
|
||||||
await this.createJob(commands, image, mountdir, workingdir, environment, secrets);
|
try {
|
||||||
CloudRunnerLogger.log('Watching pod until running');
|
CloudRunnerLogger.log('Pod running, streaming logs');
|
||||||
await KubernetesTaskRunner.watchUntilPodRunning(this.kubeClient, this.podName, this.namespace);
|
output = await KubernetesTaskRunner.runTask(
|
||||||
|
this.kubeConfig,
|
||||||
|
this.kubeClient,
|
||||||
|
this.jobName,
|
||||||
|
this.podName,
|
||||||
|
'main',
|
||||||
|
this.namespace,
|
||||||
|
);
|
||||||
|
const running = await KubernetesPods.IsPodRunning(this.podName, this.namespace, this.kubeClient);
|
||||||
|
|
||||||
CloudRunnerLogger.log('Pod is running');
|
if (!running) {
|
||||||
output += await KubernetesTaskRunner.runTask(
|
CloudRunnerLogger.log(`Pod not found, assumed ended!`);
|
||||||
this.kubeConfig,
|
break;
|
||||||
this.kubeClient,
|
} else {
|
||||||
this.jobName,
|
CloudRunnerLogger.log('Pod still running, recovering stream...');
|
||||||
this.podName,
|
}
|
||||||
this.containerName,
|
await this.cleanupTaskResources();
|
||||||
this.namespace,
|
} catch (error: any) {
|
||||||
);
|
let errorParsed;
|
||||||
} catch (error: any) {
|
try {
|
||||||
CloudRunnerLogger.log(`error running k8s workflow ${error}`);
|
errorParsed = JSON.parse(error);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
} catch {
|
||||||
CloudRunnerLogger.log(
|
errorParsed = error;
|
||||||
JSON.stringify(
|
}
|
||||||
(await this.kubeClient.listNamespacedEvent(this.namespace)).body.items
|
|
||||||
.map((x) => {
|
const reason = errorParsed.reason || errorParsed.response?.body?.reason || ``;
|
||||||
return {
|
const errorMessage = errorParsed.message || reason;
|
||||||
message: x.message || ``,
|
|
||||||
name: x.metadata.name || ``,
|
const continueStreaming =
|
||||||
reason: x.reason || ``,
|
errorMessage.includes(`dial timeout, backstop`) ||
|
||||||
};
|
errorMessage.includes(`HttpError: HTTP request failed`) ||
|
||||||
})
|
errorMessage.includes(`an error occurred when try to find container`) ||
|
||||||
.filter((x) => x.name.includes(this.podName)),
|
errorMessage.includes(`not found`) ||
|
||||||
undefined,
|
errorMessage.includes(`Not Found`);
|
||||||
4,
|
if (continueStreaming) {
|
||||||
),
|
CloudRunnerLogger.log('Log Stream Container Not Found');
|
||||||
);
|
await new Promise((resolve) => resolve(5000));
|
||||||
await this.cleanupTaskResources();
|
continue;
|
||||||
throw error;
|
} else {
|
||||||
|
CloudRunnerLogger.log(`error running k8s workflow ${error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.cleanupTaskResources();
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CloudRunnerLogger.log('Running job failed');
|
CloudRunnerLogger.log('Running job failed');
|
||||||
core.error(JSON.stringify(error, undefined, 4));
|
core.error(JSON.stringify(error, undefined, 4));
|
||||||
|
await this.cleanupTaskResources();
|
||||||
// await this.cleanupTaskResources();
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createJob(
|
|
||||||
commands: string,
|
|
||||||
image: string,
|
|
||||||
mountdir: string,
|
|
||||||
workingdir: string,
|
|
||||||
environment: CloudRunnerEnvironmentVariable[],
|
|
||||||
secrets: CloudRunnerSecret[],
|
|
||||||
) {
|
|
||||||
await this.createNamespacedJob(commands, image, mountdir, workingdir, environment, secrets);
|
|
||||||
const find = await Kubernetes.findPodFromJob(this.kubeClient, this.jobName, this.namespace);
|
|
||||||
this.setPodNameAndContainerName(find);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async doesJobExist(name: string) {
|
|
||||||
const jobs = await this.kubeClientBatch.listNamespacedJob(this.namespace);
|
|
||||||
|
|
||||||
return jobs.body.items.some((x) => x.metadata?.name === name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async doesFailedJobExist() {
|
|
||||||
const podStatus = await this.kubeClient.readNamespacedPodStatus(this.podName, this.namespace);
|
|
||||||
|
|
||||||
return podStatus.body.status?.phase === `Failed`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createNamespacedJob(
|
private async createNamespacedJob(
|
||||||
commands: string,
|
commands: string,
|
||||||
image: string,
|
image: string,
|
||||||
|
@ -254,19 +215,14 @@ class Kubernetes implements ProviderInterface {
|
||||||
this.pvcName,
|
this.pvcName,
|
||||||
this.jobName,
|
this.jobName,
|
||||||
k8s,
|
k8s,
|
||||||
this.containerName,
|
|
||||||
this.ip,
|
|
||||||
);
|
);
|
||||||
await new Promise((promise) => setTimeout(promise, 15000));
|
await new Promise((promise) => setTimeout(promise, 15000));
|
||||||
|
await this.kubeClientBatch.createNamespacedJob(this.namespace, jobSpec);
|
||||||
// await KubernetesRole.createRole(this.serviceAccountName, this.namespace, this.rbacAuthorizationV1Api);
|
|
||||||
|
|
||||||
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));
|
||||||
CloudRunnerLogger.log('Job created');
|
CloudRunnerLogger.log('Job created');
|
||||||
|
|
||||||
return result.body.metadata?.name;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CloudRunnerLogger.log(`Error occured creating job: ${error}`);
|
CloudRunnerLogger.log(`Error occured creating job: ${error}`);
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -276,7 +232,7 @@ class Kubernetes implements ProviderInterface {
|
||||||
|
|
||||||
setPodNameAndContainerName(pod: k8s.V1Pod) {
|
setPodNameAndContainerName(pod: k8s.V1Pod) {
|
||||||
this.podName = pod.metadata?.name || '';
|
this.podName = pod.metadata?.name || '';
|
||||||
this.containerName = pod.status?.containerStatuses?.[0].name || this.containerName;
|
this.containerName = pod.status?.containerStatuses?.[0].name || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async cleanupTaskResources() {
|
async cleanupTaskResources() {
|
||||||
|
@ -284,7 +240,6 @@ 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`) {
|
||||||
|
@ -303,13 +258,14 @@ 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 && BuildParameters.shouldUseRetainedWorkspaceMode(buildParameters)) {
|
if (buildParameters.retainWorkspace) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CloudRunnerLogger.log(`deleting PVC`);
|
CloudRunnerLogger.log(`deleting PVC`);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { V1EnvVar, V1EnvVarSource, V1SecretKeySelector } from '@kubernetes/client-node';
|
import { V1EnvVar, V1EnvVarSource, V1SecretKeySelector } from '@kubernetes/client-node';
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import { CommandHookService } from '../../services/hooks/command-hook-service';
|
import { CloudRunnerCustomHooks } from '../../services/cloud-runner-custom-hooks';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import CloudRunner from '../../cloud-runner';
|
||||||
|
|
||||||
class KubernetesJobSpecFactory {
|
class KubernetesJobSpecFactory {
|
||||||
|
@ -15,13 +15,67 @@ class KubernetesJobSpecFactory {
|
||||||
secrets: CloudRunnerSecret[],
|
secrets: CloudRunnerSecret[],
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
buildParameters: BuildParameters,
|
buildParameters: BuildParameters,
|
||||||
secretName: string,
|
secretName,
|
||||||
pvcName: string,
|
pvcName,
|
||||||
jobName: string,
|
jobName,
|
||||||
k8s: any,
|
k8s,
|
||||||
containerName: string,
|
|
||||||
ip: string = '',
|
|
||||||
) {
|
) {
|
||||||
|
environment.push(
|
||||||
|
...[
|
||||||
|
{
|
||||||
|
name: 'GITHUB_SHA',
|
||||||
|
value: buildGuid,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GITHUB_WORKSPACE',
|
||||||
|
value: '/data/repo',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'PROJECT_PATH',
|
||||||
|
value: buildParameters.projectPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BUILD_PATH',
|
||||||
|
value: buildParameters.buildPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BUILD_FILE',
|
||||||
|
value: buildParameters.buildFile,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BUILD_NAME',
|
||||||
|
value: buildParameters.buildName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BUILD_METHOD',
|
||||||
|
value: buildParameters.buildMethod,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CUSTOM_PARAMETERS',
|
||||||
|
value: buildParameters.customParameters,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CHOWN_FILES_TO',
|
||||||
|
value: buildParameters.chownFilesTo,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'BUILD_TARGET',
|
||||||
|
value: buildParameters.targetPlatform,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ANDROID_VERSION_CODE',
|
||||||
|
value: buildParameters.androidVersionCode.toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ANDROID_KEYSTORE_NAME',
|
||||||
|
value: buildParameters.androidKeystoreName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ANDROID_KEYALIAS_NAME',
|
||||||
|
value: buildParameters.androidKeyaliasName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
const job = new k8s.V1Job();
|
const job = new k8s.V1Job();
|
||||||
job.apiVersion = 'batch/v1';
|
job.apiVersion = 'batch/v1';
|
||||||
job.kind = 'Job';
|
job.kind = 'Job';
|
||||||
|
@ -33,7 +87,6 @@ class KubernetesJobSpecFactory {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
job.spec = {
|
job.spec = {
|
||||||
ttlSecondsAfterFinished: 9999,
|
|
||||||
backoffLimit: 0,
|
backoffLimit: 0,
|
||||||
template: {
|
template: {
|
||||||
spec: {
|
spec: {
|
||||||
|
@ -47,20 +100,16 @@ class KubernetesJobSpecFactory {
|
||||||
],
|
],
|
||||||
containers: [
|
containers: [
|
||||||
{
|
{
|
||||||
ttlSecondsAfterFinished: 9999,
|
name: 'main',
|
||||||
name: containerName,
|
|
||||||
image,
|
image,
|
||||||
command: ['/bin/sh'],
|
command: ['/bin/sh'],
|
||||||
args: [
|
args: ['-c', CloudRunnerCustomHooks.ApplyHooksToCommands(command, CloudRunner.buildParameters)],
|
||||||
'-c',
|
|
||||||
`${CommandHookService.ApplyHooksToCommands(`${command}\nsleep 2m`, CloudRunner.buildParameters)}`,
|
|
||||||
],
|
|
||||||
|
|
||||||
workingDir: `${workingDirectory}`,
|
workingDir: `${workingDirectory}`,
|
||||||
resources: {
|
resources: {
|
||||||
requests: {
|
requests: {
|
||||||
memory: `${Number.parseInt(buildParameters.containerMemory) / 1024}G` || '750M',
|
memory: buildParameters.cloudRunnerMemory || '750M',
|
||||||
cpu: Number.parseInt(buildParameters.containerCpu) / 1024 || '1',
|
cpu: buildParameters.cloudRunnerCpu || '1',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
env: [
|
env: [
|
||||||
|
@ -82,20 +131,20 @@ class KubernetesJobSpecFactory {
|
||||||
|
|
||||||
return environmentVariable;
|
return environmentVariable;
|
||||||
}),
|
}),
|
||||||
{ name: 'LOG_SERVICE_IP', value: ip },
|
|
||||||
],
|
],
|
||||||
volumeMounts: [
|
volumeMounts: [
|
||||||
{
|
{
|
||||||
name: 'build-mount',
|
name: 'build-mount',
|
||||||
mountPath: `${mountdir}`,
|
mountPath: `/${mountdir}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
lifecycle: {
|
lifecycle: {
|
||||||
preStop: {
|
preStop: {
|
||||||
exec: {
|
exec: {
|
||||||
command: [
|
command: [
|
||||||
`wait 60s;
|
'bin/bash',
|
||||||
cd /data/builder/action/steps;
|
'-c',
|
||||||
|
`cd /data/builder/action/steps;
|
||||||
chmod +x /return_license.sh;
|
chmod +x /return_license.sh;
|
||||||
/return_license.sh;`,
|
/return_license.sh;`,
|
||||||
],
|
],
|
||||||
|
@ -109,17 +158,7 @@ class KubernetesJobSpecFactory {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (process.env['CLOUD_RUNNER_MINIKUBE']) {
|
job.spec.template.spec.containers[0].resources.requests[`ephemeral-storage`] = '5Gi';
|
||||||
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';
|
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { CoreV1Api } from '@kubernetes/client-node';
|
import { CoreV1Api } from '@kubernetes/client-node';
|
||||||
class KubernetesPods {
|
class KubernetesPods {
|
||||||
public static async IsPodRunning(podName: string, namespace: string, kubeClient: CoreV1Api) {
|
public static async IsPodRunning(podName: string, namespace: string, kubeClient: CoreV1Api) {
|
||||||
|
@ -12,12 +12,6 @@ class KubernetesPods {
|
||||||
|
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
public static async GetPodStatus(podName: string, namespace: string, kubeClient: CoreV1Api) {
|
|
||||||
const pods = (await kubeClient.listNamespacedPod(namespace)).body.items.find((x) => podName === x.metadata?.name);
|
|
||||||
const phase = pods?.status?.phase || 'undefined status';
|
|
||||||
|
|
||||||
return phase;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default KubernetesPods;
|
export default KubernetesPods;
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
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 };
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { CoreV1Api } from '@kubernetes/client-node';
|
import { CoreV1Api } from '@kubernetes/client-node';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import * as k8s from '@kubernetes/client-node';
|
import * as k8s from '@kubernetes/client-node';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import * as base64 from 'base-64';
|
const base64 = require('base-64');
|
||||||
|
|
||||||
class KubernetesSecret {
|
class KubernetesSecret {
|
||||||
static async createSecret(
|
static async createSecret(
|
||||||
|
|
|
@ -9,7 +9,7 @@ class KubernetesServiceAccount {
|
||||||
serviceAccount.metadata = {
|
serviceAccount.metadata = {
|
||||||
name: serviceAccountName,
|
name: serviceAccountName,
|
||||||
};
|
};
|
||||||
serviceAccount.automountServiceAccountToken = true;
|
serviceAccount.automountServiceAccountToken = false;
|
||||||
|
|
||||||
return kubeClient.createNamespacedServiceAccount(namespace, serviceAccount);
|
return kubeClient.createNamespacedServiceAccount(namespace, serviceAccount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { waitUntil } from 'async-wait-until';
|
import waitUntil from 'async-wait-until';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as k8s from '@kubernetes/client-node';
|
import * as k8s from '@kubernetes/client-node';
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { IncomingMessage } from 'node:http';
|
import { IncomingMessage } from 'http';
|
||||||
import GitHub from '../../../github';
|
import GitHub from '../../../github';
|
||||||
|
|
||||||
class KubernetesStorage {
|
class KubernetesStorage {
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import { CoreV1Api, KubeConfig } from '@kubernetes/client-node';
|
import { CoreV1Api, KubeConfig, Log } from '@kubernetes/client-node';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import { Writable } from 'stream';
|
||||||
import { waitUntil } from 'async-wait-until';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { CloudRunnerSystem } from '../../services/core/cloud-runner-system';
|
import * as core from '@actions/core';
|
||||||
import CloudRunner from '../../cloud-runner';
|
import { CloudRunnerStatics } from '../../cloud-runner-statics';
|
||||||
import KubernetesPods from './kubernetes-pods';
|
import waitUntil from 'async-wait-until';
|
||||||
import { FollowLogStreamService } from '../../services/core/follow-log-stream-service';
|
import { FollowLogStreamService } from '../../services/follow-log-stream-service';
|
||||||
|
|
||||||
class KubernetesTaskRunner {
|
class KubernetesTaskRunner {
|
||||||
static readonly maxRetry: number = 3;
|
|
||||||
static lastReceivedMessage: string = ``;
|
|
||||||
|
|
||||||
static async runTask(
|
static async runTask(
|
||||||
kubeConfig: KubeConfig,
|
kubeConfig: KubeConfig,
|
||||||
kubeClient: CoreV1Api,
|
kubeClient: CoreV1Api,
|
||||||
|
@ -18,88 +15,85 @@ class KubernetesTaskRunner {
|
||||||
containerName: string,
|
containerName: string,
|
||||||
namespace: string,
|
namespace: string,
|
||||||
) {
|
) {
|
||||||
|
CloudRunnerLogger.log(`Streaming logs from pod: ${podName} container: ${containerName} namespace: ${namespace}`);
|
||||||
|
const stream = new Writable();
|
||||||
let output = '';
|
let output = '';
|
||||||
|
let didStreamAnyLogs: boolean = false;
|
||||||
let shouldReadLogs = true;
|
let shouldReadLogs = true;
|
||||||
let shouldCleanup = true;
|
let shouldCleanup = true;
|
||||||
let retriesAfterFinish = 0;
|
stream._write = (chunk, encoding, next) => {
|
||||||
// eslint-disable-next-line no-constant-condition
|
didStreamAnyLogs = true;
|
||||||
while (true) {
|
let message = chunk.toString().trimRight(`\n`);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
message = `[${CloudRunnerStatics.logPrefix}] ${message}`;
|
||||||
CloudRunnerLogger.log(
|
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
|
||||||
`Streaming logs from pod: ${podName} container: ${containerName} namespace: ${namespace} ${CloudRunner.buildParameters.kubeVolumeSize}/${CloudRunner.buildParameters.containerCpu}/${CloudRunner.buildParameters.containerMemory}`,
|
message,
|
||||||
|
shouldReadLogs,
|
||||||
|
shouldCleanup,
|
||||||
|
output,
|
||||||
|
));
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
const logOptions = {
|
||||||
|
follow: true,
|
||||||
|
pretty: false,
|
||||||
|
previous: false,
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const resultError = await new Promise((resolve) =>
|
||||||
|
new Log(kubeConfig).log(namespace, podName, containerName, stream, resolve, logOptions),
|
||||||
);
|
);
|
||||||
let extraFlags = ``;
|
stream.destroy();
|
||||||
extraFlags += (await KubernetesPods.IsPodRunning(podName, namespace, kubeClient))
|
if (resultError) {
|
||||||
? ` -f -c ${containerName}`
|
throw resultError;
|
||||||
: ` --previous`;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
await CloudRunnerSystem.Run(`kubectl logs ${podName}${extraFlags}`, false, true, callback);
|
|
||||||
} catch (error: any) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
||||||
const continueStreaming = await KubernetesPods.IsPodRunning(podName, namespace, kubeClient);
|
|
||||||
CloudRunnerLogger.log(`K8s logging error ${error} ${continueStreaming}`);
|
|
||||||
if (continueStreaming) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (retriesAfterFinish < KubernetesTaskRunner.maxRetry) {
|
|
||||||
retriesAfterFinish++;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
if (FollowLogStreamService.DidReceiveEndOfTransmission) {
|
if (!didStreamAnyLogs) {
|
||||||
CloudRunnerLogger.log('end of log stream');
|
core.error('Failed to stream any logs, listing namespace events, check for an error with the container');
|
||||||
break;
|
core.error(
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
events: (await kubeClient.listNamespacedEvent(namespace)).body.items
|
||||||
|
.filter((x) => {
|
||||||
|
return x.involvedObject.name === podName || x.involvedObject.name === jobName;
|
||||||
|
})
|
||||||
|
.map((x) => {
|
||||||
|
return {
|
||||||
|
type: x.involvedObject.kind,
|
||||||
|
name: x.involvedObject.name,
|
||||||
|
message: x.message,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
throw new Error(`No logs streamed from k8s`);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (stream) {
|
||||||
|
stream.destroy();
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
CloudRunnerLogger.log('end of log stream');
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async watchUntilPodRunning(kubeClient: CoreV1Api, podName: string, namespace: string) {
|
static async watchUntilPodRunning(kubeClient: CoreV1Api, podName: string, namespace: string) {
|
||||||
let waitComplete: boolean = false;
|
let success: boolean = false;
|
||||||
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;
|
||||||
waitComplete = phase !== 'Pending';
|
success = phase === 'Running';
|
||||||
message = `Phase:${status.body.status?.phase} \n Reason:${
|
CloudRunnerLogger.log(
|
||||||
status.body.status?.conditions?.[0].reason || ''
|
`${status.body.status?.phase} ${status.body.status?.conditions?.[0].reason || ''} ${
|
||||||
} \n Message:${status.body.status?.conditions?.[0].message || ''}`;
|
status.body.status?.conditions?.[0].message || ''
|
||||||
|
}`,
|
||||||
// CloudRunnerLogger.log(
|
);
|
||||||
// JSON.stringify(
|
if (success || phase !== 'Pending') return true;
|
||||||
// (await kubeClient.listNamespacedEvent(namespace)).body.items
|
|
||||||
// .map((x) => {
|
|
||||||
// return {
|
|
||||||
// message: x.message || ``,
|
|
||||||
// name: x.metadata.name || ``,
|
|
||||||
// reason: x.reason || ``,
|
|
||||||
// };
|
|
||||||
// })
|
|
||||||
// .filter((x) => x.name.includes(podName)),
|
|
||||||
// undefined,
|
|
||||||
// 4,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
if (waitComplete || phase !== 'Pending') return true;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
@ -108,11 +102,8 @@ class KubernetesTaskRunner {
|
||||||
intervalBetweenAttempts: 15000,
|
intervalBetweenAttempts: 15000,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!waitComplete) {
|
|
||||||
CloudRunnerLogger.log(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return waitComplete;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import { CloudRunnerSystem } from '../../services/core/cloud-runner-system';
|
import { CloudRunnerSystem } from '../../services/cloud-runner-system';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { ProviderInterface } from '../provider-interface';
|
import { ProviderInterface } from '../provider-interface';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import { ProviderResource } from '../provider-resource';
|
import { ProviderResource } from '../provider-resource';
|
||||||
import { ProviderWorkflow } from '../provider-workflow';
|
import { ProviderWorkflow } from '../provider-workflow';
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ 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
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import BuildParameters from '../../build-parameters';
|
import BuildParameters from '../../build-parameters';
|
||||||
import CloudRunnerEnvironmentVariable from '../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerSecret from '../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../services/cloud-runner-secret';
|
||||||
import { ProviderResource } from './provider-resource';
|
import { ProviderResource } from './provider-resource';
|
||||||
import { ProviderWorkflow } from './provider-workflow';
|
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
|
||||||
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 }[],
|
||||||
): any;
|
);
|
||||||
setupWorkflow(
|
setupWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
|
@ -22,7 +24,7 @@ export interface ProviderInterface {
|
||||||
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 }[],
|
||||||
): any;
|
);
|
||||||
runTaskInWorkflow(
|
runTaskInWorkflow(
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
buildGuid: string,
|
buildGuid: string,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import BuildParameters from '../../../build-parameters';
|
import BuildParameters from '../../../build-parameters';
|
||||||
import CloudRunnerEnvironmentVariable from '../../options/cloud-runner-environment-variable';
|
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable';
|
||||||
import CloudRunnerLogger from '../../services/core/cloud-runner-logger';
|
import CloudRunnerLogger from '../../services/cloud-runner-logger';
|
||||||
import { ProviderInterface } from '../provider-interface';
|
import { ProviderInterface } from '../provider-interface';
|
||||||
import CloudRunnerSecret from '../../options/cloud-runner-secret';
|
import CloudRunnerSecret from '../../services/cloud-runner-secret';
|
||||||
import { ProviderResource } from '../provider-resource';
|
import { ProviderResource } from '../provider-resource';
|
||||||
import { ProviderWorkflow } from '../provider-workflow';
|
import { ProviderWorkflow } from '../provider-workflow';
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ 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
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue