Merge remote-tracking branch 'game-ci/main' into cloud-runner-develop

pull/496/head
Frostebite 2023-03-07 16:14:53 +00:00
commit e075f22e5c
90 changed files with 2646 additions and 1706 deletions

View File

@ -6,6 +6,7 @@
<!-- please check all items and add your own --> <!-- please check all items and add your own -->
- [x] Read the contribution [guide](../CONTRIBUTING.md) and accept the [code](../CODE_OF_CONDUCT.md) of conduct - [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
- [ ] Readme (updated or not needed) - [ ] Readme (updated or not needed)
- [ ] Tests (added, updated or not needed) - [ ] Tests (added, updated or not needed)

View File

@ -0,0 +1,84 @@
name: Builds - MacOS
on:
workflow_dispatch:
push:
branches:
- main
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: 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

View File

@ -1,11 +1,18 @@
name: Builds name: Builds - Ubuntu
on: on:
push: { branches: [main] } workflow_dispatch:
push:
branches:
- main
pull_request: pull_request:
paths-ignore: paths-ignore:
- '.github/**' - '.github/**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env: env:
UNITY_LICENSE: UNITY_LICENSE:
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License
@ -34,23 +41,37 @@ env:
jobs: jobs:
buildForAllPlatformsUbuntu: buildForAllPlatformsUbuntu:
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }} name: ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
exclude:
- targetPlatform: Android
unityVersion: 2022.2.7f1
cloudRunnerCluster: cloudRunnerCluster:
# - local-docker # - local-docker
- local - local
projectPath: projectPath:
- test-project - test-project
unityVersion: unityVersion:
- 2019.2.11f1 - 2018.3.14f1
- 2018.4.36f1
- 2019.1.14f1
- 2019.2.21f1
- 2019.3.15f1 - 2019.3.15f1
- 2019.4.40f1
- 2020.2.7f1
- 2020.3.45f1
- 2021.1.28f1
- 2021.2.19f1
- 2021.3.19f1
- 2022.1.24f1
- 2022.2.7f1
targetPlatform: targetPlatform:
- StandaloneOSX # Build a macOS standalone (Intel 64-bit). - 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.
- StandaloneLinux64 # Build a Linux 64-bit standalone. - StandaloneLinux64 # Build a Linux 64-bit standalone with mono backend.
- iOS # Build an iOS player. - iOS # Build an iOS player.
- Android # Build an Android .apk. - Android # Build an Android .apk.
- WebGL # WebGL. - WebGL # WebGL.
@ -64,14 +85,14 @@ jobs:
########################### ###########################
# Checkout # # Checkout #
########################### ###########################
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
lfs: true lfs: true
########################### ###########################
# Cache # # Cache #
########################### ###########################
- uses: actions/cache@v2 - 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 }}-ubuntu-${{ matrix.targetPlatform }}
@ -93,7 +114,7 @@ jobs:
########################### ###########################
# Upload # # Upload #
########################### ###########################
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v3
with: with:
name: Build Ubuntu (${{ matrix.unityVersion }}) name: Build Ubuntu (${{ matrix.unityVersion }})
path: build path: build

View File

@ -0,0 +1,135 @@
name: Builds - Windows
on:
workflow_dispatch:
push:
branches:
- main
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-2019
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
- 2019.3.15f1 # Minimum version for IL2CPP
- 2019.4.40f1
- 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:
- StandaloneWindows64 # Build a Windows 64-bit standalone.
- StandaloneWindows # Build a Windows 32-bit standalone.
- WSAPlayer # Build a UWP App
- tvOS # Build an Apple TV XCode project
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v3
with:
lfs: true
###########################
# Cache #
###########################
- uses: actions/cache@v3
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 }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
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 }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
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 }}
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
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@v3
with:
name: Build Windows (${{ matrix.unityVersion }})
path: build
retention-days: 14

View File

@ -15,13 +15,13 @@ jobs:
cleanupCloudRunner: cleanupCloudRunner:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - 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@v2 - uses: actions/setup-node@v3
with: with:
node-version: 12.x node-version: 16.x
- run: yarn - run: yarn
- run: yarn run cli --help - run: yarn run cli --help
env: env:

View File

@ -55,7 +55,7 @@ jobs:
- k8s - k8s
steps: steps:
- name: Checkout (default) - name: Checkout (default)
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
lfs: false lfs: false
- name: Configure AWS Credentials - name: Configure AWS Credentials
@ -164,7 +164,7 @@ jobs:
- Android # Build an Android .apk. - Android # Build an Android .apk.
steps: steps:
- name: Checkout (default) - name: Checkout (default)
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
lfs: false lfs: false
- run: yarn - run: yarn
@ -180,7 +180,7 @@ jobs:
cloudRunnerCluster: ${{ matrix.cloudRunnerCluster }} cloudRunnerCluster: ${{ matrix.cloudRunnerCluster }}
- run: | - run: |
cp ./cloud-runner-cache/cache/${{ steps.unity-build.outputs.CACHE_KEY }}/build/${{ steps.unity-build.outputs.BUILD_ARTIFACT }} ${{ steps.unity-build.outputs.BUILD_ARTIFACT }} cp ./cloud-runner-cache/cache/${{ steps.unity-build.outputs.CACHE_KEY }}/build/${{ steps.unity-build.outputs.BUILD_ARTIFACT }} ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v3
with: with:
name: ${{ matrix.cloudRunnerCluster }} Build (${{ matrix.targetPlatform }}) name: ${{ matrix.cloudRunnerCluster }} Build (${{ matrix.targetPlatform }})
path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }} path: ${{ steps.unity-build.outputs.BUILD_ARTIFACT }}

View File

@ -7,6 +7,10 @@ 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

View File

@ -1,74 +0,0 @@
name: Mac Builds
on:
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:
- 2020.3.24f1
targetPlatform:
- StandaloneOSX # Build a MacOS executable
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v2
with:
lfs: true
###########################
# Cache #
###########################
- uses: actions/cache@v2
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@v2
with:
name: Build MacOS (${{ matrix.unityVersion }})
path: build
retention-days: 14

View File

@ -1,77 +0,0 @@
name: Windows Builds
on:
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: windows-2019
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
- 2020.3.24f1
targetPlatform:
- StandaloneWindows64 # Build a Windows 64-bit standalone.
- StandaloneWindows # Build a Windows 32-bit standalone.
- WSAPlayer # Build a UWP App
- tvOS # Build an Apple TV XCode project
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v2
with:
lfs: true
###########################
# Cache #
###########################
- uses: actions/cache@v2
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 #
###########################
- 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
allowDirtyBuild: true
# We use dirty build because we are replacing the default project settings file above
###########################
# Upload #
###########################
- uses: actions/upload-artifact@v2
with:
name: Build Windows (${{ matrix.unityVersion }})
path: build
retention-days: 14

1
.npmrc 100644
View File

@ -0,0 +1 @@
engine-strict=true

25
.vscode/launch.json vendored 100644
View File

@ -0,0 +1,25 @@
{
"configurations": [
{
"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>/**/*"]
}
]
}

View File

@ -10,8 +10,9 @@ Part of the <a href="https://game.ci">GameCI</a> open source project.
<br /> <br />
<br /> <br />
[![Actions status](https://github.com/game-ci/unity-builder/workflows/Builds/badge.svg?event=push&branch=main)](https://github.com/game-ci/unity-builder/actions?query=branch%3Amain+event%3Apush+workflow%3A%22Builds) [![Builds - Ubuntu](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-ubuntu.yml/badge.svg)](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-ubuntu.yml)
[![lgtm - code quality](https://img.shields.io/lgtm/grade/javascript/g/webbertakken/unity-builder.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/webbertakken/unity-builder/context:javascript) [![Builds - Windows](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-windows.yml/badge.svg)](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-windows.yml)
[![Builds - MacOS](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-mac.yml/badge.svg)](https://github.com/game-ci/unity-builder/actions/workflows/build-tests-mac.yml)
[![codecov - test coverage](https://codecov.io/gh/game-ci/unity-builder/branch/master/graph/badge.svg)](https://codecov.io/gh/game-ci/unity-builder) [![codecov - test coverage](https://codecov.io/gh/game-ci/unity-builder/branch/master/graph/badge.svg)](https://codecov.io/gh/game-ci/unity-builder)
<br /> <br />
<br /> <br />

View File

@ -22,7 +22,7 @@ inputs:
buildName: buildName:
required: false required: false
default: '' default: ''
description: 'Name of the build.' description: 'Name of the build. Should not include a file extension.'
buildsPath: buildsPath:
required: false required: false
default: '' default: ''
@ -50,7 +50,13 @@ inputs:
androidAppBundle: androidAppBundle:
required: false required: false
default: 'false' default: 'false'
description: 'Whether to build .aab instead of .apk' description: '[Deprecated] Use androidExportType instead. Whether to build .aab instead of .apk'
androidExportType:
required: false
default: ''
description:
'The android export type. Should be androidPackage for apk, androidAppBundle for aab, or androidStudioProject for
an android studio project.'
androidKeystoreName: androidKeystoreName:
required: false required: false
default: '' default: ''
@ -75,6 +81,10 @@ inputs:
required: false required: false
default: '' default: ''
description: 'The android target API level.' description: 'The android target API level.'
androidSymbolType:
required: false
default: 'none'
description: 'The android symbol type to export. Should be "none", "public" or "debugging".'
sshAgent: sshAgent:
required: false required: false
default: '' default: ''
@ -187,6 +197,17 @@ inputs:
description: description:
'[CloudRunner] Whether or not to watch the build to the end. Can be used for especially long running jobs e.g '[CloudRunner] Whether or not to watch the build to the end. Can be used for especially long running jobs e.g
imports or self-hosted ephemeral runners.' imports or self-hosted ephemeral runners.'
cacheUnityInstallationOnMac:
default: 'false'
required: false
description: 'Whether to cache the Unity hub and editor installation on MacOS'
unityHubVersionOnMac:
default: ''
required: false
description:
'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.'
outputs: outputs:
volume: volume:
description: 'The Persistent Volume (PV) where the build artifacts have been stored by Kubernetes' description: 'The Persistent Volume (PV) where the build artifacts have been stored by Kubernetes'

View File

@ -1,14 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor; using UnityEditor;
using System.Reflection;
namespace UnityBuilderAction.Input namespace UnityBuilderAction.Input
{ {
public class AndroidSettings public static class AndroidSettings
{ {
public static void Apply(Dictionary<string, string> options) public static void Apply(Dictionary<string, string> options)
{ {
EditorUserBuildSettings.buildAppBundle = options["customBuildPath"].EndsWith(".aab");
#if UNITY_2019_1_OR_NEWER #if UNITY_2019_1_OR_NEWER
if (options.TryGetValue("androidKeystoreName", out string keystoreName) && !string.IsNullOrEmpty(keystoreName)) if (options.TryGetValue("androidKeystoreName", out string keystoreName) && !string.IsNullOrEmpty(keystoreName))
{ {
@ -16,13 +16,21 @@ namespace UnityBuilderAction.Input
PlayerSettings.Android.keystoreName = keystoreName; PlayerSettings.Android.keystoreName = keystoreName;
} }
#endif #endif
if (options.TryGetValue("androidKeystorePass", out string keystorePass) && !string.IsNullOrEmpty(keystorePass)) // Can't use out variable declaration as Unity 2018 doesn't support it
string keystorePass;
if (options.TryGetValue("androidKeystorePass", out keystorePass) && !string.IsNullOrEmpty(keystorePass))
PlayerSettings.Android.keystorePass = keystorePass; PlayerSettings.Android.keystorePass = keystorePass;
if (options.TryGetValue("androidKeyaliasName", out string keyaliasName) && !string.IsNullOrEmpty(keyaliasName))
string keyaliasName;
if (options.TryGetValue("androidKeyaliasName", out keyaliasName) && !string.IsNullOrEmpty(keyaliasName))
PlayerSettings.Android.keyaliasName = keyaliasName; PlayerSettings.Android.keyaliasName = keyaliasName;
if (options.TryGetValue("androidKeyaliasPass", out string keyaliasPass) && !string.IsNullOrEmpty(keyaliasPass))
string keyaliasPass;
if (options.TryGetValue("androidKeyaliasPass", out keyaliasPass) && !string.IsNullOrEmpty(keyaliasPass))
PlayerSettings.Android.keyaliasPass = keyaliasPass; PlayerSettings.Android.keyaliasPass = keyaliasPass;
if (options.TryGetValue("androidTargetSdkVersion", out string androidTargetSdkVersion) && !string.IsNullOrEmpty(androidTargetSdkVersion))
string androidTargetSdkVersion;
if (options.TryGetValue("androidTargetSdkVersion", out androidTargetSdkVersion) && !string.IsNullOrEmpty(androidTargetSdkVersion))
{ {
var targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto; var targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto;
try try
@ -36,6 +44,62 @@ namespace UnityBuilderAction.Input
} }
PlayerSettings.Android.targetSdkVersion = targetSdkVersion; PlayerSettings.Android.targetSdkVersion = targetSdkVersion;
} }
string androidExportType;
if (options.TryGetValue("androidExportType", out androidExportType) && !string.IsNullOrEmpty(androidExportType))
{
// Only exists in 2018.3 and above
PropertyInfo buildAppBundle = typeof(EditorUserBuildSettings)
.GetProperty("buildAppBundle", BindingFlags.Public | BindingFlags.Static);
switch (androidExportType)
{
case "androidStudioProject":
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
if (buildAppBundle != null)
buildAppBundle.SetValue(null, false);
break;
case "androidAppBundle":
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
if (buildAppBundle != null)
buildAppBundle.SetValue(null, true);
break;
case "androidPackage":
EditorUserBuildSettings.exportAsGoogleAndroidProject = false;
if (buildAppBundle != null)
buildAppBundle.SetValue(null, false);
break;
}
}
string symbolType;
if (options.TryGetValue("androidSymbolType", out symbolType) && !string.IsNullOrEmpty(symbolType))
{
#if UNITY_2021_1_OR_NEWER
switch (symbolType)
{
case "public":
EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Public;
break;
case "debugging":
EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Debugging;
break;
case "none":
EditorUserBuildSettings.androidCreateSymbols = AndroidCreateSymbols.Disabled;
break;
}
#elif UNITY_2019_2_OR_NEWER
switch (symbolType)
{
case "public":
case "debugging":
EditorUserBuildSettings.androidCreateSymbolsZip = true;
break;
case "none":
EditorUserBuildSettings.androidCreateSymbolsZip = false;
break;
}
#endif
}
} }
} }
} }

View File

@ -12,14 +12,17 @@ namespace UnityBuilderAction.Input
public static Dictionary<string, string> GetValidatedOptions() public static Dictionary<string, string> GetValidatedOptions()
{ {
ParseCommandLineArguments(out var validatedOptions); Dictionary<string, string> validatedOptions;
ParseCommandLineArguments(out validatedOptions);
if (!validatedOptions.TryGetValue("projectPath", out var projectPath)) { string projectPath;
if (!validatedOptions.TryGetValue("projectPath", out projectPath)) {
Console.WriteLine("Missing argument -projectPath"); Console.WriteLine("Missing argument -projectPath");
EditorApplication.Exit(110); EditorApplication.Exit(110);
} }
if (!validatedOptions.TryGetValue("buildTarget", out var buildTarget)) { string buildTarget;
if (!validatedOptions.TryGetValue("buildTarget", out buildTarget)) {
Console.WriteLine("Missing argument -buildTarget"); Console.WriteLine("Missing argument -buildTarget");
EditorApplication.Exit(120); EditorApplication.Exit(120);
} }
@ -28,13 +31,15 @@ namespace UnityBuilderAction.Input
EditorApplication.Exit(121); EditorApplication.Exit(121);
} }
if (!validatedOptions.TryGetValue("customBuildPath", out var customBuildPath)) { string customBuildPath;
if (!validatedOptions.TryGetValue("customBuildPath", out customBuildPath)) {
Console.WriteLine("Missing argument -customBuildPath"); Console.WriteLine("Missing argument -customBuildPath");
EditorApplication.Exit(130); EditorApplication.Exit(130);
} }
const string defaultCustomBuildName = "TestBuild"; const string defaultCustomBuildName = "TestBuild";
if (!validatedOptions.TryGetValue("customBuildName", out var customBuildName)) { string 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 == "") {

View File

@ -106,7 +106,8 @@ namespace UnityBuilderAction.Versioning
using (var process = new System.Diagnostics.Process()) { using (var process = new System.Diagnostics.Process()) {
string workingDirectory = UnityEngine.Application.dataPath; string workingDirectory = UnityEngine.Application.dataPath;
int exitCode = process.Run(application, arguments, workingDirectory, out string output, out string errors); string output, errors;
int exitCode = process.Run(application, arguments, workingDirectory, out output, out errors);
if (exitCode != 0) { throw new GitException(exitCode, errors); } if (exitCode != 0) { throw new GitException(exitCode, errors); }
return output; return output;

1314
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ echo "Requesting activation"
# Activate license # Activate license
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \ /Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logFile /dev/stdout \ -logFile - \
-batchmode \ -batchmode \
-nographics \ -nographics \
-quit \ -quit \

View File

@ -76,8 +76,10 @@ fi
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS" echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)" ANDROID_INSTALL_LOCATION="/Applications/Unity/Hub/Editor/$UNITY_VERSION/PlaybackEngines/AndroidPlayer"
"$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)/tools/bin/sdkmanager" "$ANDROID_SDK_MANAGER_PARAMETERS" export JAVA_HOME="$ANDROID_INSTALL_LOCATION/OpenJDK"
export ANDROID_HOME="$ANDROID_INSTALL_LOCATION/SDK"
yes | "$ANDROID_HOME/tools/bin/sdkmanager" "$ANDROID_SDK_MANAGER_PARAMETERS"
echo "Updated Android SDK." echo "Updated Android SDK."
else else
echo "Not updating Android SDK." echo "Not updating Android SDK."
@ -126,6 +128,7 @@ echo ""
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html # Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \ /Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logFile - \
-quit \ -quit \
-batchmode \ -batchmode \
-nographics \ -nographics \
@ -144,8 +147,9 @@ echo ""
-androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \ -androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \
-androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \ -androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \
-androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \ -androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \
$CUSTOM_PARAMETERS \ -androidExportType "$ANDROID_EXPORT_TYPE" \
> "$UNITY_PROJECT_PATH/out.log" 2>&1 -androidSymbolType "$ANDROID_SYMBOL_TYPE" \
$CUSTOM_PARAMETERS
# Catch exit code # Catch exit code
BUILD_EXIT_CODE=$? BUILD_EXIT_CODE=$?

View File

@ -5,7 +5,7 @@ echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
pushd "$ACTIVATE_LICENSE_PATH" pushd "$ACTIVATE_LICENSE_PATH"
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \ /Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logFile /dev/stdout \ -logFile - \
-batchmode \ -batchmode \
-nographics \ -nographics \
-quit \ -quit \

View File

@ -133,6 +133,8 @@ unity-editor \
-androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \ -androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \
-androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \ -androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \
-androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \ -androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \
-androidExportType "$ANDROID_EXPORT_TYPE" \
-androidSymbolType "$ANDROID_SYMBOL_TYPE" \
$CUSTOM_PARAMETERS $CUSTOM_PARAMETERS
# Catch exit code # Catch exit code

View File

@ -126,11 +126,13 @@ $_, $customParametersArray = Invoke-Expression('Write-Output -- "" ' + $Env:CUST
-androidKeyaliasName $Env:ANDROID_KEYALIAS_NAME ` -androidKeyaliasName $Env:ANDROID_KEYALIAS_NAME `
-androidKeyaliasPass $Env:ANDROID_KEYALIAS_PASS ` -androidKeyaliasPass $Env:ANDROID_KEYALIAS_PASS `
-androidTargetSdkVersion $Env:ANDROID_TARGET_SDK_VERSION ` -androidTargetSdkVersion $Env:ANDROID_TARGET_SDK_VERSION `
-androidExportType $Env:ANDROID_EXPORT_TYPE `
-androidSymbolType $Env:ANDROID_SYMBOL_TYPE `
$customParametersArray ` $customParametersArray `
-logfile | Out-Host -logfile | Out-Host
# Catch exit code # Catch exit code
$Env:BUILD_EXIT_CODE=$? $Env:BUILD_EXIT_CODE=$LastExitCode
# Display results # Display results
if ($Env:BUILD_EXIT_CODE -eq 0) if ($Env:BUILD_EXIT_CODE -eq 0)

2
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,60 +0,0 @@
"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);
});
}
});

View File

@ -18,7 +18,6 @@ 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,

View File

@ -24,7 +24,11 @@
"test-i-aws": "cross-env cloudRunnerTests=true cloudRunnerCluster=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 cloudRunnerCluster=k8s yarn test -i -t \"cloud runner\"" "test-i-k8s": "cross-env cloudRunnerTests=true cloudRunnerCluster=k8s yarn test -i -t \"cloud runner\""
}, },
"engines": {
"node": ">=16.x"
},
"dependencies": { "dependencies": {
"@actions/cache": "^3.1.3",
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@actions/exec": "^1.1.0", "@actions/exec": "^1.1.0",
"@actions/github": "^5.0.0", "@actions/github": "^5.0.0",
@ -39,19 +43,21 @@
"nanoid": "^3.3.1", "nanoid": "^3.3.1",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"semver": "^7.3.5", "semver": "^7.3.5",
"unity-changeset": "^1.6.0", "unity-changeset": "^2.0.0",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"yaml": "^1.10.2" "yaml": "^1.10.2"
}, },
"devDependencies": { "devDependencies": {
"@arkweid/lefthook": "^0.7.7", "@evilmartians/lefthook": "^1.2.9",
"@types/base-64": "^1.0.0",
"@types/jest": "^27.4.1", "@types/jest": "^27.4.1",
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
"@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.33.3", "@vercel/ncc": "^0.36.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "7.17.0", "eslint": "^7.23.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",
@ -59,11 +65,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": "^2.3.0", "jest-fail-on-console": "^3.0.2",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"prettier": "^2.5.1", "prettier": "^2.5.1",
"ts-jest": "^27.1.3", "ts-jest": "^27.1.3",
"ts-node": "10.4.0", "ts-node": "10.4.0",
"typescript": "4.1.3" "typescript": "4.1.3",
"yarn-audit-fix": "^9.3.8"
} }
} }

View File

@ -3,6 +3,7 @@ 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()) {
@ -18,16 +19,16 @@ async function runMain() {
const buildParameters = await BuildParameters.create(); const buildParameters = await BuildParameters.create();
const baseImage = new ImageTag(buildParameters); const baseImage = new ImageTag(buildParameters);
if (buildParameters.cloudRunnerCluster !== 'local') { if (buildParameters.cloudRunnerCluster === 'local') {
await CloudRunner.run(buildParameters, baseImage.toString());
} else {
core.info('Building locally'); core.info('Building locally');
await PlatformSetup.setup(buildParameters, actionFolder); await PlatformSetup.setup(buildParameters, actionFolder);
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
MacBuilder.run(actionFolder, workspace, buildParameters); MacBuilder.run(actionFolder);
} else { } else {
await Docker.run(baseImage, { workspace, actionFolder, ...buildParameters }); await Docker.run(baseImage.toString(), { workspace, actionFolder, ...buildParameters });
} }
} else {
await CloudRunner.run(buildParameters, baseImage.toString());
} }
// Set output // Set output

View File

@ -1,4 +1,4 @@
import { stat } from 'fs/promises'; import { stat } from 'node:fs/promises';
describe('Integrity tests', () => { describe('Integrity tests', () => {
describe('package-lock.json', () => { describe('package-lock.json', () => {

View File

@ -1,5 +1,5 @@
import path from 'path'; import path from 'node:path';
import fs from 'fs'; import fs from 'node:fs';
import Action from './action'; import Action from './action';
describe('Action', () => { describe('Action', () => {

View File

@ -1,23 +1,27 @@
import path from 'path'; import path from 'node:path';
class Action { class Action {
static get supportedPlatforms() { static get supportedPlatforms(): string[] {
return ['linux', 'win32', 'darwin']; return ['linux', 'win32', 'darwin'];
} }
static get isRunningLocally() { static get isRunningLocally(): boolean {
return process.env.RUNNER_WORKSPACE === undefined; return process.env.RUNNER_WORKSPACE === undefined;
} }
static get isRunningFromSource() { static get isRunningFromSource(): boolean {
return path.basename(__dirname) === 'model'; return path.basename(__dirname) === 'model';
} }
static get canonicalName() { static get canonicalName(): string {
if (Action.isRunningFromSource) {
return path.basename(path.dirname(path.join(path.dirname(__filename), '/..')));
}
return 'unity-builder'; return 'unity-builder';
} }
static get rootFolder() { static get rootFolder(): string {
if (Action.isRunningFromSource) { if (Action.isRunningFromSource) {
return path.dirname(path.dirname(path.dirname(__filename))); return path.dirname(path.dirname(path.dirname(__filename)));
} }
@ -25,12 +29,12 @@ class Action {
return path.dirname(path.dirname(__filename)); return path.dirname(path.dirname(__filename));
} }
static get actionFolder() { static get actionFolder(): string {
return `${Action.rootFolder}/dist`; return `${Action.rootFolder}/dist`;
} }
static get workspace() { static get workspace(): string {
return process.env.GITHUB_WORKSPACE; return process.env.GITHUB_WORKSPACE!;
} }
static checkCompatibility() { static checkCompatibility() {

View File

@ -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');
}); });
}); });

View File

@ -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, inputVersionCode) { static determineVersionCode(version: string, inputVersionCode: string): string {
if (!inputVersionCode) { if (inputVersionCode === '') {
return AndroidVersioning.versionToVersionCode(version); return AndroidVersioning.versionToVersionCode(version);
} }
return inputVersionCode; return inputVersionCode;
} }
static versionToVersionCode(version) { static versionToVersionCode(version: string): string {
if (version === 'none') { if (version === 'none') {
core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`); core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
return 0; return '0';
} }
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; return versionCode.toString();
} }
static determineSdkManagerParameters(targetSdkVersion) { static determineSdkManagerParameters(targetSdkVersion: string) {
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}`;

View File

@ -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();
await expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1); expect(UnityVersioning.determineUnityVersion).toHaveBeenCalledTimes(1);
}); });
it('returns the android version code with provided input', async () => { it('returns the android version code with provided input', async () => {
@ -47,13 +47,15 @@ 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(expect.objectContaining({ androidVersionCode: 1003037 })); await expect(BuildParameters.create()).resolves.toEqual(
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();
await expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1); expect(AndroidVersioning.determineSdkManagerParameters).toHaveBeenCalledTimes(1);
}); });
it('returns the targetPlatform', async () => { it('returns the targetPlatform', async () => {
@ -95,34 +97,41 @@ describe('BuildParameters', () => {
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue })); await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
}); });
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])( test.each`
'appends exe for %s', targetPlatform | expectedExtension | androidExportType
async (targetPlatform) => { ${Platform.types.Android} | ${'.apk'} | ${'androidPackage'}
${Platform.types.Android} | ${'.aab'} | ${'androidAppBundle'}
${Platform.types.Android} | ${''} | ${'androidStudioProject'}
${Platform.types.StandaloneWindows} | ${'.exe'} | ${'n/a'}
${Platform.types.StandaloneWindows64} | ${'.exe'} | ${'n/a'}
`(
'appends $expectedExtension for $targetPlatform with androidExportType $androidExportType',
async ({ targetPlatform, expectedExtension, androidExportType }) => {
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform); jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform); jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'androidExportType', 'get').mockReturnValue(androidExportType);
await expect(BuildParameters.create()).resolves.toEqual( await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildFile: `${targetPlatform}.exe` }), expect.objectContaining({ buildFile: `${targetPlatform}${expectedExtension}` }),
); );
}, },
); );
test.each([Platform.types.Android])('appends apk for %s', async (targetPlatform) => { test.each`
targetPlatform | androidSymbolType
${Platform.types.Android} | ${'none'}
${Platform.types.Android} | ${'public'}
${Platform.types.Android} | ${'debugging'}
${Platform.types.StandaloneWindows} | ${'none'}
${Platform.types.StandaloneWindows64} | ${'none'}
`(
'androidSymbolType is set to $androidSymbolType when targetPlatform is $targetPlatform and input targetSymbolType is $androidSymbolType',
async ({ targetPlatform, androidSymbolType }) => {
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform); jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'androidSymbolType', 'get').mockReturnValue(androidSymbolType);
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform); jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(false); await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidSymbolType }));
await expect(BuildParameters.create()).resolves.toEqual( },
expect.objectContaining({ buildFile: `${targetPlatform}.apk` }),
); );
});
test.each([Platform.types.Android])('appends aab for %s', async (targetPlatform) => {
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(true);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildFile: `${targetPlatform}.aab` }),
);
});
it('returns the build method', async () => { it('returns the build method', async () => {
const mockValue = 'Namespace.ClassName.BuildMethod'; const mockValue = 'Namespace.ClassName.BuildMethod';

View File

@ -13,11 +13,14 @@ import GitHub from './github';
import CloudRunnerOptions from './cloud-runner/cloud-runner-options'; import CloudRunnerOptions from './cloud-runner/cloud-runner-options';
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 runnerTempPath: string | undefined; public runnerTempPath!: string;
public targetPlatform!: string; public targetPlatform!: string;
public projectPath!: string; public projectPath!: string;
public buildName!: string; public buildName!: string;
@ -33,6 +36,9 @@ class BuildParameters {
public androidKeyaliasPass!: string; public androidKeyaliasPass!: string;
public androidTargetSdkVersion!: string; public androidTargetSdkVersion!: string;
public androidSdkManagerParameters!: string; public androidSdkManagerParameters!: string;
public androidExportType!: string;
public androidSymbolType!: string;
public customParameters!: string; public customParameters!: string;
public sshAgent!: string; public sshAgent!: string;
public cloudRunnerCluster!: string; public cloudRunnerCluster!: string;
@ -40,8 +46,8 @@ class BuildParameters {
public gitPrivateToken!: string; public gitPrivateToken!: string;
public awsStackName!: string; public awsStackName!: string;
public kubeConfig!: string; public kubeConfig!: string;
public cloudRunnerMemory!: string; public cloudRunnerMemory!: string | undefined;
public cloudRunnerCpu!: string; public cloudRunnerCpu!: string | undefined;
public kubeVolumeSize!: string; public kubeVolumeSize!: string;
public kubeVolume!: string; public kubeVolume!: string;
public kubeStorageClass!: string; public kubeStorageClass!: string;
@ -61,7 +67,7 @@ class BuildParameters {
public logId!: string; public logId!: string;
public buildGuid!: string; public buildGuid!: string;
public cloudRunnerBranch!: string; public cloudRunnerBranch!: string;
public cloudRunnerDebug!: boolean; public cloudRunnerDebug!: boolean | undefined;
public cloudRunnerBuilderPlatform!: string | undefined; public cloudRunnerBuilderPlatform!: string | undefined;
public isCliMode!: boolean; public isCliMode!: boolean;
public retainWorkspace!: boolean; public retainWorkspace!: boolean;
@ -76,29 +82,43 @@ class BuildParameters {
public triggerWorkflowOnComplete!: string[]; public triggerWorkflowOnComplete!: string[];
public cloudRunnerDebugSkipLFS!: boolean; public cloudRunnerDebugSkipLFS!: boolean;
public cloudRunnerDebugSkipCache!: boolean; public cloudRunnerDebugSkipCache!: boolean;
public cacheUnityInstallationOnMac!: boolean;
public unityHubVersionOnMac!: string;
static async create(): Promise<BuildParameters> { static async create(): Promise<BuildParameters> {
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidAppBundle); const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidExportType);
const editorVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion); const editorVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
const buildVersion = await Versioning.determineBuildVersion(Input.versioningStrategy, Input.specifiedVersion); const buildVersion = await Versioning.determineBuildVersion(Input.versioningStrategy, Input.specifiedVersion);
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode); const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode);
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(Input.androidTargetSdkVersion); const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(Input.androidTargetSdkVersion);
// Todo - Don't use process.env directly, that's what the input model class is for. const androidSymbolExportType = Input.androidSymbolType;
// --- if (Platform.isAndroid(Input.targetPlatform)) {
switch (androidSymbolExportType) {
case 'none':
case 'public':
case 'debugging':
break;
default:
throw new Error(
`Invalid androidSymbolType: ${Input.androidSymbolType}. Must be one of: none, public, debugging`,
);
}
}
let unitySerial = ''; let unitySerial = '';
if (Input.unityLicensingServer === '') { if (Input.unityLicensingServer === '') {
if (!process.env.UNITY_SERIAL && GitHub.githubInputEnabled) { if (!Input.unitySerial && GitHub.githubInputEnabled) {
// No serial was present, so it is a personal license that we need to convert // No serial was present, so it is a personal license that we need to convert
if (!process.env.UNITY_LICENSE) { if (!Input.unityLicense) {
throw new Error(`Missing Unity License File and no Serial was found. If this throw new Error(`Missing Unity License File and no Serial was found. If this
is a personal license, make sure to follow the activation is a personal license, make sure to follow the activation
steps and set the UNITY_LICENSE GitHub secret or enter a Unity steps and set the UNITY_LICENSE GitHub secret or enter a Unity
serial number inside the UNITY_SERIAL GitHub secret.`); serial number inside the UNITY_SERIAL GitHub secret.`);
} }
unitySerial = this.getSerialFromLicenseFile(process.env.UNITY_LICENSE); unitySerial = this.getSerialFromLicenseFile(Input.unityLicense);
} else { } else {
unitySerial = process.env.UNITY_SERIAL!; unitySerial = Input.unitySerial!;
} }
} }
@ -107,7 +127,7 @@ class BuildParameters {
customImage: Input.customImage, customImage: Input.customImage,
unitySerial, unitySerial,
unityLicensingServer: Input.unityLicensingServer, unityLicensingServer: Input.unityLicensingServer,
runnerTempPath: process.env.RUNNER_TEMP, runnerTempPath: Input.runnerTempPath,
targetPlatform: Input.targetPlatform, targetPlatform: Input.targetPlatform,
projectPath: Input.projectPath, projectPath: Input.projectPath,
buildName: Input.buildName, buildName: Input.buildName,
@ -123,6 +143,8 @@ class BuildParameters {
androidKeyaliasPass: Input.androidKeyaliasPass, androidKeyaliasPass: Input.androidKeyaliasPass,
androidTargetSdkVersion: Input.androidTargetSdkVersion, androidTargetSdkVersion: Input.androidTargetSdkVersion,
androidSdkManagerParameters, androidSdkManagerParameters,
androidExportType: Input.androidExportType,
androidSymbolType: androidSymbolExportType,
customParameters: Input.customParameters, customParameters: Input.customParameters,
sshAgent: Input.sshAgent, sshAgent: Input.sshAgent,
gitPrivateToken: Input.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()), gitPrivateToken: Input.gitPrivateToken || (await GithubCliReader.GetGitHubAuthToken()),
@ -165,22 +187,35 @@ class BuildParameters {
triggerWorkflowOnComplete: CloudRunnerOptions.triggerWorkflowOnComplete, triggerWorkflowOnComplete: CloudRunnerOptions.triggerWorkflowOnComplete,
cloudRunnerDebugSkipLFS: CloudRunnerOptions.cloudRunnerDebugSkipLFS, cloudRunnerDebugSkipLFS: CloudRunnerOptions.cloudRunnerDebugSkipLFS,
cloudRunnerDebugSkipCache: CloudRunnerOptions.cloudRunnerDebugSkipCache, cloudRunnerDebugSkipCache: CloudRunnerOptions.cloudRunnerDebugSkipCache,
cacheUnityInstallationOnMac: Input.cacheUnityInstallationOnMac,
unityHubVersionOnMac: Input.unityHubVersionOnMac,
}; };
} }
static parseBuildFile(filename, platform, androidAppBundle) { static parseBuildFile(filename: string, platform: string, androidExportType: string): string {
if (Platform.isWindows(platform)) { if (Platform.isWindows(platform)) {
return `${filename}.exe`; return `${filename}.exe`;
} }
if (Platform.isAndroid(platform)) { if (Platform.isAndroid(platform)) {
return androidAppBundle ? `${filename}.aab` : `${filename}.apk`; switch (androidExportType) {
case `androidPackage`:
return `${filename}.apk`;
case `androidAppBundle`:
return `${filename}.aab`;
case `androidStudioProject`:
return filename;
default:
throw new Error(
`Unknown Android Export Type: ${androidExportType}. Must be one of androidPackage for apk, androidAppBundle for aab, androidStudioProject for android project`,
);
}
} }
return filename; return filename;
} }
static getSerialFromLicenseFile(license) { static getSerialFromLicenseFile(license: string) {
const startKey = `<DeveloperData Value="`; const startKey = `<DeveloperData Value="`;
const endKey = `"/>`; const endKey = `"/>`;
const startIndex = license.indexOf(startKey) + startKey.length; const startIndex = license.indexOf(startKey) + startKey.length;

View File

@ -1,5 +1,5 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import fs from 'fs'; import fs from 'node:fs';
import Action from './action'; import Action from './action';
import Project from './project'; import Project from './project';

View File

@ -16,7 +16,7 @@ export class CliFunctionsRepository {
}); });
} }
public static GetCliFunctions(key) { public static GetCliFunctions(key: any) {
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}`);

View File

@ -13,13 +13,15 @@ import GitHub from '../github';
import { TaskParameterSerializer } from '../cloud-runner/services/task-parameter-serializer'; import { TaskParameterSerializer } from '../cloud-runner/services/task-parameter-serializer';
import { CloudRunnerFolders } from '../cloud-runner/services/cloud-runner-folders'; import { CloudRunnerFolders } from '../cloud-runner/services/cloud-runner-folders';
import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system'; import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system';
import { OptionValues } from 'commander';
import { InputKey } from '../input';
export class Cli { export class Cli {
public static options; public static options: OptionValues | undefined;
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, alternativeKey) { public static query(key: string, alternativeKey: string) {
if (Cli.options && Cli.options[key] !== undefined) { if (Cli.options && Cli.options[key] !== undefined) {
return Cli.options[key]; return Cli.options[key];
} }
@ -61,15 +63,15 @@ 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';
const buildParameter = TaskParameterSerializer.readBuildParameterFromEnvironment(); const buildParameter = TaskParameterSerializer.readBuildParameterFromEnvironment();
CloudRunnerLogger.log(`Build Params: CloudRunnerLogger.log(`Build Params:
@ -88,14 +90,15 @@ export class Cli {
const properties = CloudRunnerOptionsReader.GetProperties(); const properties = CloudRunnerOptionsReader.GetProperties();
for (const element of properties) { for (const element of properties) {
if ( if (
Input[element] !== undefined && element in Input &&
Input[element] !== '' && Input[element as InputKey] !== undefined &&
typeof Input[element] !== `function` && Input[element as InputKey] !== '' &&
typeof Input[element as InputKey] !== `function` &&
element !== 'length' && element !== 'length' &&
element !== 'cliOptions' && element !== 'cliOptions' &&
element !== 'prototype' element !== 'prototype'
) { ) {
core.info(`${element} ${Input[element]}`); core.info(`${element} ${Input[element as InputKey]}`);
} }
} }
core.info(`\n`); core.info(`\n`);

View File

@ -2,7 +2,7 @@ import CloudRunnerLogger from '../../services/cloud-runner-logger';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as SDK from 'aws-sdk'; import * as SDK from 'aws-sdk';
import { BaseStackFormation } from './cloud-formations/base-stack-formation'; import { BaseStackFormation } from './cloud-formations/base-stack-formation';
const crypto = require('crypto'); import crypto from 'node:crypto';
export class AWSBaseStack { export class AWSBaseStack {
constructor(baseStackName: string) { constructor(baseStackName: string) {

View File

@ -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) { public static getParameterTemplate(p1: string) {
return ` return `
${p1}: ${p1}:
Type: String Type: String
@ -9,7 +9,7 @@ export class AWSCloudFormationTemplates {
`; `;
} }
public static getSecretTemplate(p1) { public static getSecretTemplate(p1: string) {
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, p2) { public static getSecretDefinitionTemplate(p1: string, p2: string) {
return ` return `
- Name: '${p1}' - Name: '${p1}'
ValueFrom: !Ref ${p2}Secret ValueFrom: !Ref ${p2}Secret
`; `;
} }
public static insertAtTemplate(template, insertionKey, insertion) { public static insertAtTemplate(template: string, insertionKey: string, insertion: string) {
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('');

View File

@ -2,7 +2,7 @@ import * as AWS from 'aws-sdk';
import CloudRunnerEnvironmentVariable from '../../services/cloud-runner-environment-variable'; import CloudRunnerEnvironmentVariable from '../../services/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 'zlib'; import * as zlib from 'node:zlib';
import CloudRunnerLogger from '../../services/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';
@ -197,22 +197,19 @@ class AWSTaskRunner {
} }
private static logRecords( private static logRecords(
records, records: AWS.Kinesis.GetRecordsOutput,
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 (let index = 0; index < records.Records.length; index++) { for (const record of records.Records) {
const json = JSON.parse( const json = JSON.parse(zlib.gunzipSync(Buffer.from(record.Data 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 (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) { for (const logEvent of json.logEvents) {
const message = json.logEvents[logEventsIndex].message;
({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration( ({ shouldReadLogs, shouldCleanup, output } = FollowLogStreamService.handleIteration(
message, logEvent.message,
shouldReadLogs, shouldReadLogs,
shouldCleanup, shouldCleanup,
output, output,
@ -231,7 +228,7 @@ class AWSTaskRunner {
}).promise(); }).promise();
} }
private static async getLogIterator(stream) { private static async getLogIterator(stream: AWS.Kinesis.DescribeStreamOutput) {
return ( return (
( (
await AWSTaskRunner.Kinesis.getShardIterator({ await AWSTaskRunner.Kinesis.getShardIterator({

View File

@ -4,7 +4,7 @@ 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: any) { static isOlderThan1day(date: Date) {
const ageDate = new Date(date.getTime() - Date.now()); const ageDate = new Date(date.getTime() - Date.now());
return ageDate.getDay() > 0; return ageDate.getDay() > 0;
@ -17,14 +17,16 @@ export class GarbageCollectionService {
const cwl = new AWS.CloudWatchLogs(); 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.stopTask({ task: taskElement.taskArn || '', cluster: element }).promise(); 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 (
@ -36,13 +38,15 @@ export class GarbageCollectionService {
return; return;
} }
if (deleteResources && (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(element.CreationTime))) { if (deleteResources && (!OneDayOlderOnly || 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: AWS.CloudFormation.DeleteStackInput = { StackName: element.StackName };
await CF.deleteStack(deleteStackInput).promise(); await CF.deleteStack(deleteStackInput).promise();
} }
@ -51,7 +55,7 @@ export class GarbageCollectionService {
for (const element of logGroups) { for (const element of logGroups) {
if ( if (
deleteResources && deleteResources &&
(!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.createdAt))) (!OneDayOlderOnly || GarbageCollectionService.isOlderThan1day(new Date(element.creationTime!)))
) { ) {
CloudRunnerLogger.log(`Deleting ${element.logGroupName}`); CloudRunnerLogger.log(`Deleting ${element.logGroupName}`);
await cwl.deleteLogGroup({ logGroupName: element.logGroupName || '' }).promise(); await cwl.deleteLogGroup({ logGroupName: element.logGroupName || '' }).promise();

View File

@ -5,6 +5,8 @@ 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 { ListObjectsRequest } from 'aws-sdk/clients/s3';
import CloudRunner from '../../../cloud-runner'; import CloudRunner from '../../../cloud-runner';
import { StackSummaries } from 'aws-sdk/clients/cloudformation';
import { LogGroups } from 'aws-sdk/clients/cloudwatchlogs';
export class TaskService { export class TaskService {
static async watch() { static async watch() {
@ -18,7 +20,7 @@ export class TaskService {
return output; return output;
} }
public static async getCloudFormationJobStacks() { public static async getCloudFormationJobStacks() {
const result: any[] = []; const result: StackSummaries = [];
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;
@ -62,7 +64,7 @@ export class TaskService {
return result; return result;
} }
public static async getTasks() { public static async getTasks() {
const result: any[] = []; const result: { taskElement: AWS.ECS.Task; element: string }[] = [];
CloudRunnerLogger.log(``); CloudRunnerLogger.log(``);
CloudRunnerLogger.log(`List Tasks`); CloudRunnerLogger.log(`List Tasks`);
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
@ -123,7 +125,7 @@ export class TaskService {
return message; return message;
} }
public static async getLogGroups() { public static async getLogGroups() {
const result: any[] = []; const result: LogGroups = [];
process.env.AWS_REGION = Input.region; process.env.AWS_REGION = Input.region;
const ecs = new AWS.CloudWatchLogs(); const ecs = new AWS.CloudWatchLogs();
let logStreamInput: AWS.CloudWatchLogs.DescribeLogGroupsRequest = { let logStreamInput: AWS.CloudWatchLogs.DescribeLogGroupsRequest = {

View File

@ -16,10 +16,10 @@ class KubernetesJobSpecFactory {
secrets: CloudRunnerSecret[], secrets: CloudRunnerSecret[],
buildGuid: string, buildGuid: string,
buildParameters: BuildParameters, buildParameters: BuildParameters,
secretName, secretName: string,
pvcName, pvcName: string,
jobName, jobName: string,
k8s, k8s: any,
) { ) {
environment.push( environment.push(
...[ ...[

View File

@ -2,7 +2,7 @@ import { CoreV1Api } from '@kubernetes/client-node';
import CloudRunnerSecret from '../../services/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/cloud-runner-logger'; import CloudRunnerLogger from '../../services/cloud-runner-logger';
const base64 = require('base-64'); import * as base64 from 'base-64';
class KubernetesSecret { class KubernetesSecret {
static async createSecret( static async createSecret(

View File

@ -3,7 +3,7 @@ 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/cloud-runner-logger'; import CloudRunnerLogger from '../../services/cloud-runner-logger';
import { IncomingMessage } from 'http'; import { IncomingMessage } from 'node:http';
import GitHub from '../../../github'; import GitHub from '../../../github';
class KubernetesStorage { class KubernetesStorage {

View File

@ -14,7 +14,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;
setupWorkflow( setupWorkflow(
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
buildGuid: string, buildGuid: string,
@ -24,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,

View File

@ -1,6 +1,6 @@
import { assert } from 'console'; import { assert } from 'node:console';
import fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
import CloudRunner from '../cloud-runner'; import CloudRunner from '../cloud-runner';
import CloudRunnerLogger from '../services/cloud-runner-logger'; import CloudRunnerLogger from '../services/cloud-runner-logger';
import { CloudRunnerFolders } from '../services/cloud-runner-folders'; import { CloudRunnerFolders } from '../services/cloud-runner-folders';
@ -10,7 +10,7 @@ import { RemoteClientLogger } from './remote-client-logger';
import { Cli } from '../../cli/cli'; import { Cli } from '../../cli/cli';
import { CliFunction } from '../../cli/cli-functions-repository'; import { CliFunction } from '../../cli/cli-functions-repository';
// eslint-disable-next-line github/no-then // eslint-disable-next-line github/no-then
const fileExists = async (fpath) => !!(await fs.promises.stat(fpath).catch(() => false)); const fileExists = async (fpath: fs.PathLike) => !!(await fs.promises.stat(fpath).catch(() => false));
export class Caching { export class Caching {
@CliFunction(`cache-push`, `push to cache`) @CliFunction(`cache-push`, `push to cache`)
@ -19,9 +19,9 @@ export class Caching {
const buildParameter = JSON.parse(process.env.BUILD_PARAMETERS || '{}'); const buildParameter = JSON.parse(process.env.BUILD_PARAMETERS || '{}');
CloudRunner.buildParameters = buildParameter; CloudRunner.buildParameters = buildParameter;
await Caching.PushToCache( await Caching.PushToCache(
Cli.options['cachePushTo'], Cli.options!['cachePushTo'],
Cli.options['cachePushFrom'], Cli.options!['cachePushFrom'],
Cli.options['artifactName'] || '', Cli.options!['artifactName'] || '',
); );
} catch (error: any) { } catch (error: any) {
CloudRunnerLogger.log(`${error}`); CloudRunnerLogger.log(`${error}`);
@ -34,9 +34,9 @@ export class Caching {
const buildParameter = JSON.parse(process.env.BUILD_PARAMETERS || '{}'); const buildParameter = JSON.parse(process.env.BUILD_PARAMETERS || '{}');
CloudRunner.buildParameters = buildParameter; CloudRunner.buildParameters = buildParameter;
await Caching.PullFromCache( await Caching.PullFromCache(
Cli.options['cachePushFrom'], Cli.options!['cachePushFrom'],
Cli.options['cachePushTo'], Cli.options!['cachePushTo'],
Cli.options['artifactName'] || '', Cli.options!['artifactName'] || '',
); );
} catch (error: any) { } catch (error: any) {
CloudRunnerLogger.log(`${error}`); CloudRunnerLogger.log(`${error}`);

View File

@ -1,11 +1,11 @@
import fs from 'fs'; import fs from 'node:fs';
import CloudRunner from '../cloud-runner'; import CloudRunner from '../cloud-runner';
import { CloudRunnerFolders } from '../services/cloud-runner-folders'; import { CloudRunnerFolders } from '../services/cloud-runner-folders';
import { Caching } from './caching'; import { Caching } from './caching';
import { LfsHashing } from '../services/lfs-hashing'; import { LfsHashing } from '../services/lfs-hashing';
import { RemoteClientLogger } from './remote-client-logger'; import { RemoteClientLogger } from './remote-client-logger';
import path from 'path'; import path from 'node:path';
import { assert } from 'console'; import { assert } from 'node:console';
import CloudRunnerLogger from '../services/cloud-runner-logger'; import CloudRunnerLogger from '../services/cloud-runner-logger';
import { CliFunction } from '../../cli/cli-functions-repository'; import { CliFunction } from '../../cli/cli-functions-repository';
import { CloudRunnerSystem } from '../services/cloud-runner-system'; import { CloudRunnerSystem } from '../services/cloud-runner-system';

View File

@ -13,7 +13,7 @@ export class RemoteClientLogger {
CloudRunnerLogger.log(`[Client][Diagnostic] ${message}`); CloudRunnerLogger.log(`[Client][Diagnostic] ${message}`);
} }
public static logWarning(message) { public static logWarning(message: string) {
CloudRunnerLogger.logWarning(message); CloudRunnerLogger.logWarning(message);
} }
} }

View File

@ -3,11 +3,12 @@ import CloudRunner from '../cloud-runner';
import * as core from '@actions/core'; import * as core from '@actions/core';
import { CustomWorkflow } from '../workflows/custom-workflow'; import { CustomWorkflow } from '../workflows/custom-workflow';
import { RemoteClientLogger } from '../remote-client/remote-client-logger'; import { RemoteClientLogger } from '../remote-client/remote-client-logger';
import path from 'path'; import path from 'node:path';
import * as fs from 'fs'; import fs from 'node:fs';
import Input from '../../input'; import Input from '../../input';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import { CustomStep } from './custom-step'; import { CustomStep } from './custom-step';
import { CloudRunnerStepState } from '../cloud-runner-step-state';
export class CloudRunnerCustomSteps { export class CloudRunnerCustomSteps {
static GetCustomStepsFromFiles(hookLifecycle: string): CustomStep[] { static GetCustomStepsFromFiles(hookLifecycle: string): CustomStep[] {
@ -183,13 +184,13 @@ export class CloudRunnerCustomSteps {
return results; return results;
} }
private static ConvertYamlSecrets(object) { private static ConvertYamlSecrets(object: CustomStep) {
if (object.secrets === undefined) { if (object.secrets === undefined) {
object.secrets = []; object.secrets = [];
return; return;
} }
object.secrets = object.secrets.map((x) => { object.secrets = object.secrets.map((x: { [key: string]: any }) => {
return { return {
ParameterKey: x.name, ParameterKey: x.name,
EnvironmentVariable: Input.ToEnvVarFormat(x.name), EnvironmentVariable: Input.ToEnvVarFormat(x.name),
@ -229,7 +230,7 @@ export class CloudRunnerCustomSteps {
return object; return object;
} }
static async RunPostBuildSteps(cloudRunnerStepState) { static async RunPostBuildSteps(cloudRunnerStepState: CloudRunnerStepState) {
let output = ``; let output = ``;
const steps: CustomStep[] = [ const steps: CustomStep[] = [
...CloudRunnerCustomSteps.ParseSteps(CloudRunner.buildParameters.postBuildSteps), ...CloudRunnerCustomSteps.ParseSteps(CloudRunner.buildParameters.postBuildSteps),
@ -248,7 +249,7 @@ export class CloudRunnerCustomSteps {
return output; return output;
} }
static async RunPreBuildSteps(cloudRunnerStepState) { static async RunPreBuildSteps(cloudRunnerStepState: CloudRunnerStepState) {
let output = ``; let output = ``;
const steps: CustomStep[] = [ const steps: CustomStep[] = [
...CloudRunnerCustomSteps.ParseSteps(CloudRunner.buildParameters.preBuildSteps), ...CloudRunnerCustomSteps.ParseSteps(CloudRunner.buildParameters.preBuildSteps),

View File

@ -1,4 +1,4 @@
import path from 'path'; import path from 'node:path';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import CloudRunner from './../cloud-runner'; import CloudRunner from './../cloud-runner';

View File

@ -2,7 +2,7 @@ import Input from '../../input';
import { GenericInputReader } from '../../input-readers/generic-input-reader'; import { GenericInputReader } from '../../input-readers/generic-input-reader';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
const formatFunction = (value, arguments_) => { const formatFunction = (value: string, arguments_: any[]) => {
for (const element of arguments_) { for (const element of arguments_) {
value = value.replace(`{${element.key}}`, element.value); value = value.replace(`{${element.key}}`, element.value);
} }
@ -11,11 +11,11 @@ const formatFunction = (value, arguments_) => {
}; };
class CloudRunnerQueryOverride { class CloudRunnerQueryOverride {
static queryOverrides: any; static queryOverrides: { [key: string]: string } | undefined;
// TODO accept premade secret sources or custom secret source definition yamls // TODO accept premade secret sources or custom secret source definition yamls
public static query(key, alternativeKey) { public static query(key: string, alternativeKey: string) {
if (CloudRunnerQueryOverride.queryOverrides && CloudRunnerQueryOverride.queryOverrides[key] !== undefined) { if (CloudRunnerQueryOverride.queryOverrides && CloudRunnerQueryOverride.queryOverrides[key] !== undefined) {
return CloudRunnerQueryOverride.queryOverrides[key]; return CloudRunnerQueryOverride.queryOverrides[key];
} }
@ -30,7 +30,7 @@ class CloudRunnerQueryOverride {
return; return;
} }
private static shouldUseOverride(query) { private static shouldUseOverride(query: string) {
if (CloudRunnerOptions.readInputOverrideCommand() !== '') { if (CloudRunnerOptions.readInputOverrideCommand() !== '') {
if (CloudRunnerOptions.readInputFromOverrideList() !== '') { if (CloudRunnerOptions.readInputFromOverrideList() !== '') {
const doesInclude = const doesInclude =
@ -44,7 +44,7 @@ class CloudRunnerQueryOverride {
} }
} }
private static async queryOverride(query) { private static async queryOverride(query: string) {
if (!this.shouldUseOverride(query)) { if (!this.shouldUseOverride(query)) {
throw new Error(`Should not be trying to run override query on ${query}`); throw new Error(`Should not be trying to run override query on ${query}`);
} }
@ -56,7 +56,7 @@ class CloudRunnerQueryOverride {
public static async PopulateQueryOverrideInput() { public static async PopulateQueryOverrideInput() {
const queries = CloudRunnerOptions.readInputFromOverrideList().split(','); const queries = CloudRunnerOptions.readInputFromOverrideList().split(',');
CloudRunnerQueryOverride.queryOverrides = new Array(); CloudRunnerQueryOverride.queryOverrides = {};
for (const element of queries) { for (const element of queries) {
if (CloudRunnerQueryOverride.shouldUseOverride(element)) { if (CloudRunnerQueryOverride.shouldUseOverride(element)) {
CloudRunnerQueryOverride.queryOverrides[element] = await CloudRunnerQueryOverride.queryOverride(element); CloudRunnerQueryOverride.queryOverrides[element] = await CloudRunnerQueryOverride.queryOverride(element);

View File

@ -1,9 +1,9 @@
import CloudRunnerSecret from './cloud-runner-secret'; import CloudRunnerSecret from './cloud-runner-secret';
export class CustomStep { export class CustomStep {
public commands; public commands!: string;
public secrets: CloudRunnerSecret[] = new Array<CloudRunnerSecret>(); public secrets: CloudRunnerSecret[] = new Array<CloudRunnerSecret>();
public name; public name!: string;
public image: string = `ubuntu`; public image: string = `ubuntu`;
public hook!: string; public hook!: string;
} }

View File

@ -1,5 +1,5 @@
import { CloudRunnerSystem } from './cloud-runner-system'; import { CloudRunnerSystem } from './cloud-runner-system';
import * as fs from 'fs'; import fs from 'node:fs';
import CloudRunnerLogger from './cloud-runner-logger'; import CloudRunnerLogger from './cloud-runner-logger';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import BuildParameters from '../../build-parameters'; import BuildParameters from '../../build-parameters';

View File

@ -44,20 +44,21 @@ export class TaskParameterSerializer {
x.name = TaskParameterSerializer.ToEnvVarFormat(x.name); x.name = TaskParameterSerializer.ToEnvVarFormat(x.name);
x.value = `${x.value}`; x.value = `${x.value}`;
if (buildParameters.cloudRunnerDebug && Number(x.name) === Number.NaN) { if (buildParameters.cloudRunnerDebug && Number.isNaN(Number(x.name))) {
core.info(`[ERROR] found a number in task param serializer ${JSON.stringify(x)}`); core.info(`[ERROR] found a number in task param serializer ${JSON.stringify(x)}`);
} }
return x; return x;
}), }),
(item) => item.name, (item: CloudRunnerEnvironmentVariable) => item.name,
); );
return result; return result;
} }
static uniqBy(a, key) { // eslint-disable-next-line no-unused-vars
const seen = {}; static uniqBy(a: CloudRunnerEnvironmentVariable[], key: (parameters: CloudRunnerEnvironmentVariable) => string) {
const seen: { [key: string]: boolean } = {};
return a.filter(function (item) { return a.filter(function (item) {
const k = key(item); const k = key(item);
@ -89,23 +90,23 @@ export class TaskParameterSerializer {
return TaskParameterSerializer.serializeFromType(Input); return TaskParameterSerializer.serializeFromType(Input);
} }
public static ToEnvVarFormat(input): string { public static ToEnvVarFormat(input: string): string {
return CloudRunnerOptions.ToEnvVarFormat(input); return CloudRunnerOptions.ToEnvVarFormat(input);
} }
public static UndoEnvVarFormat(element): string { public static UndoEnvVarFormat(element: string): string {
return this.camelize(element.replace('GAMECI_', '').toLowerCase().replace(/_+/g, ' ')); return this.camelize(element.replace('GAMECI_', '').toLowerCase().replace(/_+/g, ' '));
} }
private static camelize(string) { private static camelize(string: string) {
return string return string
.replace(/^\w|[A-Z]|\b\w/g, function (word, index) { .replace(/(^\w)|([A-Z])|(\b\w)/g, function (word: string, index: number) {
return index === 0 ? word.toLowerCase() : word.toUpperCase(); return index === 0 ? word.toLowerCase() : word.toUpperCase();
}) })
.replace(/\s+/g, ''); .replace(/\s+/g, '');
} }
private static serializeFromObject(buildParameters) { private static serializeFromObject(buildParameters: any) {
const array: any[] = []; const array: any[] = [];
const keys = Object.getOwnPropertyNames(buildParameters).filter((x) => !this.blocked.has(x)); const keys = Object.getOwnPropertyNames(buildParameters).filter((x) => !this.blocked.has(x));
for (const element of keys) { for (const element of keys) {
@ -124,7 +125,7 @@ export class TaskParameterSerializer {
return array; return array;
} }
private static serializeFromType(type) { private static serializeFromType(type: any) {
const array: any[] = []; const array: any[] = [];
const input = CloudRunnerOptionsReader.GetProperties(); const input = CloudRunnerOptionsReader.GetProperties();
for (const element of input) { for (const element of input) {
@ -149,14 +150,15 @@ export class TaskParameterSerializer {
return array; return array;
} }
private static getValue(key) {
private static getValue(key: string) {
return CloudRunnerQueryOverride.queryOverrides !== undefined && return CloudRunnerQueryOverride.queryOverrides !== undefined &&
CloudRunnerQueryOverride.queryOverrides[key] !== undefined CloudRunnerQueryOverride.queryOverrides[key] !== undefined
? CloudRunnerQueryOverride.queryOverrides[key] ? CloudRunnerQueryOverride.queryOverrides[key]
: process.env[key]; : process.env[key];
} }
s;
private static tryAddInput(array, key): CloudRunnerSecret[] { private static tryAddInput(array: CloudRunnerSecret[], key: string): CloudRunnerSecret[] {
const value = TaskParameterSerializer.getValue(key); const value = TaskParameterSerializer.getValue(key);
if (value !== undefined && value !== '' && value !== 'null') { if (value !== undefined && value !== '' && value !== 'null') {
array.push({ array.push({

View File

@ -4,8 +4,9 @@ import UnityVersioning from '../../unity-versioning';
import { Cli } from '../../cli/cli'; import { Cli } from '../../cli/cli';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import setups from './cloud-runner-suite.test'; import setups from './cloud-runner-suite.test';
import { OptionValues } from 'commander';
async function CreateParameters(overrides) { async function CreateParameters(overrides: OptionValues | undefined) {
if (overrides) Cli.options = overrides; if (overrides) Cli.options = overrides;
return BuildParameters.create(); return BuildParameters.create();

View File

@ -1,5 +1,5 @@
import fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
import BuildParameters from '../../build-parameters'; import BuildParameters from '../../build-parameters';
import { Cli } from '../../cli/cli'; import { Cli } from '../../cli/cli';
import UnityVersioning from '../../unity-versioning'; import UnityVersioning from '../../unity-versioning';

View File

@ -7,8 +7,9 @@ import { v4 as uuidv4 } from 'uuid';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import setups from './cloud-runner-suite.test'; import setups from './cloud-runner-suite.test';
import { CloudRunnerSystem } from '../services/cloud-runner-system'; import { CloudRunnerSystem } from '../services/cloud-runner-system';
import { OptionValues } from 'commander';
async function CreateParameters(overrides) { async function CreateParameters(overrides: OptionValues | undefined) {
if (overrides) { if (overrides) {
Cli.options = overrides; Cli.options = overrides;
} }

View File

@ -4,23 +4,18 @@ import { CloudRunnerStepState } from '../cloud-runner-step-state';
import { WorkflowInterface } from './workflow-interface'; import { WorkflowInterface } from './workflow-interface';
import * as core from '@actions/core'; import * as core from '@actions/core';
import { CloudRunnerCustomHooks } from '../services/cloud-runner-custom-hooks'; import { CloudRunnerCustomHooks } from '../services/cloud-runner-custom-hooks';
import path from 'path'; import path from 'node:path';
import CloudRunner from '../cloud-runner'; import CloudRunner from '../cloud-runner';
import CloudRunnerOptions from '../cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner-options';
import { CloudRunnerCustomSteps } from '../services/cloud-runner-custom-steps'; import { CloudRunnerCustomSteps } from '../services/cloud-runner-custom-steps';
export class BuildAutomationWorkflow implements WorkflowInterface { export class BuildAutomationWorkflow implements WorkflowInterface {
async run(cloudRunnerStepState: CloudRunnerStepState) { async run(cloudRunnerStepState: CloudRunnerStepState) {
try {
return await BuildAutomationWorkflow.standardBuildAutomation(cloudRunnerStepState.image, cloudRunnerStepState); return await BuildAutomationWorkflow.standardBuildAutomation(cloudRunnerStepState.image, cloudRunnerStepState);
} catch (error) {
throw error;
}
} }
private static async standardBuildAutomation(baseImage: any, cloudRunnerStepState: CloudRunnerStepState) { private static async standardBuildAutomation(baseImage: string, cloudRunnerStepState: CloudRunnerStepState) {
// TODO accept post and pre build steps as yaml files in the repo // TODO accept post and pre build steps as yaml files in the repo
try {
CloudRunnerLogger.log(`Cloud Runner is running standard build automation`); CloudRunnerLogger.log(`Cloud Runner is running standard build automation`);
let output = ''; let output = '';
@ -29,7 +24,7 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
CloudRunnerLogger.logWithTime('Configurable pre build step(s) time'); CloudRunnerLogger.logWithTime('Configurable pre build step(s) time');
if (!CloudRunner.buildParameters.isCliMode) core.startGroup('build'); if (!CloudRunner.buildParameters.isCliMode) core.startGroup('build');
CloudRunnerLogger.log(baseImage.toString()); CloudRunnerLogger.log(baseImage);
CloudRunnerLogger.logLine(` `); CloudRunnerLogger.logLine(` `);
CloudRunnerLogger.logLine('Starting build automation job'); CloudRunnerLogger.logLine('Starting build automation job');
@ -51,9 +46,6 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
CloudRunnerLogger.log(`Cloud Runner finished running standard build automation`); CloudRunnerLogger.log(`Cloud Runner finished running standard build automation`);
return output; return output;
} catch (error) {
throw error;
}
} }
private static get BuildWorkflow() { private static get BuildWorkflow() {
@ -85,7 +77,7 @@ export class BuildAutomationWorkflow implements WorkflowInterface {
${BuildAutomationWorkflow.TreeCommand}`; ${BuildAutomationWorkflow.TreeCommand}`;
} }
private static setupCommands(builderPath) { private static setupCommands(builderPath: string) {
const commands = `mkdir -p ${CloudRunnerFolders.ToLinuxFolder( const commands = `mkdir -p ${CloudRunnerFolders.ToLinuxFolder(
CloudRunnerFolders.builderPathAbsolute, CloudRunnerFolders.builderPathAbsolute,
)} && git clone -q -b ${CloudRunner.buildParameters.cloudRunnerBranch} ${ )} && git clone -q -b ${CloudRunner.buildParameters.cloudRunnerBranch} ${
@ -105,7 +97,7 @@ echo "bootstrap game ci cloud runner..."
node ${builderPath} -m remote-cli-pre-build`; node ${builderPath} -m remote-cli-pre-build`;
} }
private static BuildCommands(builderPath) { private static BuildCommands(builderPath: string) {
const distFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist'); const distFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist');
const ubuntuPlatformsFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', 'platforms', 'ubuntu'); const ubuntuPlatformsFolder = path.join(CloudRunnerFolders.builderPathAbsolute, 'dist', 'platforms', 'ubuntu');

View File

@ -4,5 +4,5 @@ export interface WorkflowInterface {
run( run(
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
cloudRunnerStepState: CloudRunnerStepState, cloudRunnerStepState: CloudRunnerStepState,
); ): Promise<string>;
} }

View File

@ -1,16 +1,19 @@
import { exec } from '@actions/exec'; import { execWithErrorCheck } from './exec-with-error-check';
import ImageEnvironmentFactory from './image-environment-factory'; import ImageEnvironmentFactory from './image-environment-factory';
import { existsSync, mkdirSync } from 'fs'; import { existsSync, mkdirSync } from 'node:fs';
import path from 'path'; import path from 'node:path';
import { ExecOptions } from '@actions/exec';
import { DockerParameters, StringKeyValuePair } from './shared-types';
class Docker { class Docker {
static async run( static async run(
image, image: string,
parameters, parameters: DockerParameters,
silent = false, silent: boolean = false,
overrideCommands = '', overrideCommands: string = '',
additionalVariables: any[] = [], additionalVariables: StringKeyValuePair[] = [],
options: any = false, // eslint-disable-next-line unicorn/no-useless-undefined
options: ExecOptions | undefined = undefined,
entrypointBash: boolean = false, entrypointBash: boolean = false,
) { ) {
let runCommand = ''; let runCommand = '';
@ -21,19 +24,19 @@ class Docker {
case 'win32': case 'win32':
runCommand = this.getWindowsCommand(image, parameters); runCommand = this.getWindowsCommand(image, parameters);
} }
if (options !== false) { if (options) {
options.silent = silent; options.silent = silent;
await exec(runCommand, undefined, options); await execWithErrorCheck(runCommand, undefined, options);
} else { } else {
await exec(runCommand, undefined, { silent }); await execWithErrorCheck(runCommand, undefined, { silent });
} }
} }
static getLinuxCommand( static getLinuxCommand(
image, image: string,
parameters, parameters: DockerParameters,
overrideCommands = '', overrideCommands: string = '',
additionalVariables: any[] = [], additionalVariables: StringKeyValuePair[] = [],
entrypointBash: boolean = false, entrypointBash: boolean = false,
): string { ): string {
const { workspace, actionFolder, runnerTempPath, sshAgent, gitPrivateToken } = parameters; const { workspace, actionFolder, runnerTempPath, sshAgent, gitPrivateToken } = parameters;
@ -67,7 +70,7 @@ class Docker {
"${overrideCommands !== '' ? overrideCommands : `/entrypoint.sh`}"`; "${overrideCommands !== '' ? overrideCommands : `/entrypoint.sh`}"`;
} }
static getWindowsCommand(image: any, parameters: any): string { static getWindowsCommand(image: string, parameters: DockerParameters): string {
const { workspace, actionFolder, unitySerial, gitPrivateToken } = parameters; const { workspace, actionFolder, unitySerial, gitPrivateToken } = parameters;
return `docker run \ return `docker run \

View File

@ -0,0 +1,24 @@
import { getExecOutput, ExecOptions } from '@actions/exec';
export async function execWithErrorCheck(
commandLine: string,
arguments_?: string[],
options?: ExecOptions,
): Promise<number> {
const result = await getExecOutput(commandLine, arguments_, options);
// Check for errors in the Build Results section
const match = result.stdout.match(/^#\s*Build results\s*#(.*)^Size:/ms);
if (match) {
const buildResults = match[1];
const errorMatch = buildResults.match(/^Errors:\s*(\d+)$/m);
if (errorMatch && Number.parseInt(errorMatch[1], 10) !== 0) {
throw new Error(`There was an error building the project. Please read the logs for details.`);
}
} else {
throw new Error(`There was an error building the project. Please read the logs for details.`);
}
return result.exitCode;
}

View File

@ -3,6 +3,7 @@ import CloudRunner from './cloud-runner/cloud-runner';
import CloudRunnerOptions from './cloud-runner/cloud-runner-options'; import CloudRunnerOptions from './cloud-runner/cloud-runner-options';
import * as core from '@actions/core'; import * as core from '@actions/core';
import { Octokit } from '@octokit/core'; import { Octokit } from '@octokit/core';
class GitHub { class GitHub {
private static readonly asyncChecksApiWorkflowName = `Async Checks API`; private static readonly asyncChecksApiWorkflowName = `Async Checks API`;
public static githubInputEnabled: boolean = true; public static githubInputEnabled: boolean = true;
@ -44,8 +45,8 @@ class GitHub {
return CloudRunnerOptions.githubRepoName; return CloudRunnerOptions.githubRepoName;
} }
public static async createGitHubCheck(summary) { public static async createGitHubCheck(summary: string) {
if (!CloudRunnerOptions.githubChecks || CloudRunner.isCloudRunnerEnvironment) { if (!CloudRunnerOptions.githubChecks) {
return ``; return ``;
} }
GitHub.startedDate = new Date().toISOString(); GitHub.startedDate = new Date().toISOString();
@ -81,8 +82,7 @@ class GitHub {
} }
public static async updateGitHubCheck(longDescription, summary, result = `neutral`, status = `in_progress`) { public static async updateGitHubCheck(longDescription, summary, result = `neutral`, status = `in_progress`) {
const isLocalAsync = CloudRunner.buildParameters.asyncWorkflow && !CloudRunner.isCloudRunnerAsyncEnvironment; if (!CloudRunnerOptions.githubChecks) {
if (!CloudRunnerOptions.githubChecks || isLocalAsync) {
return; return;
} }
GitHub.longDescriptionContent += `\n${longDescription}`; GitHub.longDescriptionContent += `\n${longDescription}`;
@ -129,15 +129,15 @@ class GitHub {
await GitHub.updateGitHubCheckRequest(data); await GitHub.updateGitHubCheckRequest(data);
} }
public static async updateGitHubCheckRequest(data) { public static async updateGitHubCheckRequest(data: any) {
return await GitHub.octokitDefaultToken.request(`PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}`, data); return await GitHub.octokitDefaultToken.request(`PATCH /repos/{owner}/{repo}/check-runs/{check_run_id}`, data);
} }
public static async createGitHubCheckRequest(data) { public static async createGitHubCheckRequest(data: any) {
return await GitHub.octokitDefaultToken.request(`POST /repos/{owner}/{repo}/check-runs`, data); return await GitHub.octokitDefaultToken.request(`POST /repos/{owner}/{repo}/check-runs`, data);
} }
public static async runUpdateAsyncChecksWorkflow(data, mode) { public static async runUpdateAsyncChecksWorkflow(data: any, mode: string) {
if (mode === `create`) { if (mode === `create`) {
throw new Error(`Not supported: only use update`); throw new Error(`Not supported: only use update`);
} }

View File

@ -1,13 +1,8 @@
import BuildParameters from './build-parameters';
import { ReadLicense } from './input-readers/test-license-reader'; import { ReadLicense } from './input-readers/test-license-reader';
import { DockerParameters, StringKeyValuePair } from './shared-types';
class Parameter {
public name;
public value;
}
class ImageEnvironmentFactory { class ImageEnvironmentFactory {
public static getEnvVarString(parameters, additionalVariables: any[] = []) { public static getEnvVarString(parameters: DockerParameters, additionalVariables: StringKeyValuePair[] = []) {
const environmentVariables = ImageEnvironmentFactory.getEnvironmentVariables(parameters, additionalVariables); const environmentVariables = ImageEnvironmentFactory.getEnvironmentVariables(parameters, additionalVariables);
let string = ''; let string = '';
for (const p of environmentVariables) { for (const p of environmentVariables) {
@ -25,8 +20,9 @@ class ImageEnvironmentFactory {
return string; return string;
} }
public static getEnvironmentVariables(parameters: BuildParameters, additionalVariables: any[] = []) {
let environmentVariables: Parameter[] = [ public static getEnvironmentVariables(parameters: DockerParameters, additionalVariables: StringKeyValuePair[] = []) {
let environmentVariables: StringKeyValuePair[] = [
{ name: 'UNITY_LICENSE', value: process.env.UNITY_LICENSE || ReadLicense() }, { name: 'UNITY_LICENSE', value: process.env.UNITY_LICENSE || ReadLicense() },
{ name: 'UNITY_LICENSE_FILE', value: process.env.UNITY_LICENSE_FILE }, { name: 'UNITY_LICENSE_FILE', value: process.env.UNITY_LICENSE_FILE },
{ name: 'UNITY_EMAIL', value: process.env.UNITY_EMAIL }, { name: 'UNITY_EMAIL', value: process.env.UNITY_EMAIL },
@ -50,6 +46,8 @@ class ImageEnvironmentFactory {
{ name: 'ANDROID_KEYALIAS_PASS', value: parameters.androidKeyaliasPass }, { name: 'ANDROID_KEYALIAS_PASS', value: parameters.androidKeyaliasPass },
{ name: 'ANDROID_TARGET_SDK_VERSION', value: parameters.androidTargetSdkVersion }, { name: 'ANDROID_TARGET_SDK_VERSION', value: parameters.androidTargetSdkVersion },
{ name: 'ANDROID_SDK_MANAGER_PARAMETERS', value: parameters.androidSdkManagerParameters }, { name: 'ANDROID_SDK_MANAGER_PARAMETERS', value: parameters.androidSdkManagerParameters },
{ name: 'ANDROID_EXPORT_TYPE', value: parameters.androidExportType },
{ name: 'ANDROID_SYMBOL_TYPE', value: parameters.androidSymbolType },
{ name: 'CUSTOM_PARAMETERS', value: parameters.customParameters }, { name: 'CUSTOM_PARAMETERS', value: parameters.customParameters },
{ name: 'CHOWN_FILES_TO', value: parameters.chownFilesTo }, { name: 'CHOWN_FILES_TO', value: parameters.chownFilesTo },
{ name: 'GITHUB_REF', value: process.env.GITHUB_REF }, { name: 'GITHUB_REF', value: process.env.GITHUB_REF },

View File

@ -1,7 +1,7 @@
import ImageTag from './image-tag'; import ImageTag from './image-tag';
describe('ImageTag', () => { describe('ImageTag', () => {
const some = { const testImageParameters = {
editorVersion: '2099.9.f9f9', editorVersion: '2099.9.f9f9',
targetPlatform: 'Test', targetPlatform: 'Test',
builderPlatform: '', builderPlatform: '',
@ -15,38 +15,38 @@ describe('ImageTag', () => {
describe('constructor', () => { describe('constructor', () => {
it('can be called', () => { it('can be called', () => {
const { targetPlatform } = some; expect(() => new ImageTag(testImageParameters)).not.toThrow();
expect(() => new ImageTag({ targetPlatform })).not.toThrow();
}); });
it('accepts parameters and sets the right properties', () => { it('accepts parameters and sets the right properties', () => {
const image = new ImageTag(some); const image = new ImageTag(testImageParameters);
expect(image.repository).toStrictEqual('unityci'); expect(image.repository).toStrictEqual('unityci');
expect(image.name).toStrictEqual('editor'); expect(image.name).toStrictEqual('editor');
expect(image.editorVersion).toStrictEqual(some.editorVersion); expect(image.editorVersion).toStrictEqual(testImageParameters.editorVersion);
expect(image.targetPlatform).toStrictEqual(some.targetPlatform); expect(image.targetPlatform).toStrictEqual(testImageParameters.targetPlatform);
expect(image.builderPlatform).toStrictEqual(some.builderPlatform); expect(image.builderPlatform).toStrictEqual(testImageParameters.builderPlatform);
}); });
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', (version) => { test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', (version) => {
expect(() => new ImageTag({ editorVersion: version, targetPlatform: some.targetPlatform })).not.toThrow(); expect(
() => new ImageTag({ editorVersion: version, targetPlatform: testImageParameters.targetPlatform }),
).not.toThrow();
}); });
test.each(['some version', ''])('throws for incorrect version %p', (editorVersion) => { test.each(['some version', ''])('throws for incorrect version %p', (editorVersion) => {
const { targetPlatform } = some; const { targetPlatform } = testImageParameters;
expect(() => new ImageTag({ editorVersion, targetPlatform })).toThrow(); expect(() => new ImageTag({ editorVersion, targetPlatform })).toThrow();
}); });
test.each([undefined, 'nonExisting'])('throws for unsupported target %p', (targetPlatform) => { test.each(['nonExisting'])('throws for unsupported target %p', (targetPlatform) => {
expect(() => new ImageTag({ targetPlatform })).toThrow(); expect(() => new ImageTag({ targetPlatform })).toThrow();
}); });
}); });
describe('toString', () => { describe('toString', () => {
it('returns the correct version', () => { it('returns the correct version', () => {
const image = new ImageTag({ editorVersion: '2099.1.1111', targetPlatform: some.targetPlatform }); const image = new ImageTag({ editorVersion: '2099.1.1111', targetPlatform: testImageParameters.targetPlatform });
switch (process.platform) { switch (process.platform) {
case 'win32': case 'win32':
expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2099.1.1111-1`); expect(image.toString()).toStrictEqual(`${defaults.image}:windows-2099.1.1111-1`);
@ -59,7 +59,7 @@ describe('ImageTag', () => {
it('returns customImage if given', () => { it('returns customImage if given', () => {
const image = new ImageTag({ const image = new ImageTag({
editorVersion: '2099.1.1111', editorVersion: '2099.1.1111',
targetPlatform: some.targetPlatform, targetPlatform: testImageParameters.targetPlatform,
customImage: `${defaults.image}:2099.1.1111@347598437689743986`, customImage: `${defaults.image}:2099.1.1111@347598437689743986`,
}); });
@ -80,7 +80,7 @@ describe('ImageTag', () => {
}); });
it('returns no specific build platform for generic targetPlatforms', () => { it('returns no specific build platform for generic targetPlatforms', () => {
const image = new ImageTag({ targetPlatform: 'NoTarget' }); const image = new ImageTag({ editorVersion: '2019.2.11f1', targetPlatform: 'NoTarget' });
switch (process.platform) { switch (process.platform) {
case 'win32': case 'win32':

View File

@ -1,21 +1,18 @@
import Platform from './platform'; import Platform from './platform';
import BuildParameters from './build-parameters';
import Input from './input';
class ImageTag { class ImageTag {
public repository: string; public repository: string;
public name: string; public name: string;
public cloudRunnerBuilderPlatform!: string | undefined; public cloudRunnerBuilderPlatform!: string;
public editorVersion: string; public editorVersion: string;
public targetPlatform: any; public targetPlatform: string;
public builderPlatform: string; public builderPlatform: string;
public customImage: any; public customImage: string;
public imageRollingVersion: number; public imageRollingVersion: number;
public imagePlatformPrefix: string; public imagePlatformPrefix: string;
constructor(imageProperties: Partial<BuildParameters>) { constructor(imageProperties: { [key: string]: string }) {
const { editorVersion = '2019.2.11f1', targetPlatform, customImage, cloudRunnerBuilderPlatform } = imageProperties; const { editorVersion, targetPlatform, customImage, cloudRunnerBuilderPlatform } = imageProperties;
if (!ImageTag.versionPattern.test(editorVersion)) { if (!ImageTag.versionPattern.test(editorVersion)) {
throw new Error(`Invalid version "${editorVersion}".`); throw new Error(`Invalid version "${editorVersion}".`);
@ -39,8 +36,8 @@ class ImageTag {
this.imageRollingVersion = 1; // Will automatically roll to the latest non-breaking version. this.imageRollingVersion = 1; // Will automatically roll to the latest non-breaking version.
} }
static get versionPattern() { static get versionPattern(): RegExp {
return /^20\d{2}\.\d\.\w{3,4}|3$/; return /^(20\d{2}\.\d\.\w{3,4}|3)$/;
} }
static get targetPlatformSuffixes() { static get targetPlatformSuffixes() {
@ -60,7 +57,7 @@ class ImageTag {
}; };
} }
static getImagePlatformPrefixes(platform) { static getImagePlatformPrefixes(platform: string): string {
switch (platform) { switch (platform) {
case 'win32': case 'win32':
return 'windows'; return 'windows';
@ -71,7 +68,7 @@ class ImageTag {
} }
} }
static getTargetPlatformToTargetPlatformSuffixMap(platform, version) { static getTargetPlatformToTargetPlatformSuffixMap(platform: string, version: string): string {
const { generic, webgl, mac, windows, windowsIl2cpp, wsaPlayer, linux, linuxIl2cpp, android, ios, tvos, facebook } = const { generic, webgl, mac, windows, windowsIl2cpp, wsaPlayer, linux, linuxIl2cpp, android, ios, tvos, facebook } =
ImageTag.targetPlatformSuffixes; ImageTag.targetPlatformSuffixes;
@ -84,7 +81,7 @@ class ImageTag {
case Platform.types.StandaloneWindows: case Platform.types.StandaloneWindows:
case Platform.types.StandaloneWindows64: case Platform.types.StandaloneWindows64:
// Can only build windows-il2cpp on a windows based system // Can only build windows-il2cpp on a windows based system
if (Input.useIL2Cpp && process.platform === 'win32') { if (process.platform === 'win32') {
// Unity versions before 2019.3 do not support il2cpp // Unity versions before 2019.3 do not support il2cpp
if (major >= 2020 || (major === 2019 && minor >= 3)) { if (major >= 2020 || (major === 2019 && minor >= 3)) {
return windowsIl2cpp; return windowsIl2cpp;
@ -97,7 +94,7 @@ class ImageTag {
return windows; return windows;
case Platform.types.StandaloneLinux64: { case Platform.types.StandaloneLinux64: {
// Unity versions before 2019.3 do not support il2cpp // Unity versions before 2019.3 do not support il2cpp
if ((Input.useIL2Cpp && major >= 2020) || (major === 2019 && minor >= 3)) { if (major >= 2020 || (major === 2019 && minor >= 3)) {
return linuxIl2cpp; return linuxIl2cpp;
} }
@ -150,17 +147,17 @@ class ImageTag {
} }
} }
get tag() { get tag(): string {
const versionAndPlatform = `${this.editorVersion}-${this.builderPlatform}`.replace(/-+$/, ''); const versionAndPlatform = `${this.editorVersion}-${this.builderPlatform}`.replace(/-+$/, '');
return `${this.imagePlatformPrefix}-${versionAndPlatform}-${this.imageRollingVersion}`; return `${this.imagePlatformPrefix}-${versionAndPlatform}-${this.imageRollingVersion}`;
} }
get image() { get image(): string {
return `${this.repository}/${this.name}`.replace(/^\/+/, ''); return `${this.repository}/${this.name}`.replace(/^\/+/, '');
} }
toString() { toString(): string {
const { image, tag, customImage } = this; const { image, tag, customImage } = this;
if (customImage) return customImage; if (customImage) return customImage;

View File

@ -1,10 +1,22 @@
import * as Index from '.'; import * as Index from '.';
interface ExportedModules {
[key: string]: any;
Action: any;
BuildParameters: any;
Cache: any;
Docker: any;
ImageTag: any;
Input: any;
Platform: any;
Project: any;
Unity: any;
}
const exportedModules: ExportedModules = Index;
describe('Index', () => { describe('Index', () => {
test.each(['Action', 'BuildParameters', 'Cache', 'Docker', 'ImageTag', 'Input', 'Platform', 'Project', 'Unity'])( test.each(Object.keys(exportedModules))('exports %s', (exportedModule) => {
'exports %s', expect(exportedModules[exportedModule]).toBeDefined();
(exportedModule) => { });
expect(Index[exportedModule]).toBeDefined();
},
);
}); });

View File

@ -1,5 +1,5 @@
import fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
import YAML from 'yaml'; import YAML from 'yaml';
export class ActionYamlReader { export class ActionYamlReader {

View File

@ -2,7 +2,7 @@ import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system'
import CloudRunnerOptions from '../cloud-runner/cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner/cloud-runner-options';
export class GenericInputReader { export class GenericInputReader {
public static async Run(command) { public static async Run(command: string) {
if (CloudRunnerOptions.cloudRunnerCluster === 'local') { if (CloudRunnerOptions.cloudRunnerCluster === 'local') {
return ''; return '';
} }

View File

@ -1,5 +1,5 @@
import { assert } from 'console'; import { assert } from 'node:console';
import fs from 'fs'; import fs from 'node:fs';
import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system'; import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system';
import CloudRunnerLogger from '../cloud-runner/services/cloud-runner-logger'; import CloudRunnerLogger from '../cloud-runner/services/cloud-runner-logger';
import CloudRunnerOptions from '../cloud-runner/cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner/cloud-runner-options';

View File

@ -1,9 +1,9 @@
import path from 'path'; import path from 'node:path';
import fs from 'fs'; import fs from 'node:fs';
import YAML from 'yaml'; import YAML from 'yaml';
import CloudRunnerOptions from '../cloud-runner/cloud-runner-options'; import CloudRunnerOptions from '../cloud-runner/cloud-runner-options';
export function ReadLicense() { export function ReadLicense(): string {
if (CloudRunnerOptions.cloudRunnerCluster === 'local') { if (CloudRunnerOptions.cloudRunnerCluster === 'local') {
return ''; return '';
} }

View File

@ -161,6 +161,82 @@ describe('Input', () => {
}); });
}); });
describe('androidExportType', () => {
it('returns the default value', () => {
expect(Input.androidExportType).toStrictEqual('androidPackage');
});
// TODO: Remove "and androidAppBundle is not set" in v3
test.each`
input | expected
${'androidPackage'} | ${'androidPackage'}
${'androidAppBundle'} | ${'androidAppBundle'}
${'androidStudioProject'} | ${'androidStudioProject'}
`('returns $expected when $input is passed and androidAppBundle is not set', ({ input, expected }) => {
const spy = jest.spyOn(core, 'getInput').mockReturnValue(input);
expect(Input.androidExportType).toStrictEqual(expected);
expect(spy).toHaveBeenCalledTimes(1);
});
// TODO: Remove in v3
test.each`
input | expected
${'androidPackage'} | ${'androidPackage'}
${'androidAppBundle'} | ${'androidAppBundle'}
${'androidStudioProject'} | ${'androidStudioProject'}
`('returns $expected when $input is passed and overrides androidAppBundle if it is set', ({ input, expected }) => {
const spy = jest.spyOn(Input, 'getInput');
spy.mockImplementationOnce(() => {
return input;
});
spy.mockImplementationOnce(() => {
return 'true';
});
expect(Input.androidExportType).toStrictEqual(expected);
expect(spy).toHaveBeenCalledTimes(1);
});
// TODO: Remove in v3
test.each`
input | expected
${'true'} | ${'androidAppBundle'}
${'false'} | ${'androidPackage'}
`(
'returns $expected when androidExportType is undefined and androidAppBundle is set to $input',
({ input, expected }) => {
const spy = jest.spyOn(Input, 'getInput');
spy.mockImplementationOnce(() => {
return '';
});
spy.mockImplementationOnce(() => {
return input;
});
expect(Input.androidExportType).toStrictEqual(expected);
expect(spy).toHaveBeenCalledTimes(2);
},
);
});
describe('androidSymbolType', () => {
it('returns the default value', () => {
expect(Input.androidSymbolType).toStrictEqual('none');
});
test.each`
input | expected
${'none'} | ${'none'}
${'public'} | ${'public'}
${'debugging'} | ${'debugging'}
`('returns $expected when $input is passed', ({ input, expected }) => {
const spy = jest.spyOn(core, 'getInput').mockReturnValue(input);
expect(Input.androidExportType).toStrictEqual(expected);
expect(spy).toHaveBeenCalledTimes(1);
});
});
describe('androidKeystoreName', () => { describe('androidKeystoreName', () => {
it('returns the default value', () => { it('returns the default value', () => {
expect(Input.androidKeystoreName).toStrictEqual(''); expect(Input.androidKeystoreName).toStrictEqual('');

View File

@ -1,11 +1,13 @@
import fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
import { Cli } from './cli/cli'; import { Cli } from './cli/cli';
import CloudRunnerQueryOverride from './cloud-runner/services/cloud-runner-query-override'; import CloudRunnerQueryOverride from './cloud-runner/services/cloud-runner-query-override';
import Platform from './platform'; import Platform from './platform';
import GitHub from './github'; import GitHub from './github';
const core = require('@actions/core'); import * as core from '@actions/core';
export type InputKey = keyof typeof Input;
/** /**
* Input variables specified in workflows using "with" prop. * Input variables specified in workflows using "with" prop.
@ -15,7 +17,7 @@ const core = require('@actions/core');
* Todo: rename to UserInput and remove anything that is not direct input from the user / ci workflow * Todo: rename to UserInput and remove anything that is not direct input from the user / ci workflow
*/ */
class Input { class Input {
public static getInput(query) { public static getInput(query: string): string | undefined {
if (GitHub.githubInputEnabled) { if (GitHub.githubInputEnabled) {
const coreInput = core.getInput(query); const coreInput = core.getInput(query);
if (coreInput && coreInput !== '') { if (coreInput && coreInput !== '') {
@ -34,153 +36,201 @@ class Input {
} }
if (process.env[query] !== undefined) { if (process.env[query] !== undefined) {
return process.env[query]; return process.env[query]!;
} }
if (alternativeQuery !== query && process.env[alternativeQuery] !== undefined) { if (alternativeQuery !== query && process.env[alternativeQuery] !== undefined) {
return process.env[alternativeQuery]; return process.env[alternativeQuery]!;
} }
return;
} }
static get region(): string { static get region(): string {
return Input.getInput('region') || 'eu-west-2'; return Input.getInput('region') || 'eu-west-2';
} }
static get githubRepo() { static get githubRepo(): string | undefined {
return Input.getInput('GITHUB_REPOSITORY') || Input.getInput('GITHUB_REPO') || undefined; return Input.getInput('GITHUB_REPOSITORY') || Input.getInput('GITHUB_REPO') || undefined;
} }
static get branch() {
static get branch(): string {
if (Input.getInput(`GITHUB_REF`)) { if (Input.getInput(`GITHUB_REF`)) {
return Input.getInput(`GITHUB_REF`).replace('refs/', '').replace(`head/`, '').replace(`heads/`, ''); return Input.getInput(`GITHUB_REF`)!.replace('refs/', '').replace(`head/`, '').replace(`heads/`, '');
} else if (Input.getInput('branch')) { } else if (Input.getInput('branch')) {
return Input.getInput('branch'); return Input.getInput('branch')!;
} else { } else {
return ''; return '';
} }
} }
static get gitSha() { static get gitSha(): string {
if (Input.getInput(`GITHUB_SHA`)) { if (Input.getInput(`GITHUB_SHA`)) {
return Input.getInput(`GITHUB_SHA`); return Input.getInput(`GITHUB_SHA`)!;
} else if (Input.getInput(`GitSha`)) { } else if (Input.getInput(`GitSHA`)) {
return Input.getInput(`GitSha`); return Input.getInput(`GitSHA`)!;
}
} }
static get useIL2Cpp() { return '';
return Input.getInput(`useIL2Cpp`) || true;
} }
static get runNumber() { static get runNumber(): string {
return Input.getInput('GITHUB_RUN_NUMBER') || Input.getInput('runNumber') || '0'; return Input.getInput('GITHUB_RUN_NUMBER') || '0';
} }
static get targetPlatform() { static get targetPlatform(): string {
return Input.getInput('targetPlatform') || Platform.default; return Input.getInput('targetPlatform') || Platform.default;
} }
static get unityVersion() { static get unityVersion(): string {
return Input.getInput('unityVersion') || 'auto'; return Input.getInput('unityVersion') || 'auto';
} }
static get customImage() { static get customImage(): string {
return Input.getInput('customImage') || ''; return Input.getInput('customImage') || '';
} }
static get projectPath() { static get projectPath(): string {
const input = Input.getInput('projectPath'); const input = Input.getInput('projectPath');
const rawProjectPath = input let rawProjectPath;
? input
: fs.existsSync(path.join('test-project', 'ProjectSettings', 'ProjectVersion.txt')) && if (input) {
rawProjectPath = input;
} else if (
fs.existsSync(path.join('test-project', 'ProjectSettings', 'ProjectVersion.txt')) &&
!fs.existsSync(path.join('ProjectSettings', 'ProjectVersion.txt')) !fs.existsSync(path.join('ProjectSettings', 'ProjectVersion.txt'))
? 'test-project' ) {
: '.'; rawProjectPath = 'test-project';
} else {
rawProjectPath = '.';
}
return rawProjectPath.replace(/\/$/, ''); return rawProjectPath.replace(/\/$/, '');
} }
static get buildName() { static get runnerTempPath(): string {
return Input.getInput('buildName') || this.targetPlatform; return Input.getInput('RUNNER_TEMP') || '';
} }
static get buildsPath() { static get buildName(): string {
return Input.getInput('buildName') || Input.targetPlatform;
}
static get buildsPath(): string {
return Input.getInput('buildsPath') || 'build'; return Input.getInput('buildsPath') || 'build';
} }
static get unityLicensingServer() { static get unityLicensingServer(): string {
return Input.getInput('unityLicensingServer') || ''; return Input.getInput('unityLicensingServer') || '';
} }
static get buildMethod() { static get buildMethod(): string {
return Input.getInput('buildMethod') || ''; // Processed in docker file return Input.getInput('buildMethod') || ''; // Processed in docker file
} }
static get customParameters() { static get customParameters(): string {
return Input.getInput('customParameters') || ''; return Input.getInput('customParameters') || '';
} }
static get versioningStrategy() { static get versioningStrategy(): string {
return Input.getInput('versioning') || 'Semantic'; return Input.getInput('versioning') || 'Semantic';
} }
static get specifiedVersion() { static get specifiedVersion(): string {
return Input.getInput('version') || ''; return Input.getInput('version') || '';
} }
static get androidVersionCode() { static get androidVersionCode(): string {
return Input.getInput('androidVersionCode'); return Input.getInput('androidVersionCode') || '';
} }
static get androidAppBundle() { static get androidAppBundle(): boolean {
core.warning('androidAppBundle is deprecated, please use androidExportType instead');
const input = Input.getInput('androidAppBundle') || false; const input = Input.getInput('androidAppBundle') || false;
return input === 'true'; return input === 'true';
} }
static get androidKeystoreName() { static get androidExportType(): string {
// TODO: remove this in V3
const exportType = Input.getInput('androidExportType') || '';
if (exportType !== '') {
return exportType;
}
return Input.androidAppBundle ? 'androidAppBundle' : 'androidPackage';
// End TODO
// Use this in V3 when androidAppBundle is removed
// return Input.getInput('androidExportType') || 'androidPackage';
}
static get androidKeystoreName(): string {
return Input.getInput('androidKeystoreName') || ''; return Input.getInput('androidKeystoreName') || '';
} }
static get androidKeystoreBase64() { static get androidKeystoreBase64(): string {
return Input.getInput('androidKeystoreBase64') || ''; return Input.getInput('androidKeystoreBase64') || '';
} }
static get androidKeystorePass() { static get androidKeystorePass(): string {
return Input.getInput('androidKeystorePass') || ''; return Input.getInput('androidKeystorePass') || '';
} }
static get androidKeyaliasName() { static get androidKeyaliasName(): string {
return Input.getInput('androidKeyaliasName') || ''; return Input.getInput('androidKeyaliasName') || '';
} }
static get androidKeyaliasPass() { static get androidKeyaliasPass(): string {
return Input.getInput('androidKeyaliasPass') || ''; return Input.getInput('androidKeyaliasPass') || '';
} }
static get androidTargetSdkVersion() { static get androidTargetSdkVersion(): string {
return Input.getInput('androidTargetSdkVersion') || ''; return Input.getInput('androidTargetSdkVersion') || '';
} }
static get sshAgent() { static get androidSymbolType(): string {
return Input.getInput('androidSymbolType') || 'none';
}
static get sshAgent(): string {
return Input.getInput('sshAgent') || ''; return Input.getInput('sshAgent') || '';
} }
static get gitPrivateToken() { static get gitPrivateToken(): string | undefined {
return Input.getInput('gitPrivateToken') || false; return Input.getInput('gitPrivateToken');
} }
static get chownFilesTo() { static get chownFilesTo() {
return Input.getInput('chownFilesTo') || ''; return Input.getInput('chownFilesTo') || '';
} }
static get allowDirtyBuild() { static get allowDirtyBuild(): boolean {
const input = Input.getInput('allowDirtyBuild') || false; const input = Input.getInput('allowDirtyBuild') || false;
return input === 'true'; return input === 'true';
} }
static get cacheUnityInstallationOnMac(): boolean {
const input = Input.getInput('cacheUnityInstallationOnMac') || false;
return input === 'true';
}
static get unityHubVersionOnMac(): string {
const input = Input.getInput('unityHubVersionOnMac') || '';
return input !== '' ? input : '';
}
static get unitySerial(): string | undefined {
return Input.getInput('UNITY_SERIAL');
}
static get unityLicense(): string | undefined {
return Input.getInput('UNITY_LICENSE');
}
public static ToEnvVarFormat(input: string) { public static ToEnvVarFormat(input: string) {
if (input.toUpperCase() === input) { if (input.toUpperCase() === input) {
return input; return input;

View File

@ -1,11 +1,9 @@
import { exec } from '@actions/exec'; import { execWithErrorCheck } from './exec-with-error-check';
import { BuildParameters } from '.';
class MacBuilder { class MacBuilder {
public static async run(actionFolder, workspace, buildParameters: BuildParameters, silent = false) { public static async run(actionFolder: string, silent: boolean = false) {
await exec('bash', [`${actionFolder}/platforms/mac/entrypoint.sh`], { await execWithErrorCheck('bash', [`${actionFolder}/platforms/mac/entrypoint.sh`], {
silent, silent,
ignoreReturnCode: true,
}); });
} }
} }

View File

@ -1,12 +1,12 @@
const core = require('@actions/core'); import * as core from '@actions/core';
class Output { class Output {
static async setBuildVersion(buildVersion) { static async setBuildVersion(buildVersion: string) {
await core.setOutput('buildVersion', buildVersion); core.setOutput('buildVersion', buildVersion);
} }
static async setAndroidVersionCode(androidVersionCode) { static async setAndroidVersionCode(androidVersionCode: string) {
await core.setOutput('androidVersionCode', androidVersionCode); core.setOutput('androidVersionCode', androidVersionCode);
} }
} }

View File

@ -1,4 +1,4 @@
import fs from 'fs'; import fs from 'node:fs';
import * as core from '@actions/core'; import * as core from '@actions/core';
import { BuildParameters } from '.'; import { BuildParameters } from '.';
import { SetupMac, SetupWindows, SetupAndroid } from './platform-setup/'; import { SetupMac, SetupWindows, SetupAndroid } from './platform-setup/';

View File

@ -1,5 +1,5 @@
import fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
import { BuildParameters } from '..'; import { BuildParameters } from '..';
class SetupAndroid { class SetupAndroid {

View File

@ -1,54 +1,122 @@
import { BuildParameters } from '..'; import { BuildParameters } from '..';
import { getUnityChangeset } from 'unity-changeset'; import { getUnityChangeset } from 'unity-changeset';
import { exec } from '@actions/exec'; import { exec, getExecOutput } from '@actions/exec';
import fs from 'fs'; import { restoreCache, saveCache } from '@actions/cache';
import fs from 'node:fs';
class SetupMac { class SetupMac {
static unityHubPath = `"/Applications/Unity Hub.app/Contents/MacOS/Unity Hub"`; static unityHubBasePath = `/Applications/"Unity Hub.app"`;
static unityHubExecPath = `${SetupMac.unityHubBasePath}/Contents/MacOS/"Unity Hub"`;
public static async setup(buildParameters: BuildParameters, actionFolder: string) { public static async setup(buildParameters: BuildParameters, actionFolder: string) {
const unityEditorPath = `/Applications/Unity/Hub/Editor/${buildParameters.editorVersion}/Unity.app/Contents/MacOS/Unity`; const unityEditorPath = `/Applications/Unity/Hub/Editor/${buildParameters.editorVersion}/Unity.app/Contents/MacOS/Unity`;
// Only install unity if the editor doesn't already exist if (!fs.existsSync(this.unityHubExecPath)) {
await SetupMac.installUnityHub(buildParameters);
}
if (!fs.existsSync(unityEditorPath)) { if (!fs.existsSync(unityEditorPath)) {
await SetupMac.installUnityHub();
await SetupMac.installUnity(buildParameters); await SetupMac.installUnity(buildParameters);
} }
await SetupMac.setEnvironmentVariables(buildParameters, actionFolder); await SetupMac.setEnvironmentVariables(buildParameters, actionFolder);
} }
private static async installUnityHub(silent = false) { private static async installUnityHub(buildParameters: BuildParameters, silent = false) {
const command = 'brew install unity-hub'; // Can't use quotes in the cache package so we need a different path
if (!fs.existsSync(this.unityHubPath)) { const unityHubCachePath = `/Applications/Unity\\ Hub.app`;
const targetHubVersion =
buildParameters.unityHubVersionOnMac !== ''
? buildParameters.unityHubVersionOnMac
: await SetupMac.getLatestUnityHubVersion();
const restoreKey = `Cache-MacOS-UnityHub@${targetHubVersion}`;
if (buildParameters.cacheUnityInstallationOnMac) {
const cacheId = await restoreCache([unityHubCachePath], restoreKey);
if (cacheId) {
// Cache restored successfully, unity hub is installed now
return;
}
}
const commandSuffix = buildParameters.unityHubVersionOnMac !== '' ? `@${buildParameters.unityHubVersionOnMac}` : '';
const command = `brew install unity-hub${commandSuffix}`;
// Ignoring return code because the log seems to overflow the internal buffer which triggers // Ignoring return code because the log seems to overflow the internal buffer which triggers
// a false error // a false error
const errorCode = await exec(command, undefined, { silent, ignoreReturnCode: true }); const errorCode = await exec(command, undefined, { silent, ignoreReturnCode: true });
if (errorCode) { if (errorCode) {
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`); throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
} }
if (buildParameters.cacheUnityInstallationOnMac) {
await saveCache([unityHubCachePath], restoreKey);
} }
} }
/**
* Gets the latest version of Unity Hub available on brew
* @returns The latest version of Unity Hub available on brew
*/
private static async getLatestUnityHubVersion(): Promise<string> {
// Need to check if the latest version available is the same as the one we have cached
const hubVersionCommand = `/bin/bash -c "brew info unity-hub | grep -o '[0-9]\\+\\.[0-9]\\+\\.[0-9]\\+'"`;
const result = await getExecOutput(hubVersionCommand, undefined, { silent: true });
if (result.exitCode === 0 && result.stdout !== '') {
return result.stdout;
}
return '';
}
private static getModuleParametersForTargetPlatform(targetPlatform: string): string {
let moduleArgument = '';
switch (targetPlatform) {
case 'iOS':
moduleArgument += `--module ios `;
break;
case 'tvOS':
moduleArgument += '--module tvos ';
break;
case 'StandaloneOSX':
moduleArgument += `--module mac-il2cpp `;
break;
case 'Android':
moduleArgument += `--module android `;
break;
case 'WebGL':
moduleArgument += '--module webgl ';
break;
default:
throw new Error(`Unsupported module for target platform: ${targetPlatform}.`);
}
return moduleArgument;
}
private static async installUnity(buildParameters: BuildParameters, silent = false) { private static async installUnity(buildParameters: BuildParameters, silent = false) {
const unityChangeset = await getUnityChangeset(buildParameters.editorVersion); const unityEditorPath = `/Applications/Unity/Hub/Editor/${buildParameters.editorVersion}`;
let command = `${this.unityHubPath} -- --headless install \ const key = `Cache-MacOS-UnityEditor-With-Module-${buildParameters.targetPlatform}@${buildParameters.editorVersion}`;
--version ${buildParameters.editorVersion} \
--changeset ${unityChangeset.changeset} `;
switch (buildParameters.targetPlatform) { if (buildParameters.cacheUnityInstallationOnMac) {
case 'iOS': const cacheId = await restoreCache([unityEditorPath], key);
command += `--module ios `; if (cacheId) {
break; // Cache restored successfully, unity editor is installed now
case 'StandaloneOSX': return;
command += `--module mac-il2cpp `; }
break;
case 'android':
command += `--module android `;
break;
} }
command += `--childModules`; const unityChangeset = await getUnityChangeset(buildParameters.editorVersion);
const moduleArgument = SetupMac.getModuleParametersForTargetPlatform(buildParameters.targetPlatform);
const command = `${this.unityHubExecPath} -- --headless install \
--version ${buildParameters.editorVersion} \
--changeset ${unityChangeset.changeset} \
${moduleArgument} \
--childModules `;
// Ignoring return code because the log seems to overflow the internal buffer which triggers // Ignoring return code because the log seems to overflow the internal buffer which triggers
// a false error // a false error
@ -56,6 +124,10 @@ class SetupMac {
if (errorCode) { if (errorCode) {
throw new Error(`There was an error installing the Unity Editor. See logs above for details.`); throw new Error(`There was an error installing the Unity Editor. See logs above for details.`);
} }
if (buildParameters.cacheUnityInstallationOnMac) {
await saveCache([unityEditorPath], key);
}
} }
private static async setEnvironmentVariables(buildParameters: BuildParameters, actionFolder: string) { private static async setEnvironmentVariables(buildParameters: BuildParameters, actionFolder: string) {
@ -80,6 +152,8 @@ class SetupMac {
process.env.ANDROID_KEYALIAS_PASS = buildParameters.androidKeyaliasPass; process.env.ANDROID_KEYALIAS_PASS = buildParameters.androidKeyaliasPass;
process.env.ANDROID_TARGET_SDK_VERSION = buildParameters.androidTargetSdkVersion; process.env.ANDROID_TARGET_SDK_VERSION = buildParameters.androidTargetSdkVersion;
process.env.ANDROID_SDK_MANAGER_PARAMETERS = buildParameters.androidSdkManagerParameters; process.env.ANDROID_SDK_MANAGER_PARAMETERS = buildParameters.androidSdkManagerParameters;
process.env.ANDROID_EXPORT_TYPE = buildParameters.androidExportType;
process.env.ANDROID_SYMBOL_TYPE = buildParameters.androidSymbolType;
process.env.CUSTOM_PARAMETERS = buildParameters.customParameters; process.env.CUSTOM_PARAMETERS = buildParameters.customParameters;
process.env.CHOWN_FILES_TO = buildParameters.chownFilesTo; process.env.CHOWN_FILES_TO = buildParameters.chownFilesTo;
} }

View File

@ -1,5 +1,5 @@
import { exec } from '@actions/exec'; import { exec } from '@actions/exec';
import fs from 'fs'; import fs from 'node:fs';
import { BuildParameters } from '..'; import { BuildParameters } from '..';
class SetupWindows { class SetupWindows {
@ -9,7 +9,7 @@ class SetupWindows {
await SetupWindows.setupWindowsRun(targetPlatform); await SetupWindows.setupWindowsRun(targetPlatform);
} }
private static async setupWindowsRun(targetPlatform, silent = false) { private static async setupWindowsRun(targetPlatform: string, silent: boolean = false) {
if (!fs.existsSync('c:/regkeys')) { if (!fs.existsSync('c:/regkeys')) {
fs.mkdirSync('c:/regkeys'); fs.mkdirSync('c:/regkeys');
} }
@ -24,7 +24,7 @@ class SetupWindows {
} }
} }
private static async generateWinSDKRegKeys(silent = false) { private static async generateWinSDKRegKeys(silent: boolean = false) {
// Export registry keys that point to the Windows 10 SDK // Export registry keys that point to the Windows 10 SDK
const exportWinSDKRegKeysCommand = const exportWinSDKRegKeysCommand =
'reg export "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0" c:/regkeys/winsdk.reg /y'; 'reg export "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v10.0" c:/regkeys/winsdk.reg /y';

View File

@ -1,4 +1,4 @@
import fs from 'fs'; import fs from 'node:fs';
import { BuildParameters } from '..'; import { BuildParameters } from '..';
class ValidateWindows { class ValidateWindows {
@ -11,16 +11,10 @@ class ValidateWindows {
} }
} }
private static validateWindowsPlatformRequirements(platform) { private static validateWindowsPlatformRequirements(platform: string) {
switch (platform) { switch (platform) {
case 'StandaloneWindows': case 'StandaloneWindows':
this.checkForVisualStudio();
this.checkForWin10SDK();
break;
case 'StandaloneWindows64': case 'StandaloneWindows64':
this.checkForVisualStudio();
this.checkForWin10SDK();
break;
case 'WSAPlayer': case 'WSAPlayer':
this.checkForVisualStudio(); this.checkForVisualStudio();
this.checkForWin10SDK(); this.checkForWin10SDK();

View File

@ -30,7 +30,7 @@ class Platform {
}; };
} }
static isWindows(platform) { static isWindows(platform: string) {
switch (platform) { switch (platform) {
case Platform.types.StandaloneWindows: case Platform.types.StandaloneWindows:
case Platform.types.StandaloneWindows64: case Platform.types.StandaloneWindows64:
@ -40,7 +40,7 @@ class Platform {
} }
} }
static isAndroid(platform) { static isAndroid(platform: string) {
switch (platform) { switch (platform) {
case Platform.types.Android: case Platform.types.Android:
return true; return true;

View File

@ -0,0 +1,6 @@
export class StringKeyValuePair {
public name!: string;
public value!: string;
}
export type DockerParameters = { [key: string]: any };

View File

@ -1,21 +1,21 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import { exec } from '@actions/exec'; import { exec, ExecListeners } from '@actions/exec';
class System { class System {
static async run(command, arguments_: any = [], options = {}, shouldLog = true) { static async run(command: string, arguments_: string[] = [], options = {}, shouldLog = true) {
let result = ''; let result = '';
let error = ''; let error = '';
let debug = ''; let debug = '';
const listeners = { const listeners: ExecListeners = {
stdout: (dataBuffer) => { stdout: (dataBuffer: Buffer) => {
result += dataBuffer.toString(); result += dataBuffer.toString();
}, },
stderr: (dataBuffer) => { stderr: (dataBuffer: Buffer) => {
error += dataBuffer.toString(); error += dataBuffer.toString();
}, },
debug: (dataString) => { debug: (dataString: string) => {
debug += dataString.toString(); debug += dataString;
}, },
}; };
@ -33,7 +33,7 @@ class System {
} }
}; };
const throwContextualError = (message) => { const throwContextualError = (message: string) => {
let commandAsString = command; let commandAsString = command;
if (Array.isArray(arguments_)) { if (Array.isArray(arguments_)) {
commandAsString += ` ${arguments_.join(' ')}`; commandAsString += ` ${arguments_.join(' ')}`;

View File

@ -1,12 +1,12 @@
import * as fs from 'fs'; import fs from 'node:fs';
import path from 'path'; import path from 'node:path';
export default class UnityVersioning { export default class UnityVersioning {
static get versionPattern() { static get versionPattern() {
return /20\d{2}\.\d\.\w{3,4}|3/; return /20\d{2}\.\d\.\w{3,4}|3/;
} }
static determineUnityVersion(projectPath, unityVersion) { static determineUnityVersion(projectPath: string, unityVersion: string) {
if (unityVersion === 'auto') { if (unityVersion === 'auto') {
return UnityVersioning.read(projectPath); return UnityVersioning.read(projectPath);
} }
@ -14,7 +14,7 @@ export default class UnityVersioning {
return unityVersion; return unityVersion;
} }
static read(projectPath) { static read(projectPath: string) {
const filePath = path.join(projectPath, 'ProjectSettings', 'ProjectVersion.txt'); const filePath = path.join(projectPath, 'ProjectSettings', 'ProjectVersion.txt');
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
throw new Error(`Project settings file not found at "${filePath}". Have you correctly set the projectPath?`); throw new Error(`Project settings file not found at "${filePath}". Have you correctly set the projectPath?`);
@ -23,7 +23,7 @@ export default class UnityVersioning {
return UnityVersioning.parse(fs.readFileSync(filePath, 'utf8')); return UnityVersioning.parse(fs.readFileSync(filePath, 'utf8'));
} }
static parse(projectVersionTxt) { static parse(projectVersionTxt: string) {
const matches = projectVersionTxt.match(UnityVersioning.versionPattern); const matches = projectVersionTxt.match(UnityVersioning.versionPattern);
if (!matches || matches.length === 0) { if (!matches || matches.length === 0) {
throw new Error(`Failed to parse version from "${projectVersionTxt}".`); throw new Error(`Failed to parse version from "${projectVersionTxt}".`);

View File

@ -37,7 +37,7 @@ describe('Versioning', () => {
describe('grepCompatibleInputVersionRegex', () => { describe('grepCompatibleInputVersionRegex', () => {
// eslint-disable-next-line unicorn/consistent-function-scoping // eslint-disable-next-line unicorn/consistent-function-scoping
const matchInputUsingGrep = async (input) => { const matchInputUsingGrep = async (input: string) => {
const output = await System.run('sh', undefined, { const output = await System.run('sh', undefined, {
input: Buffer.from(`echo '${input}' | grep -E '${Versioning.grepCompatibleInputVersionRegex}'`), input: Buffer.from(`echo '${input}' | grep -E '${Versioning.grepCompatibleInputVersionRegex}'`),
silent: true, silent: true,
@ -68,7 +68,7 @@ describe('Versioning', () => {
const reference = jest.spyOn(Versioning, 'ref', 'get').mockReturnValue('refs/heads/feature-branch-2'); const reference = jest.spyOn(Versioning, 'ref', 'get').mockReturnValue('refs/heads/feature-branch-2');
expect(Versioning.branch).toStrictEqual('feature-branch-2'); expect(Versioning.branch).toStrictEqual('feature-branch-2');
expect(reference).toHaveBeenCalledTimes(2); expect(reference).toHaveBeenCalledTimes(1);
}); });
it('prefers headRef over ref when set', () => { it('prefers headRef over ref when set', () => {
@ -103,16 +103,6 @@ describe('Versioning', () => {
}); });
}); });
describe('isDirtyAllowed', () => {
it('does not throw', () => {
expect(() => Versioning.isDirtyAllowed).not.toThrow();
});
it('returns false by default', () => {
expect(Versioning.isDirtyAllowed).toStrictEqual(false);
});
});
describe('logging git diff', () => { describe('logging git diff', () => {
it('calls git diff', async () => { it('calls git diff', async () => {
// allowDirtyBuild: true // allowDirtyBuild: true
@ -140,28 +130,28 @@ describe('Versioning', () => {
describe('descriptionRegex1', () => { describe('descriptionRegex1', () => {
it('is a valid regex', () => { it('is a valid regex', () => {
expect(Versioning.descriptionRegex1).toBeInstanceOf(RegExp); expect(Versioning.descriptionRegexes[0]).toBeInstanceOf(RegExp);
}); });
test.each(['v1.1-1-g12345678', 'v0.1-2-g12345678', 'v0.0-500-gA9B6C3D0-dirty'])( test.each(['v1.1-1-g12345678', 'v0.1-2-g12345678', 'v0.0-500-gA9B6C3D0-dirty'])(
'is happy with valid %s', 'is happy with valid %s',
(description) => { (description) => {
expect(Versioning.descriptionRegex1.test(description)).toBeTruthy(); expect(Versioning.descriptionRegexes[0].test(description)).toBeTruthy();
}, },
); );
test.each(['1.1-1-g12345678', '0.1-2-g12345678', '0.0-500-gA9B6C3D0-dirty'])( test.each(['1.1-1-g12345678', '0.1-2-g12345678', '0.0-500-gA9B6C3D0-dirty'])(
'accepts valid semantic versions without v-prefix %s', 'accepts valid semantic versions without v-prefix %s',
(description) => { (description) => {
expect(Versioning.descriptionRegex1.test(description)).toBeTruthy(); expect(Versioning.descriptionRegexes[0].test(description)).toBeTruthy();
}, },
); );
test.each(['v0', 'v0.1', 'v0.1.2', 'v0.1-2', 'v0.1-2-g'])('does not like %s', (description) => { test.each(['v0', 'v0.1', 'v0.1.2', 'v0.1-2', 'v0.1-2-g'])('does not like %s', (description) => {
expect(Versioning.descriptionRegex1.test(description)).toBeFalsy(); expect(Versioning.descriptionRegexes[0].test(description)).toBeFalsy();
// Also, never expect without the v to work for any of these cases. // Also, never expect without the v to work for any of these cases.
expect(Versioning.descriptionRegex1.test(description?.slice(1))).toBeFalsy(); expect(Versioning.descriptionRegexes[0].test(description?.slice(1))).toBeFalsy();
}); });
}); });

View File

@ -5,14 +5,6 @@ import Input from './input';
import System from './system'; import System from './system';
export default class Versioning { export default class Versioning {
static get projectPath() {
return Input.projectPath;
}
static get isDirtyAllowed() {
return Input.allowDirtyBuild;
}
static get strategies() { static get strategies() {
return { None: 'None', Semantic: 'Semantic', Tag: 'Tag', Custom: 'Custom' }; return { None: 'None', Semantic: 'Semantic', Tag: 'Tag', Custom: 'Custom' };
} }
@ -25,8 +17,7 @@ export default class Versioning {
* Get the branch name of the (related) branch * Get the branch name of the (related) branch
*/ */
static get branch() { static get branch() {
// Todo - use optional chaining (https://github.com/zeit/ncc/issues/534) return this.headRef || this.ref?.slice(11);
return this.headRef || (this.ref && this.ref.slice(11));
} }
/** /**
@ -62,52 +53,46 @@ export default class Versioning {
*/ */
static async logDiff() { static async logDiff() {
const diffCommand = `git --no-pager diff | head -n ${this.maxDiffLines.toString()}`; const diffCommand = `git --no-pager diff | head -n ${this.maxDiffLines.toString()}`;
await System.run('sh', undefined, { await System.run(
'sh',
undefined,
{
input: Buffer.from(diffCommand), input: Buffer.from(diffCommand),
silent: true, silent: true,
}); },
false,
);
} }
/** /**
* Regex to parse version description into separate fields * Regex to parse version description into separate fields
*/ */
static get descriptionRegex1() { static get descriptionRegexes(): RegExp[] {
return /^v?([\d.]+)-(\d+)-g(\w+)-?(\w+)*/g; return [
/^v?([\d.]+)-(\d+)-g(\w+)-?(\w+)*/g,
/^v?([\d.]+-\w+)-(\d+)-g(\w+)-?(\w+)*/g,
/^v?([\d.]+-\w+\.\d+)-(\d+)-g(\w+)-?(\w+)*/g,
];
} }
static get descriptionRegex2() { static async determineBuildVersion(strategy: string, inputVersion: string): Promise<string> {
return /^v?([\d.]+-\w+)-(\d+)-g(\w+)-?(\w+)*/g;
}
static get descriptionRegex3() {
return /^v?([\d.]+-\w+\.\d+)-(\d+)-g(\w+)-?(\w+)*/g;
}
static async determineBuildVersion(strategy: string, inputVersion: string) {
// Validate input // Validate input
if (!Object.hasOwnProperty.call(this.strategies, strategy)) { if (!Object.hasOwnProperty.call(this.strategies, strategy)) {
throw new ValidationError(`Versioning strategy should be one of ${Object.values(this.strategies).join(', ')}.`); throw new ValidationError(`Versioning strategy should be one of ${Object.values(this.strategies).join(', ')}.`);
} }
let version;
switch (strategy) { switch (strategy) {
case this.strategies.None: case this.strategies.None:
version = 'none'; return 'none';
break;
case this.strategies.Custom: case this.strategies.Custom:
version = inputVersion; return inputVersion;
break;
case this.strategies.Semantic: case this.strategies.Semantic:
version = await this.generateSemanticVersion(); return await this.generateSemanticVersion();
break;
case this.strategies.Tag: case this.strategies.Tag:
version = await this.generateTagVersion(); return await this.generateTagVersion();
break;
default: default:
throw new NotImplementedException(`Strategy ${strategy} is not implemented.`); throw new NotImplementedException(`Strategy ${strategy} is not implemented.`);
} }
return version;
} }
/** /**
@ -127,7 +112,7 @@ export default class Versioning {
await this.logDiff(); await this.logDiff();
if ((await this.isDirty()) && !this.isDirtyAllowed) { if ((await this.isDirty()) && !Input.allowDirtyBuild) {
throw new Error('Branch is dirty. Refusing to base semantic version on uncommitted changes'); throw new Error('Branch is dirty. Refusing to base semantic version on uncommitted changes');
} }
@ -175,9 +160,9 @@ export default class Versioning {
*/ */
static async parseSemanticVersion() { static async parseSemanticVersion() {
const description = await this.getVersionDescription(); const description = await this.getVersionDescription();
for (const descriptionRegex of Versioning.descriptionRegexes) {
try { try {
const [match, tag, commits, hash] = this.descriptionRegex1.exec(description) as RegExpExecArray; const [match, tag, commits, hash] = descriptionRegex.exec(description) as RegExpExecArray;
return { return {
match, match,
@ -186,35 +171,14 @@ export default class Versioning {
hash, hash,
}; };
} catch { } catch {
try { continue;
const [match, tag, commits, hash] = this.descriptionRegex2.exec(description) as RegExpExecArray; }
}
return { core.warning(`Failed to parse git describe output or version can not be determined through: "${description}".`);
match,
tag,
commits,
hash,
};
} catch {
try {
const [match, tag, commits, hash] = this.descriptionRegex3.exec(description) as RegExpExecArray;
return {
match,
tag,
commits,
hash,
};
} catch {
core.warning(
`Failed to parse git describe output or version can not be determined through: "${description}".`,
);
return false; return false;
} }
}
}
}
/** /**
* Returns whether the repository is shallow. * Returns whether the repository is shallow.
@ -250,7 +214,7 @@ export default class Versioning {
* identifies the current commit. * identifies the current commit.
*/ */
static async getVersionDescription() { static async getVersionDescription() {
return this.git(['describe', '--long', '--tags', '--always', this.sha]); return this.git(['describe', '--long', '--tags', '--always', this.sha!]);
} }
/** /**
@ -283,7 +247,7 @@ export default class Versioning {
static async hasAnyVersionTags() { static async hasAnyVersionTags() {
const numberOfTagsAsString = await System.run('sh', undefined, { const numberOfTagsAsString = await System.run('sh', undefined, {
input: Buffer.from(`git tag --list --merged HEAD | grep -E '${this.grepCompatibleInputVersionRegex}' | wc -l`), input: Buffer.from(`git tag --list --merged HEAD | grep -E '${this.grepCompatibleInputVersionRegex}' | wc -l`),
cwd: this.projectPath, cwd: Input.projectPath,
silent: false, silent: false,
}); });
@ -298,7 +262,7 @@ export default class Versioning {
* Note: HEAD should not be used, as it may be detached, resulting in an additional count. * Note: HEAD should not be used, as it may be detached, resulting in an additional count.
*/ */
static async getTotalNumberOfCommits() { static async getTotalNumberOfCommits() {
const numberOfCommitsAsString = await this.git(['rev-list', '--count', this.sha]); const numberOfCommitsAsString = await this.git(['rev-list', '--count', this.sha!]);
return Number.parseInt(numberOfCommitsAsString, 10); return Number.parseInt(numberOfCommitsAsString, 10);
} }
@ -306,7 +270,7 @@ export default class Versioning {
/** /**
* Run git in the specified project path * Run git in the specified project path
*/ */
static async git(arguments_, options = {}) { static async git(arguments_: string[], options = {}) {
return System.run('git', arguments_, { cwd: this.projectPath, ...options }); return System.run('git', arguments_, { cwd: Input.projectPath, ...options }, false);
} }
} }

View File

@ -13,7 +13,7 @@ PlayerSettings:
useOnDemandResources: 0 useOnDemandResources: 0
accelerometerFrequency: 60 accelerometerFrequency: 60
companyName: DefaultCompany companyName: DefaultCompany
productName: simple-test-project productName: simpletestproject
defaultCursor: {fileID: 0} defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0} cursorHotspot: {x: 0, y: 0}
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
@ -165,6 +165,7 @@ PlayerSettings:
androidMaxAspectRatio: 2.1 androidMaxAspectRatio: 2.1
applicationIdentifier: applicationIdentifier:
Standalone: com.Company.ProductName Standalone: com.Company.ProductName
Android: com.DefaultCompany.simpletestproject
buildNumber: {} buildNumber: {}
AndroidBundleVersionCode: 1 AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 16 AndroidMinSdkVersion: 16

View File

@ -13,7 +13,7 @@ PlayerSettings:
useOnDemandResources: 0 useOnDemandResources: 0
accelerometerFrequency: 60 accelerometerFrequency: 60
companyName: DefaultCompany companyName: DefaultCompany
productName: simple-test-project productName: simpletestproject
defaultCursor: {fileID: 0} defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0} cursorHotspot: {x: 0, y: 0}
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
@ -154,11 +154,12 @@ PlayerSettings:
androidMaxAspectRatio: 2.1 androidMaxAspectRatio: 2.1
applicationIdentifier: applicationIdentifier:
Standalone: com.Company.ProductName Standalone: com.Company.ProductName
Android: com.DefaultCompany.simpletestproject
buildNumber: buildNumber:
Standalone: 0 Standalone: 0
iPhone: 0 iPhone: 0
tvOS: 0 tvOS: 0
overrideDefaultApplicationIdentifier: 1 overrideDefaultApplicationIdentifier: 0
AndroidBundleVersionCode: 1 AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 19 AndroidMinSdkVersion: 19
AndroidTargetSdkVersion: 0 AndroidTargetSdkVersion: 0

View File

@ -1,12 +1,12 @@
{ {
"compilerOptions": { "compilerOptions": {
"experimentalDecorators": true, "experimentalDecorators": true,
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, "target": "ES2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
"outDir": "./lib" /* Redirect output structure to the directory. */, "outDir": "./lib" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"strict": true /* Enable all strict type-checking options. */, "strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": false /* Re-enable after fixing compatibility */ /* Raise error on expressions and declarations with an implied 'any' type. */, "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
}, },
"exclude": ["node_modules", "dist"] "exclude": ["node_modules", "dist"]

1136
yarn.lock

File diff suppressed because it is too large Load Diff