Compare commits

...

54 Commits

Author SHA1 Message Date
Philipp Mildenberger
2b399b2641 Add gitPrivateToken support again (#377) 2022-04-05 17:46:52 +02:00
David Finol
40891d6b43 Fix mac builds (#376) 2022-04-04 10:19:40 +02:00
Webber Takken
441be81543 Switch to version 1 images (#374)
* feat: upgrade to images of version 1 (rolling tag)

* chore: indicate what needs to move out of the input class
2022-04-03 17:59:14 +02:00
David Finol
1bc7130fea Revert Husky (#372) 2022-04-01 20:20:36 +02:00
David Finol
419c5bb965 Test push block 2022-04-01 13:08:09 -05:00
Paul Pacheco
d98a0ed32d fix: windows build (#368) 2022-03-31 21:28:40 +02:00
David Finol
ca9d445c3c Revert windows and mac builds on PR (#367) 2022-03-31 05:31:57 -05:00
David Finol
89c1b38c3b Test windows and mac in PRs 2022-03-31 04:45:42 -05:00
Paul Pacheco
b72639aac0 perf: avoid building docker image (#365)
* avoid building a custom image

* fix: remove unnecessary double-dash

* Rebuild with -- fix

* linting

* Remove unused variable

* support windows as well

* Fix -- command not found

* Fix unused import, remove docker build test

* no dockerfile anymore

Co-authored-by: Webber Takken <webber.nl@gmail.com>
2022-03-31 01:16:30 +02:00
Webber Takken
9a40b8903e fix: ensure line endings (#366)
* fix: ensure line endings

* fix: only affect specific files

* chore: rearrange attributes order
2022-03-30 23:27:10 +02:00
Webber Takken
f1c154a23c Attempt to streamline dev lifecycle (git hooks) (#357)
* fix: misalignments in dev lifecycle

* fix: dist no longer added to staged

* fix: misalignments in dev lifecycle

* chore: multi-platform hooks and tests

* chore: multi-platform hooks and tests

* chore: add intention for colors

* chore: update lint-staged to fix color

* chore: update dist files

* feat: move to lefthook (remove husky and lint-staged)

* feat: move to lefthook (remove husky and lint-staged)

* fix: test aftereach

* fix: test aftereach

* fix: early restore call

* feat: jest fails if something gets logged to console

* chore: add todos of misplaced code

* chore: update dist files

* chore: move jest file
2022-03-28 01:23:32 +02:00
Paul Pacheco
9440c54d51 feat: work with rootless docker (#362)
Running docker currently mounts the docker.sock file into the container.
This was introduced in 2ab738c083 but
there is no explanation provided.

The docker.sock file is only needed if we want to run docker inside the container
to create other images or start other containers.
I searched through the code and I did not find any such use.

In particular, on fedora this gives permission denied because docker.sock
is owned by root and the container runs under an unprivileged user.
One has to change the permissions of docker.sock
(which is actually a link to /run/podman/podman.sock) to be writeable by the user.

If we don't need to use docker inside the containers,  then we can remove this file,
thus we can run this GitHub action as an unprivileged user out of the box.
2022-03-27 03:05:15 +02:00
dependabot[bot]
1ae498bcf1 Bump minimist from 1.2.5 to 1.2.6 (#361)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-26 01:14:00 +01:00
Paul Pacheco
8ed8ccb20c fix: op not permitted in self-hosted runner (#359)
In self hosted runners in fedora with SELinux enabled,
it sometimes gives a random error
```
Error: lsetxattr /var/run/docker.sock: operation not permitted

Error: The process '/usr/bin/docker' failed with exit code 126
```

This seems to happen with docker.sock which is a link to
/run/podman/podman.sock
looks like lsetxattr is broken for links.
2022-03-23 19:41:57 +01:00
Frostebite
efa2eddee9 Update cloud-runner-aws-pipeline.yml 2022-03-15 23:09:38 +00:00
Paul Pacheco
9358a3a890 feat: compatibility with self-hosted runners with SELinux (#355)
* feat: compatibility with self-hosted runners with SELinux

When using a self-hosted runner with SELinux (fedora)
volumes need to be mounted with ":z" in order to have write access

these flags are documented [here](https://docs.docker.com/storage/bind-mounts/#configure-the-selinux-label)

* Ensure folders are created

* use if instead of short circuit

* ts convention either inline or use braces

* Fix linting

* fix linting errors

Co-authored-by: Webber Takken <webber.nl@gmail.com>
2022-03-11 18:18:18 +01:00
Frostebite
d975f3b80f Minor tweaks and corrections for cloud runner pipeline and branch parameter (#351)
* Update cloud-runner-aws-pipeline.yml

* Update cloud-runner-k8s-pipeline.yml

* yarn build

* yarn build

* correct branch ref

* correct branch ref passed to target repo

* Create k8s-tests.yml

* Delete k8s-tests.yml

* correct branch ref passed to target repo

* correct branch ref passed to target repo
2022-03-04 19:42:24 +00:00
David Finol
693ff829de Yarn dependencies upgrade & yarn lint update (#347)
* Run yarn upgrade in order to resolve security vulnerability

* Remove unneeded git add from pre-commit hook

* Update packages

* Update non-eslint packages
2022-02-28 05:30:59 -06:00
David Finol
ff46e7645f Restore androidSdkManagerParameters (#349) 2022-02-27 14:31:47 +01:00
Webber Takken
eb42a8c9b8 Update entrypoint.sh (#348)
if there is both a unity package and a test-project in one github repo, then the token generation process is created Library folder and then the build of the test project breaks. Requires a tilde to ignore Library folder in _activate-license.
Or need set the path ACTIVATE_LICENSE_PATH from the global ENV in runtime-action

Co-authored-by: Maxim Vorobyev <dolphinikk@gmail.com>
2022-02-26 19:08:42 +01:00
David Finol
1abb902750 Fix license issue (#346) 2022-02-24 16:21:06 -06:00
David Finol
8e0583a14b Fix Android build parameters error (#335)
Tests failing due to issue with `gh`. Test confirmed here: https://github.com/finol-digital/Card-Game-Simulator/actions/runs/1879452353
2022-02-21 23:31:08 -06:00
David Finol
b94200d3d4 Sync docs2 (#341)
* Run build

* Sync docs
2022-02-21 13:19:28 -06:00
AndrewKahr
a6ebcb5b75 Fix minor typo in mac build test workflow (#333) 2022-02-02 12:38:35 +01:00
AndrewKahr
c7907c7e78 Initial Support for MacOS IL2CPP Builds (#326)
* Add intial framework for macos builds. Test install editor

* Fix unity hub path space

* Single quote space in path

* Escape space character

* More backslashes

* Move to bash scripts for setup

* Add path to command args

* Different command to run shell script

* Use full path to scripts

* Unpack changeset value and fix missing escape characters

* Print changeset

* More debug

* Remove debug

* Fix script paths

* Printenv debug

* Write environment variables to file to read in bash script

* Debug file write

* More debug

* Fix missing await

* Move back to process.env

* Fix path typo

* Add missing flags

* Make directory for license activation

* Add missing sudo

* Give permissions to license folder

* Fix path issues

* Add build tests

* Try ts setup again

* Try quoting path

* Further migrate mac scripts to align with linux scripts

* print pwd

* Fix changeset and remove unneeded env vars

* Ignore return code

* fix missing current directory

* Fix project path

* pwd

* Remove project path

* Revert to cwd being the workspace folder and pass action folder as an env variable.

* Add blank project to use for activation

* Add blank project path

* Fix build tests

* Don't rebuild library on windows

* Fix project path windows

* Fix platform specific workspace env variable

* Fix incorrect variable name

* Update .github/workflows/mac-build-tests.yml

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update .github/workflows/mac-build-tests.yml

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update dist/BlankProject/Packages/packages-lock.json

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/platform-setup/setup-mac.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/platform-setup/setup-mac.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Fix formatting

Co-authored-by: Webber Takken <webber.nl@gmail.com>
2022-02-02 10:15:37 +01:00
dependabot[bot]
9f13e1d9cf Bump shelljs from 0.8.4 to 0.8.5 (#331)
Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.4 to 0.8.5.
- [Release notes](https://github.com/shelljs/shelljs/releases)
- [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/shelljs/shelljs/compare/v0.8.4...v0.8.5)

---
updated-dependencies:
- dependency-name: shelljs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Webber Takken <webber@takken.io>
2022-02-01 09:56:09 +01:00
dependabot[bot]
ec0cdeacc9 Bump tar from 6.1.0 to 6.1.11 (#330)
Bumps [tar](https://github.com/npm/node-tar) from 6.1.0 to 6.1.11.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v6.1.0...v6.1.11)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-01 09:55:38 +01:00
Frostebite
03ae77dc7c Cloud Runner v2 (#310) 2022-02-01 02:31:20 +00:00
dependabot[bot]
4e38a84fe7 Bump node-fetch from 2.6.1 to 2.6.7 (#324)
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-25 23:54:22 +01:00
AndrewKahr
3d0eb0805b Initial Support for Windows Based Builds (#305)
* Implemented logic for windows based docker builds. Moved dockerfiles and scripts to platform specific folders.

* Add missing newline character

* Add build-tests for windows and a unity project configured to output il2cpp

* Add additional build targets (uwp and tvOS)
Adjustments to build scripts to not require win10 sdk when not needed (tvOS)
Platform-based prereq setup
Setup image tags for the new platforms with errors if building on the wrong base os
Rename test-project-il2cpp to test-project-windows to be used for all windows based project building (IL2CPP backend selected instead of mono)
Fix tests to be platform based

* Update dist/platforms/windows/steps/return_license.ps1

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/docker.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/docker.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/docker.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Fix outdated repository and homepage links in dockerfiles

* Fix comment style and rename validateWindowsPrereqs to validateWindowsPlatformRequirements

* Remove redundant comment

* Remove windows unity test project, add ProjectSettings for the il2cpp backend, and add logic to replace the projectsettings file with the il2cpp one on windows test builds.

* Fix action.test.ts to accept windows as a base platform

* Fix camelcase for wsaPlayer

* Switch from add to copy in windows dockerfile

* Change slash direction

* Switch ADD to COPY to conform with best practices, change ls to dir on windows dockerfile

* Improve error message for unset UNITY_EMAIL and UNITY_PASSWORD

* Further improve missing email and password error. Remove temppaths being mounted to docker image

* Add debug statement. TODO: Remove these

* Add more debug

* Explicitly pass in unity email to docker run

* Remove debug and fix environment variables for activation/deactivation scripts

* Prevent Unity serial from leaking to console

* Debug folder listings

* More debug print dirs

* fix debug print path

* fix reg export command

* Remove debug directory listings and try setSecret to mask serial

* Update src/model/action.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/docker.ts

Co-authored-by: Webber Takken <webber.nl@gmail.com>

* Update src/model/image-tag.ts

Co-authored-by: David Finol <davidmfinol@gmail.com>

* Update .github/workflows/build-tests.yml

Co-authored-by: David Finol <davidmfinol@gmail.com>

* Move platform validation and setup out of docker and into its own layer, remove branching on docker run command

* Fix test failure due to missing license

* Fix camelCase and duplicate variables

* Fix lint issues and make paths more understandable

* Fix typo in build-tests.yml

* Fix move command in build-tests.yml

* Different method to force move file

* Fix missing quote and backslash

* Pass unity email and password to builder action for windows build tests

* Push serial to windows test builds

* Make windows build tests only run on push to main

Co-authored-by: Webber Takken <webber.nl@gmail.com>
Co-authored-by: David Finol <davidmfinol@gmail.com>
2022-01-25 22:18:15 +01:00
ninetyninereds
7871734e90 added projectPath parameter to running of git (#323) 2022-01-24 17:09:26 +01:00
dependabot[bot]
018e347c3d Bump nanoid from 3.1.30 to 3.1.31 (#322)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.30 to 3.1.31.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.30...3.1.31)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 01:44:40 +01:00
dependabot[bot]
05e37305c1 Bump shelljs from 0.8.4 to 0.8.5 (#319)
Bumps [shelljs](https://github.com/shelljs/shelljs) from 0.8.4 to 0.8.5.
- [Release notes](https://github.com/shelljs/shelljs/releases)
- [Changelog](https://github.com/shelljs/shelljs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/shelljs/shelljs/compare/v0.8.4...v0.8.5)

---
updated-dependencies:
- dependency-name: shelljs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 01:43:37 +01:00
David Finol
15a02a4b1b Remove deprecated param from versioning (#315) 2022-01-02 19:02:45 -06:00
David Finol
c45cd78d0d Support version tags that don't start with v for semantic versioning (#303)
* Fixes #242

* Update semver version

* Update husky

* Update husky pre-commit hook

* Update dependencies

* Update dependencies

* Remove git add since changes will be automatically added

* Restore git add

* Update dependencies

* Update test
2022-01-02 15:31:48 -06:00
David Finol
a3e783f430 Fix docs link (#301) 2021-11-29 00:55:31 +01:00
David Finol
239273ca72 Add androidTargetSdkVersion as an option to update the Android SDK (#298)
* Add androidTargetSdkVersion as an option to update the Android SDK API level

* Fix build script

* Update default value

* Add JAVA_HOME

* Use Unity_path

* Update src/model/android-versioning.test.ts

Co-authored-by: Webber Takken <webber@takken.io>

* Correct JAVA_HOME

* Use unity_path

* Update JAVA_HOME to use path found from 2020.3

* Dynamically determine JAVA_HOME

* Update path determination

Co-authored-by: Webber Takken <webber@takken.io>
2021-11-24 06:51:52 -06:00
David Finol
11a0d0947e Improve androidVersionCode parsing and application (#297) 2021-11-15 11:12:37 -06:00
David Finol
13fdcad790 Add gitPrivateToken (#296)
* adding option to pass git credential

* trigger change

* trigger change

* build dist/index

* prettier

* adding set git credentials with more config

* correct docker.ts input

* change default of git credential

* try using git command line to set token

* remove git config cat

* adding api: to git config

* change to token

* change input name to reflect the type github private token

Co-authored-by: Alexander Brandstedt <alexander@infralium.com>
Co-authored-by: Alexander Brandstedt <mad01@users.noreply.github.com>
2021-11-14 16:52:35 -06:00
Michal Miškerník
e97ec82110 Use find instead of glob for changing file permissions (#293) 2021-10-22 01:03:21 +02:00
dependabot[bot]
8a836b81c5 Bump ansi-regex from 5.0.0 to 5.0.1 (#292)
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-25 22:41:11 +03:00
dependabot[bot]
1fa70bbbdf Bump tmpl from 1.0.4 to 1.0.5 (#291)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-25 22:38:43 +03:00
Estellise Yukihime
c317d144c3 fix strategy 'Tag' versioning (#287)
* fix - remove \n in getTag method

* build ts

* recommit
2021-09-06 18:31:24 +02:00
Webber Takken
3ebdb0e678 Run license activation in an empty directory (#285) 2021-08-31 01:18:34 +02:00
dependabot[bot]
7d9f968d70 Bump path-parse from 1.0.6 to 1.0.7 (#282)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-11 23:50:32 +02:00
Webber Takken
70081d231f Indicate how to support us (#277) 2021-07-12 19:28:11 +02:00
dependabot[bot]
36364461d5 Bump normalize-url from 4.5.0 to 4.5.1 (#275)
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-01 14:15:01 +02:00
David Finol
b66dffbf92 Projectpath error message (#274)
* Improve error message

* Improve error message
2021-07-01 06:38:44 -05:00
dependabot[bot]
2fc01a1db4 Bump ws from 6.2.1 to 6.2.2 (#269)
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Webber Takken <webber@takken.io>
2021-06-06 00:01:42 +02:00
Webber Takken
8c1a159dd0 add default tag for feature request (#272) 2021-06-05 23:59:56 +02:00
ivan-hernandez-scopely
497f2f7b5f Using SSH_AUTH_SOCK (ssh agent forwarding) to pull upm private repos (#256)
* using SSH_AUTH_SOCK (ssh agent forwarding) to pull upm private repos

* sshAgent as input parameter

* yarn run prettier --write "src/**/*.{js,ts}"

* yarn run lint --fix && yarn build

* fixed compilation after rebase

* removed RUN apt-get update && apt-get install -y openssh-client. This change needs to be done upstream. See game-ci/docker#117
2021-05-28 23:51:10 +02:00
dependabot[bot]
71ca7bdbfc Bump browserslist from 4.16.4 to 4.16.6 (#266)
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.16.4 to 4.16.6.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.16.4...4.16.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-26 12:19:42 +02:00
Frostebite
c96b8cf443 Remote builder refactoring (#264)
Remote builder refactoring
2021-05-23 05:08:40 +01:00
Webber Takken
9fff362775 Remove -nographics flag, ensure single -batchmode flag (#261)
* Remove -nographics flag, ensure -batchmode

* Remove explicit batch mode

* Add libnotify4 and bin for notify-send

* non-interactive frontend

* Move docker changes to base image (docker repo)
2021-05-22 21:07:54 +02:00
164 changed files with 301809 additions and 113088 deletions

View File

@@ -14,6 +14,7 @@
"rules": {
"prettier/prettier": "error",
"import/no-extraneous-dependencies": 0,
"import/no-namespace": "off"
"import/no-namespace": "off",
"no-undef": "off" // TODO: REMOVE THIS LINE WHEN UPDATING ESLINT RULES
}
}

9
.gitattributes vendored
View File

@@ -1,3 +1,6 @@
dist/index* -diff linguist-generated=true
dist/licenses* -diff linguist-generated=true
dist/sourcemap* -diff linguist-generated=true
[attr]generated-code-file text eol=lf -diff linguist-generated=true
[attr]generated-binary-file -text -diff linguist-generated=true
dist/index* generated-code-file
dist/licenses* generated-code-file
dist/sourcemap* generated-code-file

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: game-ci
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -2,7 +2,7 @@
name: Feature request
about: Suggest an improvement, or a new feature
title: ''
labels: ''
labels: enhancement
assignees: ''
---

View File

@@ -1,60 +0,0 @@
name: AWS
on:
push: { branches: [aws, aws-ts-clean] }
env:
AWS_REGION: "eu-west-1"
jobs:
buildForAllPlatforms:
name: AWS Fargate Build
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
# - 2019.2.11f1
- 2019.3.15f1
targetPlatform:
#- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
#- StandaloneWindows64 # Build a Windows 64-bit standalone.
- StandaloneLinux64 # Build a Linux 64-bit standalone.
#- iOS # Build an iOS player.
#- Android # Build an Android .apk.
#- WebGL # WebGL.
# - StandaloneWindows # Build a Windows standalone.
# - WSAPlayer # Build an Windows Store Apps player.
# - PS4 # Build a PS4 Standalone.
# - XboxOne # Build a Xbox One Standalone.
# - tvOS # Build to Apple's tvOS platform.
# - Switch # Build a Nintendo Switch player
# steps
steps:
- name: Checkout (default)
uses: actions/checkout@v2
if: github.event.event_type != 'pull_request_target'
with:
lfs: true
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-2
- uses: ./
id: aws-fargate-unity-build
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
with:
remoteBuildCluster: aws
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
githubToken: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -10,7 +10,7 @@ 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:
buildForAllPlatforms:
buildForAllPlatformsUbuntu:
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
runs-on: ubuntu-latest
strategy:
@@ -48,9 +48,9 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ matrix.projectPath }}/Library
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
key: Library-${{ matrix.projectPath }}-ubuntu-${{ matrix.targetPlatform }}
restore-keys: |
Library-${{ matrix.projectPath }}-
Library-${{ matrix.projectPath }}-ubuntu-
Library-
###########################
@@ -68,6 +68,6 @@ jobs:
###########################
- uses: actions/upload-artifact@v2
with:
name: Build (${{ matrix.unityVersion }})
name: Build Ubuntu (${{ matrix.unityVersion }})
path: build
retention-days: 14

View File

@@ -0,0 +1,111 @@
name: Cloud Runner - AWS Tests
on:
push: { branches: [main, cloud-runner-develop] }
env:
GKE_ZONE: 'us-central1'
GKE_REGION: 'us-central1'
GKE_PROJECT: 'unitykubernetesbuilder'
GKE_CLUSTER: 'unity-builder-cluster'
GCP_LOGGING: true
GCP_PROJECT: unitykubernetesbuilder
AWS_REGION: eu-west-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
AWS_BASE_STACK_NAME: game-ci-github-pipelines
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
CLOUD_RUNNER_TESTS: true
DEBUG: true
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
jobs:
buildForAllPlatforms:
name: AWS Fargate Build
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
projectPath:
- test-project
unityVersion:
# - 2019.2.11f1
- 2019.3.15f1
targetPlatform:
#- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
- StandaloneWindows64 # Build a Windows 64-bit standalone.
- StandaloneLinux64 # Build a Linux 64-bit standalone.
#- iOS # Build an iOS player.
#- Android # Build an Android .apk.
#- WebGL # WebGL.
# - StandaloneWindows # Build a Windows standalone.
# - WSAPlayer # Build an Windows Store Apps player.
# - PS4 # Build a PS4 Standalone.
# - XboxOne # Build a Xbox One Standalone.
# - tvOS # Build to Apple's tvOS platform.
# - Switch # Build a Nintendo Switch player
# steps
steps:
- name: Checkout (default)
uses: actions/checkout@v2
if: github.event.event_type != 'pull_request_target'
with:
lfs: true
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-2
- run: yarn
- run: yarn run cli --help
- run: yarn run test-i-aws
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
PROJECT_PATH: ${{ matrix.projectPath }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TARGET_PLATFORM: ${{ matrix.targetPlatform }}
- uses: ./
id: aws-fargate-unity-build
timeout-minutes: 25
with:
cloudRunnerCluster: aws
versioning: None
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
postBuildSteps: |
- name: upload
image: amazon/aws-cli
commands: |
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID --profile default
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY --profile default
aws configure set region $AWS_DEFAULT_REGION --profile default
aws s3 ls
aws s3 ls game-ci-test-storage
ls /data/cache/$CACHE_KEY
echo "/data/cache/$CACHE_KEY/build-$BUILD_GUID.zip s3://game-ci-test-storage/$CACHE_KEY/$BUILD_FILE"
aws s3 cp /data/cache/$CACHE_KEY/build-$BUILD_GUID.zip s3://game-ci-test-storage/$CACHE_KEY/build-$BUILD_GUID.zip
aws s3 cp /data/cache/$CACHE_KEY s3://game-ci-test-storage/$CACHE_KEY/$BUILD_GUID
secrets:
- name: awsAccessKeyId
value: ${{ secrets.AWS_ACCESS_KEY_ID }}
- name: awsSecretAccessKey
value: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: awsDefaultRegion
value: eu-west-2
- run: |
aws s3 cp s3://game-ci-test-storage/${{ steps.aws-fargate-unity-build.outputs.BRANCH }}/build-${{ steps.aws-fargate-unity-build.outputs.BUILD_GUID }}.zip build-${{ steps.aws-fargate-unity-build.outputs.BUILD_GUID }}.zip
ls
###########################
# Upload #
###########################
# download from cloud storage
- uses: actions/upload-artifact@v2
with:
name: AWS Build (${{ matrix.targetPlatform }})
path: build-${{ steps.aws-fargate-unity-build.outputs.BUILD_GUID }}.zip
retention-days: 14

View File

@@ -0,0 +1,125 @@
name: Cloud Runner - K8s Tests
on:
push: { branches: [cloud-runner-develop] }
# push: { branches: [main] }
# pull_request:
# paths-ignore:
# - '.github/**'
env:
GKE_ZONE: 'us-central1'
GKE_REGION: 'us-central1'
GKE_PROJECT: 'unitykubernetesbuilder'
GKE_CLUSTER: 'game-ci-github-pipelines'
GCP_LOGGING: true
GCP_PROJECT: unitykubernetesbuilder
GCP_LOG_FILE: ${{ github.workspace }}/cloud-runner-logs.txt
AWS_REGION: eu-west-2
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: eu-west-2
AWS_BASE_STACK_NAME: game-ci-github-pipelines
CLOUD_RUNNER_BRANCH: ${{ github.ref }}
CLOUD_RUNNER_TESTS: true
DEBUG: true
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
jobs:
k8sBuilds:
name: K8s (GKE Autopilot) build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
unityVersion:
# - 2019.2.11f1
- 2019.3.15f1
targetPlatform:
# - StandaloneWindows64
- StandaloneLinux64
steps:
###########################
# Checkout #
###########################
- uses: actions/checkout@v2
if: github.event.event_type != 'pull_request_target'
with:
lfs: true
###########################
# Setup #
###########################
- uses: google-github-actions/setup-gcloud@master
with:
version: '288.0.0'
service_account_email: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
service_account_key: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
- name: Get GKE cluster credentials
run: gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
###########################
# Cloud Runner Test Suite #
###########################
- uses: actions/setup-node@v2
with:
node-version: 12.x
- run: yarn
- run: yarn run cli --help
- name: Cloud Runner Test Suite
run: yarn run test-i-k8s --detectOpenHandles --forceExit
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
PROJECT_PATH: ${{ matrix.projectPath }}
TARGET_PLATFORM: ${{ matrix.targetPlatform }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
KUBE_CONFIG: ${{ steps.read-base64.outputs.base64 }}
unityVersion: ${{ matrix.unityVersion }}
###########################
# Cloud Runner Build Test #
###########################
- name: Cloud Runner Build Test
uses: ./
id: k8s-unity-build
timeout-minutes: 30
with:
cloudRunnerCluster: k8s
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
targetPlatform: ${{ matrix.targetPlatform }}
kubeConfig: ${{ steps.read-base64.outputs.base64 }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
projectPath: test-project
unityVersion: ${{ matrix.unityVersion }}
versioning: None
postBuildSteps: |
- name: upload
image: amazon/aws-cli
commands: |
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID --profile default
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY --profile default
aws configure set region $AWS_DEFAULT_REGION --profile default
aws s3 ls
aws s3 ls game-ci-test-storage
ls /data/cache/$BRANCH
echo "/data/cache/$BRANCH/build-$BUILD_GUID.zip s3://game-ci-test-storage/$BRANCH/$BUILD_FILE"
aws s3 cp /data/cache/$BRANCH/build-$BUILD_GUID.zip s3://game-ci-test-storage/$BRANCH/build-$BUILD_GUID.zip
secrets:
- name: awsAccessKeyId
value: ${{ secrets.AWS_ACCESS_KEY_ID }}
- name: awsSecretAccessKey
value: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: awsDefaultRegion
value: eu-west-2
- run: |
aws s3 cp s3://game-ci-test-storage/${{ steps.k8s-unity-build.outputs.BRANCH }}/build-${{ steps.k8s-unity-build.outputs.BUILD_GUID }}.zip build-${{ steps.k8s-unity-build.outputs.BUILD_GUID }}.zip
ls
###########################
# Upload #
###########################
# download from cloud storage
- uses: actions/upload-artifact@v2
with:
name: K8s Build (${{ matrix.targetPlatform }})
path: build-${{ steps.k8s-unity-build.outputs.BUILD_GUID }}.zip
retention-days: 14

View File

@@ -1,30 +1,27 @@
name: Kubernetes
name: Mac Builds
on:
workflow_dispatch: {}
# push: { branches: [main] }
# pull_request:
# paths-ignore:
# - '.github/**'
push:
branches:
- main
env:
GKE_ZONE: 'us-central1-c'
GKE_REGION: 'us-central1'
GKE_PROJECT: 'unitykubernetesbuilder'
GKE_CLUSTER: 'unity-builder-cluster'
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\" Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\n <Features>\n <Feature Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature Value=\"62\"/>\n </Features>\n <DeveloperData Value=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\" Type=\"EDITOR_FEATURE\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
jobs:
k8sBuilds:
name: K8s build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
runs-on: ubuntu-latest
continue-on-error: true
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:
- StandaloneLinux64
- StandaloneWindows64
- StandaloneOSX # Build a MacOS executable
steps:
###########################
# Checkout #
@@ -34,47 +31,44 @@ jobs:
lfs: true
###########################
# Spin up #
# Cache #
###########################
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
- uses: actions/cache@v2
with:
version: '288.0.0'
service_account_email: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
service_account_key: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
- run: ./dist/bootstrapper/ApplyClusterAndAcquireLock.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
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: frostebite/File-To-Base64@master
id: read-base64
with:
filePath: ~/.kube/config
- uses: ./
id: k8s-unity-build
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 }}
kubeConfig: ${{ steps.read-base64.outputs.base64 }}
githubToken: ${{ secrets.GITHUB_TOKEN }}
projectPath: test-project
unityVersion: 2019.3.15f1
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
# We use dirty build because we are replacing the default project settings file above
allowDirtyBuild: true
###########################
# Upload #
###########################
- uses: frostebite/K8s-Download-Volume@master
with:
kubeConfig: ${{ steps.read-base64.outputs.base64 }}
volume: ${{ steps.k8s-unity-build.outputs.volume }}
sourcePath: repo/build/
- uses: actions/upload-artifact@v2
with:
name: Kubernetes Build (${{ matrix.targetPlatform }})
path: k8s-volume-download
name: Build MacOS (${{ matrix.unityVersion }})
path: build
retention-days: 14
###########################
# Spin down #
###########################
- run: ./dist/bootstrapper/ReleaseLockAndAttemptShutdown.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
if: ${{ always() }}

View File

@@ -10,5 +10,3 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: Actions-R-Us/actions-tagger@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1,77 @@
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

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@
node_modules
coverage/
lib/
.vsconfig
yarn-error.log
.orig

32
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,32 @@
{
"god.tsconfig": "./tsconfig.json",
"yaml.customTags": [
"!And",
"!And sequence",
"!If",
"!If sequence",
"!Not",
"!Not sequence",
"!Equals",
"!Equals sequence",
"!Or",
"!Or sequence",
"!FindInMap",
"!FindInMap sequence",
"!Base64",
"!Join",
"!Join sequence",
"!Cidr",
"!Ref",
"!Sub",
"!Sub sequence",
"!GetAtt",
"!GetAZs",
"!ImportValue",
"!ImportValue sequence",
"!Select",
"!Select sequence",
"!Split",
"!Split sequence"
]
}

View File

@@ -41,6 +41,14 @@ To help improve the documentation, please find the docs [repository](https://git
To contribute to Unity Builder, kindly read the [contribution guide](./CONTRIBUTING.md).
## Support us
GameCI is free for everyone forever.
You can support us at [OpenCollective](https://opencollective.com/game-ci).
## Licence
[MIT](./LICENSE)
This repository is [MIT](./LICENSE) licensed.
This includes all contributions from the community.

View File

@@ -2,6 +2,10 @@ name: 'Unity - Builder'
author: Webber Takken <webber@takken.io>
description: 'Build Unity projects for different platforms.'
inputs:
targetPlatform:
required: true
default: ''
description: 'Platform that the build should target.'
unityVersion:
required: false
default: 'auto'
@@ -10,10 +14,6 @@ inputs:
required: false
default: ''
description: 'Specific docker image that should be used for building the project'
targetPlatform:
required: false
default: ''
description: 'Platform that the build should target.'
projectPath:
required: false
default: ''
@@ -30,38 +30,10 @@ inputs:
required: false
default: ''
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
remoteBuildCluster:
default: 'local'
customParameters:
required: false
description: 'Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must be configured.'
awsStackName:
default: 'game-ci'
required: false
description: 'The Cloud Formation stack name that must be setup before using this option.'
kubeConfig:
default: ''
required: false
description: 'Supply a base64 encoded kubernetes config to run builds on kubernetes and stream logs until completion.'
kubeVolume:
default: ''
required: false
description: 'Supply a Persistent Volume Claim name to use for the Unity build.'
remoteBuildMemory:
default: '800M'
required: false
description: 'Amount of memory to assign the remote build container'
remoteBuildCpu:
default: '0.25'
required: false
description: 'Amount of CPU time to assign the remote build container'
kubeVolumeSize:
default: '5Gi'
required: false
description: 'Amount of disc space to assign the Kubernetes Persistent Volume'
githubToken:
default: ''
required: false
description: 'GitHub token for cloning, only needed when kubeconfig is used.'
description: 'Custom parameters to configure the build.'
versioning:
required: false
default: 'Semantic'
@@ -98,14 +70,18 @@ inputs:
required: false
default: ''
description: 'The android keyaliasPass'
customParameters:
androidTargetSdkVersion:
required: false
default: ''
description: >
Custom parameters to configure the build.
Parameters must start with a hyphen (-) and may be followed by a value (without hyphen).
Parameters without a value will be considered booleans (with a value of true).
description: 'The android target API level.'
sshAgent:
required: false
default: ''
description: 'SSH Agent path to forward to the container'
gitPrivateToken:
required: false
default: ''
description: 'Github private token to pull from github'
chownFilesTo:
required: false
default: ''
@@ -113,12 +89,51 @@ inputs:
allowDirtyBuild:
required: false
default: ''
description: >
Allows the branch of the build to be dirty, and still generate the build.
Note that it is generally bad practice to modify your branch
in a CI Pipeline. However there are exceptions where this might
be needed. (use with care).
description: 'Allows the branch of the build to be dirty, and still generate the build.'
postBuildSteps:
required: false
default: ''
description: 'run a post build job in yaml format with the keys image, secrets (name, value object array), command string'
preBuildSteps:
required: false
default: ''
description: 'Run a pre build job after the repository setup but before the build job (in yaml format with the keys image, secrets (name, value object array), command line string)'
customJob:
required: false
default: ''
description: 'Run a custom job instead of the standard build automation for cloud runner (in yaml format with the keys image, secrets (name, value object array), command line string)'
awsBaseStackName:
default: 'game-ci'
required: false
description: 'The Cloud Formation stack name that must be setup before using this option.'
cloudRunnerCluster:
default: 'local'
required: false
description: 'Either local, k8s or aws can be used to run builds on a remote cluster. Additional parameters must be configured.'
cloudRunnerCpu:
default: '1.0'
required: false
description: 'Amount of CPU time to assign the remote build container'
cloudRunnerMemory:
default: '750M'
required: false
description: 'Amount of memory to assign the remote build container'
githubToken:
default: ''
required: false
description: 'GitHub token for cloning, only needed when kubeconfig is used.'
kubeConfig:
default: ''
required: false
description: 'Supply a base64 encoded kubernetes config to run builds on kubernetes and stream logs until completion.'
kubeVolume:
default: ''
required: false
description: 'Supply a Persistent Volume Claim name to use for the Unity build.'
kubeVolumeSize:
default: '5Gi'
required: false
description: 'Amount of disc space to assign the Kubernetes Persistent Volume'
outputs:
volume:
description: 'The Persistent Volume (PV) where the build artifacts have been stored by Kubernetes'

13
cloud-runner-logs Normal file
View File

@@ -0,0 +1,13 @@
Cloud Runner platform selected AWS
Cloud Runner is running in custom job mode
AWS Region: eu-west-2
Parsing build steps:
- name: 'step 1'
image: 'alpine'
commands: 'printenv'
secrets:
- name: 'testSecretName'
value: 'testSecretValue'
game-ci stack does not exist (["game-ci-github-automation-424-linux64-a9hz-cleanup","game-ci-github-automation-423-linux64-v34g-cleanup","game-ci-github-automation-423-linux64-v34g","game-ci-github-automation-422-linux64-7x6i-cleanup","game-ci-github-automation-422-linux64-7x6i","game-ci-github-automation-414-linux64-j21p-cleanup","game-ci-github-automation-414-linux64-j21p","game-ci-github-automation-413-linux64-tcih-cleanup","game-ci-github-automation-413-linux64-tcih","game-ci-github-automation-411-linux64-0s69-cleanup","game-ci-github-automation-411-linux64-0s69","game-ci-github-automation-410-linux64-1tli-cleanup","game-ci-github-automation-410-linux64-1tli","game-ci-github-automation-408-linux64-8pbw-cleanup","game-ci-github-automation-408-linux64-8pbw","game-ci-github-automation-407-linux64-21un-cleanup","game-ci-github-automation-407-linux64-21un","game-ci-github-automation-406-linux64-dizb-cleanup","game-ci-github-automation-406-linux64-dizb","game-ci-github-automation-405-linux64-9xj5-cleanup","game-ci-github-automation-405-linux64-9xj5","game-ci-github-automation-402-linux64-0bym-cleanup","game-ci-github-automation-402-linux64-0bym","game-ci-github-automation-400-linux64-arqv-cleanup","game-ci-github-automation-400-linux64-arqv","game-ci-github-automation-399-linux64-utkt-cleanup","game-ci-github-automation-399-linux64-utkt","game-ci-github-automation-397-linux64-xwfu-cleanup","game-ci-github-automation-397-linux64-xwfu","game-ci-github-automation-396-linux64-2g3q-cleanup","game-ci-github-automation-396-linux64-2g3q","game-ci-github-automation","game-ci-stack-integration-tests-390-linux64-mcdw-cleanup","game-ci-stack-integration-tests-390-linux64-mcdw","game-ci-stack-integration-tests-391-linux64-2arq-cleanup","game-ci-stack-integration-tests-391-linux64-2arq","game-ci-stack-integration-tests-390-linux64-awd0-cleanup","game-ci-stack-integration-tests-390-linux64-awd0","game-ci-stack-integration-tests"])
created stack (version: eedce7440581ab2e8a80cee59e34ed64)

49
dist/BlankProject/.gitignore vendored Normal file
View File

@@ -0,0 +1,49 @@
Library/
[Tt]emp/
[Oo]bj/
[Bb]uild/
[Bb]uilds/
[Ll]ogs/
# Uncomment this line if you wish to ignore the asset store tools plugin
# [Aa]ssets/AssetStoreTools*
# IDEs
.vs/
.idea/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties

8
dist/BlankProject/Assets/Scenes.meta vendored Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 131a6b21c8605f84396be9f6751fb6e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,208 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 3
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 0
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &519420028
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 519420032}
- component: {fileID: 519420031}
- component: {fileID: 519420029}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &519420029
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
m_Enabled: 1
--- !u!20 &519420031
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 2
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_FocalLength: 50
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 1
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 0
m_HDR: 1
m_AllowMSAA: 0
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 0
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &519420032
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 519420028}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2cda990e2423bbf4892e6590ba056729
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
dist/BlankProject/Packages/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,4 @@
{
"dependencies": {
}
}

View File

@@ -0,0 +1,4 @@
{
"dependencies": {
}
}

View File

@@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!11 &1
AudioManager:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Volume: 1
Rolloff Scale: 1
Doppler Factor: 1
Default Speaker Mode: 2
m_SampleRate: 0
m_DSPBufferSize: 1024
m_VirtualVoiceCount: 512
m_RealVoiceCount: 32
m_SpatializerPlugin:
m_AmbisonicDecoderPlugin:
m_DisableAudio: 0
m_VirtualizeEffects: 1
m_RequestedDSPBufferSize: 0

View File

@@ -0,0 +1,6 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!236 &1
ClusterInputManager:
m_ObjectHideFlags: 0
m_Inputs: []

View File

@@ -0,0 +1,37 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!55 &1
PhysicsManager:
m_ObjectHideFlags: 0
serializedVersion: 13
m_Gravity: {x: 0, y: -9.81, z: 0}
m_DefaultMaterial: {fileID: 0}
m_BounceThreshold: 2
m_DefaultMaxDepenetrationVelocity: 10
m_SleepThreshold: 0.005
m_DefaultContactOffset: 0.01
m_DefaultSolverIterations: 6
m_DefaultSolverVelocityIterations: 1
m_QueriesHitBackfaces: 0
m_QueriesHitTriggers: 1
m_EnableAdaptiveForce: 0
m_ClothInterCollisionDistance: 0.1
m_ClothInterCollisionStiffness: 0.2
m_ContactsGeneration: 1
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_AutoSimulation: 1
m_AutoSyncTransforms: 0
m_ReuseCollisionCallbacks: 1
m_ClothInterCollisionSettingsToggle: 0
m_ClothGravity: {x: 0, y: -9.81, z: 0}
m_ContactPairsMode: 0
m_BroadphaseType: 0
m_WorldBounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 250, y: 250, z: 250}
m_WorldSubdivisions: 8
m_FrictionType: 0
m_EnableEnhancedDeterminism: 0
m_EnableUnifiedHeightmaps: 1
m_SolverType: 0
m_DefaultMaxAngularSpeed: 50

View File

@@ -0,0 +1,11 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1045 &1
EditorBuildSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Scenes:
- enabled: 1
path: Assets/Scenes/SampleScene.unity
guid: 2cda990e2423bbf4892e6590ba056729
m_configObjects: {}

View File

@@ -0,0 +1,40 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!159 &1
EditorSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_SerializationMode: 2
m_LineEndingsForNewScripts: 0
m_DefaultBehaviorMode: 1
m_PrefabRegularEnvironment: {fileID: 0}
m_PrefabUIEnvironment: {fileID: 0}
m_SpritePackerMode: 4
m_SpritePackerPaddingPower: 1
m_EtcTextureCompressorBehavior: 1
m_EtcTextureFastCompressor: 1
m_EtcTextureNormalCompressor: 2
m_EtcTextureBestCompressor: 4
m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp
m_ProjectGenerationRootNamespace:
m_EnableTextureStreamingInEditMode: 1
m_EnableTextureStreamingInPlayMode: 1
m_AsyncShaderCompilation: 1
m_CachingShaderPreprocessor: 1
m_PrefabModeAllowAutoSave: 1
m_EnterPlayModeOptionsEnabled: 0
m_EnterPlayModeOptions: 3
m_GameObjectNamingDigits: 1
m_GameObjectNamingScheme: 0
m_AssetNamingUsesSpace: 1
m_UseLegacyProbeSampleCount: 0
m_SerializeInlineMappingsOnOneLine: 1
m_DisableCookiesInLightmapper: 1
m_AssetPipelineMode: 1
m_CacheServerMode: 0
m_CacheServerEndpoint:
m_CacheServerNamespacePrefix: default
m_CacheServerEnableDownload: 1
m_CacheServerEnableUpload: 1
m_CacheServerEnableAuth: 0
m_CacheServerEnableTls: 0

View File

@@ -0,0 +1,64 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!30 &1
GraphicsSettings:
m_ObjectHideFlags: 0
serializedVersion: 13
m_Deferred:
m_Mode: 1
m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0}
m_DeferredReflections:
m_Mode: 1
m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0}
m_ScreenSpaceShadows:
m_Mode: 1
m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0}
m_LegacyDeferred:
m_Mode: 1
m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0}
m_DepthNormals:
m_Mode: 1
m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0}
m_MotionVectors:
m_Mode: 1
m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0}
m_LightHalo:
m_Mode: 1
m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0}
m_LensFlare:
m_Mode: 1
m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0}
m_VideoShadersIncludeMode: 2
m_AlwaysIncludedShaders:
- {fileID: 7, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
- {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0}
m_PreloadedShaders: []
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
m_CustomRenderPipeline: {fileID: 0}
m_TransparencySortMode: 0
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
m_DefaultRenderingPath: 1
m_DefaultMobileRenderingPath: 1
m_TierSettings: []
m_LightmapStripping: 0
m_FogStripping: 0
m_InstancingStripping: 0
m_LightmapKeepPlain: 1
m_LightmapKeepDirCombined: 1
m_LightmapKeepDynamicPlain: 1
m_LightmapKeepDynamicDirCombined: 1
m_LightmapKeepShadowMask: 1
m_LightmapKeepSubtractive: 1
m_FogKeepLinear: 1
m_FogKeepExp: 1
m_FogKeepExp2: 1
m_AlbedoSwatchInfos: []
m_LightsUseLinearIntensity: 0
m_LightsUseColorTemperature: 0
m_DefaultRenderingLayerMask: 1
m_LogWhenShaderIsCompiled: 0

View File

@@ -0,0 +1,487 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!13 &1
InputManager:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Axes:
- serializedVersion: 3
m_Name: Horizontal
descriptiveName:
descriptiveNegativeName:
negativeButton: left
positiveButton: right
altNegativeButton: a
altPositiveButton: d
gravity: 3
dead: 0.001
sensitivity: 3
snap: 1
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Vertical
descriptiveName:
descriptiveNegativeName:
negativeButton: down
positiveButton: up
altNegativeButton: s
altPositiveButton: w
gravity: 3
dead: 0.001
sensitivity: 3
snap: 1
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Fire1
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left ctrl
altNegativeButton:
altPositiveButton: mouse 0
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Fire2
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left alt
altNegativeButton:
altPositiveButton: mouse 1
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Fire3
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left shift
altNegativeButton:
altPositiveButton: mouse 2
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Jump
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: space
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Mouse X
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton:
altNegativeButton:
altPositiveButton:
gravity: 0
dead: 0
sensitivity: 0.1
snap: 0
invert: 0
type: 1
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Mouse Y
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton:
altNegativeButton:
altPositiveButton:
gravity: 0
dead: 0
sensitivity: 0.1
snap: 0
invert: 0
type: 1
axis: 1
joyNum: 0
- serializedVersion: 3
m_Name: Mouse ScrollWheel
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton:
altNegativeButton:
altPositiveButton:
gravity: 0
dead: 0
sensitivity: 0.1
snap: 0
invert: 0
type: 1
axis: 2
joyNum: 0
- serializedVersion: 3
m_Name: Horizontal
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton:
altNegativeButton:
altPositiveButton:
gravity: 0
dead: 0.19
sensitivity: 1
snap: 0
invert: 0
type: 2
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Vertical
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton:
altNegativeButton:
altPositiveButton:
gravity: 0
dead: 0.19
sensitivity: 1
snap: 0
invert: 1
type: 2
axis: 1
joyNum: 0
- serializedVersion: 3
m_Name: Fire1
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: joystick button 0
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Fire2
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: joystick button 1
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Fire3
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: joystick button 2
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Jump
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: joystick button 3
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Submit
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: return
altNegativeButton:
altPositiveButton: joystick button 0
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Submit
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: enter
altNegativeButton:
altPositiveButton: space
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Cancel
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: escape
altNegativeButton:
altPositiveButton: joystick button 1
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Enable Debug Button 1
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left ctrl
altNegativeButton:
altPositiveButton: joystick button 8
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Enable Debug Button 2
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: backspace
altNegativeButton:
altPositiveButton: joystick button 9
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Reset
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left alt
altNegativeButton:
altPositiveButton: joystick button 1
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Next
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: page down
altNegativeButton:
altPositiveButton: joystick button 5
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Previous
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: page up
altNegativeButton:
altPositiveButton: joystick button 4
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Validate
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: return
altNegativeButton:
altPositiveButton: joystick button 0
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Persistent
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: right shift
altNegativeButton:
altPositiveButton: joystick button 2
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Multiplier
descriptiveName:
descriptiveNegativeName:
negativeButton:
positiveButton: left shift
altNegativeButton:
altPositiveButton: joystick button 3
gravity: 0
dead: 0
sensitivity: 0
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Horizontal
descriptiveName:
descriptiveNegativeName:
negativeButton: left
positiveButton: right
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Vertical
descriptiveName:
descriptiveNegativeName:
negativeButton: down
positiveButton: up
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 0
axis: 0
joyNum: 0
- serializedVersion: 3
m_Name: Debug Vertical
descriptiveName:
descriptiveNegativeName:
negativeButton: down
positiveButton: up
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 2
axis: 6
joyNum: 0
- serializedVersion: 3
m_Name: Debug Horizontal
descriptiveName:
descriptiveNegativeName:
negativeButton: left
positiveButton: right
altNegativeButton:
altPositiveButton:
gravity: 1000
dead: 0.001
sensitivity: 1000
snap: 0
invert: 0
type: 2
axis: 5
joyNum: 0

View File

@@ -0,0 +1,35 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!387306366 &1
MemorySettings:
m_ObjectHideFlags: 0
m_EditorMemorySettings:
m_MainAllocatorBlockSize: -1
m_ThreadAllocatorBlockSize: -1
m_MainGfxBlockSize: -1
m_ThreadGfxBlockSize: -1
m_CacheBlockSize: -1
m_TypetreeBlockSize: -1
m_ProfilerBlockSize: -1
m_ProfilerEditorBlockSize: -1
m_BucketAllocatorGranularity: -1
m_BucketAllocatorBucketsCount: -1
m_BucketAllocatorBlockSize: -1
m_BucketAllocatorBlockCount: -1
m_ProfilerBucketAllocatorGranularity: -1
m_ProfilerBucketAllocatorBucketsCount: -1
m_ProfilerBucketAllocatorBlockSize: -1
m_ProfilerBucketAllocatorBlockCount: -1
m_TempAllocatorSizeMain: -1
m_JobTempAllocatorBlockSize: -1
m_BackgroundJobTempAllocatorBlockSize: -1
m_JobTempAllocatorReducedBlockSize: -1
m_TempAllocatorSizeGIBakingWorker: -1
m_TempAllocatorSizeNavMeshWorker: -1
m_TempAllocatorSizeAudioWorker: -1
m_TempAllocatorSizeCloudWorker: -1
m_TempAllocatorSizeGfx: -1
m_TempAllocatorSizeJobWorker: -1
m_TempAllocatorSizeBackgroundWorker: -1
m_TempAllocatorSizePreloadManager: -1
m_PlatformMemorySettings: {}

View File

@@ -0,0 +1,93 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!126 &1
NavMeshProjectSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
areas:
- name: Walkable
cost: 1
- name: Not Walkable
cost: 1
- name: Jump
cost: 2
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
- name:
cost: 1
m_LastAgentTypeID: -887442657
m_Settings:
- serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.75
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_SettingNames:
- Humanoid

View File

@@ -0,0 +1,8 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!149 &1
NetworkManager:
m_ObjectHideFlags: 0
m_DebugLevel: 0
m_Sendrate: 15
m_AssetToPrefab: {}

View File

@@ -0,0 +1,44 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &1
MonoBehaviour:
m_ObjectHideFlags: 61
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_EnablePreReleasePackages: 0
m_EnablePackageDependencies: 0
m_AdvancedSettingsExpanded: 1
m_ScopedRegistriesSettingsExpanded: 1
m_SeeAllPackageVersions: 0
oneTimeWarningShown: 0
m_Registries:
- m_Id: main
m_Name:
m_Url: https://packages.unity.com
m_Scopes: []
m_IsDefault: 1
m_Capabilities: 7
m_UserSelectedRegistryName:
m_UserAddingNewScopedRegistry: 0
m_RegistryInfoDraft:
m_ErrorMessage:
m_Original:
m_Id:
m_Name:
m_Url:
m_Scopes: []
m_IsDefault: 0
m_Capabilities: 0
m_Modified: 0
m_Name:
m_Url:
m_Scopes:
-
m_SelectedScopeIndex: 0

View File

@@ -0,0 +1,56 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!19 &1
Physics2DSettings:
m_ObjectHideFlags: 0
serializedVersion: 5
m_Gravity: {x: 0, y: -9.81}
m_DefaultMaterial: {fileID: 0}
m_VelocityIterations: 8
m_PositionIterations: 3
m_VelocityThreshold: 1
m_MaxLinearCorrection: 0.2
m_MaxAngularCorrection: 8
m_MaxTranslationSpeed: 100
m_MaxRotationSpeed: 360
m_BaumgarteScale: 0.2
m_BaumgarteTimeOfImpactScale: 0.75
m_TimeToSleep: 0.5
m_LinearSleepTolerance: 0.01
m_AngularSleepTolerance: 2
m_DefaultContactOffset: 0.01
m_JobOptions:
serializedVersion: 2
useMultithreading: 0
useConsistencySorting: 0
m_InterpolationPosesPerJob: 100
m_NewContactsPerJob: 30
m_CollideContactsPerJob: 100
m_ClearFlagsPerJob: 200
m_ClearBodyForcesPerJob: 200
m_SyncDiscreteFixturesPerJob: 50
m_SyncContinuousFixturesPerJob: 50
m_FindNearestContactsPerJob: 100
m_UpdateTriggerContactsPerJob: 100
m_IslandSolverCostThreshold: 100
m_IslandSolverBodyCostScale: 1
m_IslandSolverContactCostScale: 10
m_IslandSolverJointCostScale: 10
m_IslandSolverBodiesPerJob: 50
m_IslandSolverContactsPerJob: 50
m_SimulationMode: 0
m_QueriesHitTriggers: 1
m_QueriesStartInColliders: 1
m_CallbacksOnDisable: 1
m_ReuseCollisionCallbacks: 1
m_AutoSyncTransforms: 0
m_AlwaysShowColliders: 0
m_ShowColliderSleep: 1
m_ShowColliderContacts: 0
m_ShowColliderAABB: 0
m_ContactArrowScale: 0.2
m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412}
m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432}
m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745}
m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804}
m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

View File

@@ -0,0 +1,7 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1386491679 &1
PresetManager:
m_ObjectHideFlags: 0
serializedVersion: 2
m_DefaultPresets: {}

View File

@@ -0,0 +1,665 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!129 &1
PlayerSettings:
m_ObjectHideFlags: 0
serializedVersion: 23
productGUID: 034a658b4a2c341fbb4fcd6299d7141d
AndroidProfiler: 0
AndroidFilterTouchesWhenObscured: 0
AndroidEnableSustainedPerformanceMode: 0
defaultScreenOrientation: 4
targetDevice: 2
useOnDemandResources: 0
accelerometerFrequency: 60
companyName: DefaultCompany
productName: BlankProject
defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0}
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
m_ShowUnitySplashScreen: 1
m_ShowUnitySplashLogo: 1
m_SplashScreenOverlayOpacity: 1
m_SplashScreenAnimation: 1
m_SplashScreenLogoStyle: 1
m_SplashScreenDrawMode: 0
m_SplashScreenBackgroundAnimationZoom: 1
m_SplashScreenLogoAnimationZoom: 1
m_SplashScreenBackgroundLandscapeAspect: 1
m_SplashScreenBackgroundPortraitAspect: 1
m_SplashScreenBackgroundLandscapeUvs:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
m_SplashScreenBackgroundPortraitUvs:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
m_SplashScreenLogos: []
m_VirtualRealitySplashScreen: {fileID: 0}
m_HolographicTrackingLossScreen: {fileID: 0}
defaultScreenWidth: 1920
defaultScreenHeight: 1080
defaultScreenWidthWeb: 960
defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0
m_ActiveColorSpace: 0
m_MTRendering: 1
mipStripping: 0
numberOfMipsStripped: 0
m_StackTraceTypes: 010000000100000001000000010000000100000001000000
iosShowActivityIndicatorOnLoading: -1
androidShowActivityIndicatorOnLoading: -1
iosUseCustomAppBackgroundBehavior: 0
iosAllowHTTPDownload: 1
allowedAutorotateToPortrait: 1
allowedAutorotateToPortraitUpsideDown: 1
allowedAutorotateToLandscapeRight: 1
allowedAutorotateToLandscapeLeft: 1
useOSAutorotation: 1
use32BitDisplayBuffer: 1
preserveFramebufferAlpha: 0
disableDepthAndStencilBuffers: 0
androidStartInFullscreen: 1
androidRenderOutsideSafeArea: 1
androidUseSwappy: 1
androidBlitType: 0
androidResizableWindow: 0
androidDefaultWindowWidth: 1920
androidDefaultWindowHeight: 1080
androidMinimumWindowWidth: 400
androidMinimumWindowHeight: 300
androidFullscreenMode: 1
defaultIsNativeResolution: 1
macRetinaSupport: 1
runInBackground: 0
captureSingleScreen: 0
muteOtherAudioSources: 0
Prepare IOS For Recording: 0
Force IOS Speakers When Recording: 0
deferSystemGesturesMode: 0
hideHomeButton: 0
submitAnalytics: 1
usePlayerLog: 1
bakeCollisionMeshes: 0
forceSingleInstance: 0
useFlipModelSwapchain: 1
resizableWindow: 0
useMacAppStoreValidation: 0
macAppStoreCategory: public.app-category.games
gpuSkinning: 0
xboxPIXTextureCapture: 0
xboxEnableAvatar: 0
xboxEnableKinect: 0
xboxEnableKinectAutoTracking: 0
xboxEnableFitness: 0
visibleInBackground: 1
allowFullscreenSwitch: 1
fullscreenMode: 1
xboxSpeechDB: 0
xboxEnableHeadOrientation: 0
xboxEnableGuest: 0
xboxEnablePIXSampling: 0
metalFramebufferOnly: 0
xboxOneResolution: 0
xboxOneSResolution: 0
xboxOneXResolution: 3
xboxOneMonoLoggingLevel: 0
xboxOneLoggingLevel: 1
xboxOneDisableEsram: 0
xboxOneEnableTypeOptimization: 0
xboxOnePresentImmediateThreshold: 0
switchQueueCommandMemory: 1048576
switchQueueControlMemory: 16384
switchQueueComputeMemory: 262144
switchNVNShaderPoolsGranularity: 33554432
switchNVNDefaultPoolsGranularity: 16777216
switchNVNOtherPoolsGranularity: 16777216
switchNVNMaxPublicTextureIDCount: 0
switchNVNMaxPublicSamplerIDCount: 0
stadiaPresentMode: 0
stadiaTargetFramerate: 0
vulkanNumSwapchainBuffers: 3
vulkanEnableSetSRGBWrite: 0
vulkanEnablePreTransform: 0
vulkanEnableLateAcquireNextImage: 0
vulkanEnableCommandBufferRecycling: 1
m_SupportedAspectRatios:
4:3: 1
5:4: 1
16:10: 1
16:9: 1
Others: 1
bundleVersion: 1.0
preloadedAssets: []
metroInputSource: 0
wsaTransparentSwapchain: 0
m_HolographicPauseOnTrackingLoss: 1
xboxOneDisableKinectGpuReservation: 1
xboxOneEnable7thCore: 1
vrSettings:
enable360StereoCapture: 0
isWsaHolographicRemotingEnabled: 0
enableFrameTimingStats: 0
useHDRDisplay: 0
D3DHDRBitDepth: 0
m_ColorGamuts: 00000000
targetPixelDensity: 30
resolutionScalingMode: 0
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier:
Standalone: com.DefaultCompany.2DProject
buildNumber:
Standalone: 0
iPhone: 0
tvOS: 0
overrideDefaultApplicationIdentifier: 1
AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 22
AndroidTargetSdkVersion: 0
AndroidPreferredInstallLocation: 1
aotOptions:
stripEngineCode: 1
iPhoneStrippingLevel: 0
iPhoneScriptCallOptimization: 0
ForceInternetPermission: 0
ForceSDCardPermission: 0
CreateWallpaper: 0
APKExpansionFiles: 0
keepLoadedShadersAlive: 0
StripUnusedMeshComponents: 0
VertexChannelCompressionMask: 4054
iPhoneSdkVersion: 988
iOSTargetOSVersionString: 11.0
tvOSSdkVersion: 0
tvOSRequireExtendedGameController: 0
tvOSTargetOSVersionString: 11.0
uIPrerenderedIcon: 0
uIRequiresPersistentWiFi: 0
uIRequiresFullScreen: 1
uIStatusBarHidden: 1
uIExitOnSuspend: 0
uIStatusBarStyle: 0
appleTVSplashScreen: {fileID: 0}
appleTVSplashScreen2x: {fileID: 0}
tvOSSmallIconLayers: []
tvOSSmallIconLayers2x: []
tvOSLargeIconLayers: []
tvOSLargeIconLayers2x: []
tvOSTopShelfImageLayers: []
tvOSTopShelfImageLayers2x: []
tvOSTopShelfImageWideLayers: []
tvOSTopShelfImageWideLayers2x: []
iOSLaunchScreenType: 0
iOSLaunchScreenPortrait: {fileID: 0}
iOSLaunchScreenLandscape: {fileID: 0}
iOSLaunchScreenBackgroundColor:
serializedVersion: 2
rgba: 0
iOSLaunchScreenFillPct: 100
iOSLaunchScreenSize: 100
iOSLaunchScreenCustomXibPath:
iOSLaunchScreeniPadType: 0
iOSLaunchScreeniPadImage: {fileID: 0}
iOSLaunchScreeniPadBackgroundColor:
serializedVersion: 2
rgba: 0
iOSLaunchScreeniPadFillPct: 100
iOSLaunchScreeniPadSize: 100
iOSLaunchScreeniPadCustomXibPath:
iOSLaunchScreenCustomStoryboardPath:
iOSLaunchScreeniPadCustomStoryboardPath:
iOSDeviceRequirements: []
iOSURLSchemes: []
macOSURLSchemes: []
iOSBackgroundModes: 0
iOSMetalForceHardShadows: 0
metalEditorSupport: 1
metalAPIValidation: 1
iOSRenderExtraFrameOnPause: 0
iosCopyPluginsCodeInsteadOfSymlink: 0
appleDeveloperTeamID:
iOSManualSigningProvisioningProfileID:
tvOSManualSigningProvisioningProfileID:
iOSManualSigningProvisioningProfileType: 0
tvOSManualSigningProvisioningProfileType: 0
appleEnableAutomaticSigning: 0
iOSRequireARKit: 0
iOSAutomaticallyDetectAndAddCapabilities: 1
appleEnableProMotion: 0
shaderPrecisionModel: 0
clonedFromGUID: 10ad67313f4034357812315f3c407484
templatePackageId: com.unity.template.2d@6.1.0
templateDefaultScene: Assets/Scenes/SampleScene.unity
useCustomMainManifest: 0
useCustomLauncherManifest: 0
useCustomMainGradleTemplate: 0
useCustomLauncherGradleManifest: 0
useCustomBaseGradleTemplate: 0
useCustomGradlePropertiesTemplate: 0
useCustomProguardFile: 0
AndroidTargetArchitectures: 1
AndroidTargetDevices: 0
AndroidSplashScreenScale: 0
androidSplashScreen: {fileID: 0}
AndroidKeystoreName:
AndroidKeyaliasName:
AndroidBuildApkPerCpuArchitecture: 0
AndroidTVCompatibility: 0
AndroidIsGame: 1
AndroidEnableTango: 0
androidEnableBanner: 1
androidUseLowAccuracyLocation: 0
androidUseCustomKeystore: 0
m_AndroidBanners:
- width: 320
height: 180
banner: {fileID: 0}
androidGamepadSupportLevel: 0
chromeosInputEmulation: 1
AndroidMinifyWithR8: 0
AndroidMinifyRelease: 0
AndroidMinifyDebug: 0
AndroidValidateAppBundleSize: 1
AndroidAppBundleSizeToValidate: 150
m_BuildTargetIcons: []
m_BuildTargetPlatformIcons: []
m_BuildTargetBatching: []
m_BuildTargetGraphicsJobs:
- m_BuildTarget: MacStandaloneSupport
m_GraphicsJobs: 0
- m_BuildTarget: Switch
m_GraphicsJobs: 0
- m_BuildTarget: MetroSupport
m_GraphicsJobs: 0
- m_BuildTarget: AppleTVSupport
m_GraphicsJobs: 0
- m_BuildTarget: BJMSupport
m_GraphicsJobs: 0
- m_BuildTarget: LinuxStandaloneSupport
m_GraphicsJobs: 0
- m_BuildTarget: PS4Player
m_GraphicsJobs: 0
- m_BuildTarget: iOSSupport
m_GraphicsJobs: 0
- m_BuildTarget: WindowsStandaloneSupport
m_GraphicsJobs: 0
- m_BuildTarget: XboxOnePlayer
m_GraphicsJobs: 0
- m_BuildTarget: LuminSupport
m_GraphicsJobs: 0
- m_BuildTarget: AndroidPlayer
m_GraphicsJobs: 0
- m_BuildTarget: WebGLSupport
m_GraphicsJobs: 0
m_BuildTargetGraphicsJobMode: []
m_BuildTargetGraphicsAPIs:
- m_BuildTarget: AndroidPlayer
m_APIs: 150000000b000000
m_Automatic: 1
- m_BuildTarget: iOSSupport
m_APIs: 10000000
m_Automatic: 1
m_BuildTargetVRSettings: []
openGLRequireES31: 0
openGLRequireES31AEP: 0
openGLRequireES32: 0
m_TemplateCustomTags: {}
mobileMTRendering:
Android: 1
iPhone: 1
tvOS: 1
m_BuildTargetGroupLightmapEncodingQuality: []
m_BuildTargetGroupLightmapSettings: []
m_BuildTargetNormalMapEncoding: []
m_BuildTargetDefaultTextureCompressionFormat:
- m_BuildTarget: Android
m_Format: 3
playModeTestRunnerEnabled: 0
runPlayModeTestAsEditModeTest: 0
actionOnDotNetUnhandledException: 1
enableInternalProfiler: 0
logObjCUncaughtExceptions: 1
enableCrashReportAPI: 0
cameraUsageDescription:
locationUsageDescription:
microphoneUsageDescription:
bluetoothUsageDescription:
switchNMETAOverride:
switchNetLibKey:
switchSocketMemoryPoolSize: 6144
switchSocketAllocatorPoolSize: 128
switchSocketConcurrencyLimit: 14
switchScreenResolutionBehavior: 2
switchUseCPUProfiler: 0
switchUseGOLDLinker: 0
switchLTOSetting: 0
switchApplicationID: 0x01004b9000490000
switchNSODependencies:
switchTitleNames_0:
switchTitleNames_1:
switchTitleNames_2:
switchTitleNames_3:
switchTitleNames_4:
switchTitleNames_5:
switchTitleNames_6:
switchTitleNames_7:
switchTitleNames_8:
switchTitleNames_9:
switchTitleNames_10:
switchTitleNames_11:
switchTitleNames_12:
switchTitleNames_13:
switchTitleNames_14:
switchTitleNames_15:
switchPublisherNames_0:
switchPublisherNames_1:
switchPublisherNames_2:
switchPublisherNames_3:
switchPublisherNames_4:
switchPublisherNames_5:
switchPublisherNames_6:
switchPublisherNames_7:
switchPublisherNames_8:
switchPublisherNames_9:
switchPublisherNames_10:
switchPublisherNames_11:
switchPublisherNames_12:
switchPublisherNames_13:
switchPublisherNames_14:
switchPublisherNames_15:
switchIcons_0: {fileID: 0}
switchIcons_1: {fileID: 0}
switchIcons_2: {fileID: 0}
switchIcons_3: {fileID: 0}
switchIcons_4: {fileID: 0}
switchIcons_5: {fileID: 0}
switchIcons_6: {fileID: 0}
switchIcons_7: {fileID: 0}
switchIcons_8: {fileID: 0}
switchIcons_9: {fileID: 0}
switchIcons_10: {fileID: 0}
switchIcons_11: {fileID: 0}
switchIcons_12: {fileID: 0}
switchIcons_13: {fileID: 0}
switchIcons_14: {fileID: 0}
switchIcons_15: {fileID: 0}
switchSmallIcons_0: {fileID: 0}
switchSmallIcons_1: {fileID: 0}
switchSmallIcons_2: {fileID: 0}
switchSmallIcons_3: {fileID: 0}
switchSmallIcons_4: {fileID: 0}
switchSmallIcons_5: {fileID: 0}
switchSmallIcons_6: {fileID: 0}
switchSmallIcons_7: {fileID: 0}
switchSmallIcons_8: {fileID: 0}
switchSmallIcons_9: {fileID: 0}
switchSmallIcons_10: {fileID: 0}
switchSmallIcons_11: {fileID: 0}
switchSmallIcons_12: {fileID: 0}
switchSmallIcons_13: {fileID: 0}
switchSmallIcons_14: {fileID: 0}
switchSmallIcons_15: {fileID: 0}
switchManualHTML:
switchAccessibleURLs:
switchLegalInformation:
switchMainThreadStackSize: 1048576
switchPresenceGroupId:
switchLogoHandling: 0
switchReleaseVersion: 0
switchDisplayVersion: 1.0.0
switchStartupUserAccount: 0
switchTouchScreenUsage: 0
switchSupportedLanguagesMask: 0
switchLogoType: 0
switchApplicationErrorCodeCategory:
switchUserAccountSaveDataSize: 0
switchUserAccountSaveDataJournalSize: 0
switchApplicationAttribute: 0
switchCardSpecSize: -1
switchCardSpecClock: -1
switchRatingsMask: 0
switchRatingsInt_0: 0
switchRatingsInt_1: 0
switchRatingsInt_2: 0
switchRatingsInt_3: 0
switchRatingsInt_4: 0
switchRatingsInt_5: 0
switchRatingsInt_6: 0
switchRatingsInt_7: 0
switchRatingsInt_8: 0
switchRatingsInt_9: 0
switchRatingsInt_10: 0
switchRatingsInt_11: 0
switchRatingsInt_12: 0
switchLocalCommunicationIds_0:
switchLocalCommunicationIds_1:
switchLocalCommunicationIds_2:
switchLocalCommunicationIds_3:
switchLocalCommunicationIds_4:
switchLocalCommunicationIds_5:
switchLocalCommunicationIds_6:
switchLocalCommunicationIds_7:
switchParentalControl: 0
switchAllowsScreenshot: 1
switchAllowsVideoCapturing: 1
switchAllowsRuntimeAddOnContentInstall: 0
switchDataLossConfirmation: 0
switchUserAccountLockEnabled: 0
switchSystemResourceMemory: 16777216
switchSupportedNpadStyles: 22
switchNativeFsCacheSize: 32
switchIsHoldTypeHorizontal: 0
switchSupportedNpadCount: 8
switchSocketConfigEnabled: 0
switchTcpInitialSendBufferSize: 32
switchTcpInitialReceiveBufferSize: 64
switchTcpAutoSendBufferSizeMax: 256
switchTcpAutoReceiveBufferSizeMax: 256
switchUdpSendBufferSize: 9
switchUdpReceiveBufferSize: 42
switchSocketBufferEfficiency: 4
switchSocketInitializeEnabled: 1
switchNetworkInterfaceManagerInitializeEnabled: 1
switchPlayerConnectionEnabled: 1
switchUseNewStyleFilepaths: 0
switchUseMicroSleepForYield: 1
switchEnableRamDiskSupport: 0
switchMicroSleepForYieldTime: 25
switchRamDiskSpaceSize: 12
ps4NPAgeRating: 12
ps4NPTitleSecret:
ps4NPTrophyPackPath:
ps4ParentalLevel: 11
ps4ContentID: ED1633-NPXX51362_00-0000000000000000
ps4Category: 0
ps4MasterVersion: 01.00
ps4AppVersion: 01.00
ps4AppType: 0
ps4ParamSfxPath:
ps4VideoOutPixelFormat: 0
ps4VideoOutInitialWidth: 1920
ps4VideoOutBaseModeInitialWidth: 1920
ps4VideoOutReprojectionRate: 60
ps4PronunciationXMLPath:
ps4PronunciationSIGPath:
ps4BackgroundImagePath:
ps4StartupImagePath:
ps4StartupImagesFolder:
ps4IconImagesFolder:
ps4SaveDataImagePath:
ps4SdkOverride:
ps4BGMPath:
ps4ShareFilePath:
ps4ShareOverlayImagePath:
ps4PrivacyGuardImagePath:
ps4ExtraSceSysFile:
ps4NPtitleDatPath:
ps4RemotePlayKeyAssignment: -1
ps4RemotePlayKeyMappingDir:
ps4PlayTogetherPlayerCount: 0
ps4EnterButtonAssignment: 2
ps4ApplicationParam1: 0
ps4ApplicationParam2: 0
ps4ApplicationParam3: 0
ps4ApplicationParam4: 0
ps4DownloadDataSize: 0
ps4GarlicHeapSize: 2048
ps4ProGarlicHeapSize: 2560
playerPrefsMaxSize: 32768
ps4Passcode: bi9UOuSpM2Tlh01vOzwvSikHFswuzleh
ps4pnSessions: 1
ps4pnPresence: 1
ps4pnFriends: 1
ps4pnGameCustomData: 1
playerPrefsSupport: 0
enableApplicationExit: 0
resetTempFolder: 1
restrictedAudioUsageRights: 0
ps4UseResolutionFallback: 0
ps4ReprojectionSupport: 0
ps4UseAudio3dBackend: 0
ps4UseLowGarlicFragmentationMode: 1
ps4SocialScreenEnabled: 0
ps4ScriptOptimizationLevel: 2
ps4Audio3dVirtualSpeakerCount: 14
ps4attribCpuUsage: 0
ps4PatchPkgPath:
ps4PatchLatestPkgPath:
ps4PatchChangeinfoPath:
ps4PatchDayOne: 0
ps4attribUserManagement: 0
ps4attribMoveSupport: 0
ps4attrib3DSupport: 0
ps4attribShareSupport: 0
ps4attribExclusiveVR: 0
ps4disableAutoHideSplash: 0
ps4videoRecordingFeaturesUsed: 0
ps4contentSearchFeaturesUsed: 0
ps4CompatibilityPS5: 0
ps4GPU800MHz: 1
ps4attribEyeToEyeDistanceSettingVR: 0
ps4IncludedModules: []
ps4attribVROutputEnabled: 0
monoEnv:
splashScreenBackgroundSourceLandscape: {fileID: 0}
splashScreenBackgroundSourcePortrait: {fileID: 0}
blurSplashScreenBackground: 1
spritePackerPolicy:
webGLMemorySize: 32
webGLExceptionSupport: 1
webGLNameFilesAsHashes: 0
webGLDataCaching: 1
webGLDebugSymbols: 0
webGLEmscriptenArgs:
webGLModulesDirectory:
webGLTemplate: APPLICATION:Default
webGLAnalyzeBuildSize: 0
webGLUseEmbeddedResources: 0
webGLCompressionFormat: 0
webGLWasmArithmeticExceptions: 0
webGLLinkerTarget: 1
webGLThreadsSupport: 0
webGLDecompressionFallback: 0
scriptingDefineSymbols: {}
additionalCompilerArguments: {}
platformArchitecture: {}
scriptingBackend: {}
il2cppCompilerConfiguration: {}
managedStrippingLevel: {}
incrementalIl2cppBuild: {}
suppressCommonWarnings: 1
allowUnsafeCode: 0
useDeterministicCompilation: 1
enableRoslynAnalyzers: 1
additionalIl2CppArgs:
scriptingRuntimeVersion: 1
gcIncremental: 1
assemblyVersionValidation: 1
gcWBarrierValidation: 0
apiCompatibilityLevelPerPlatform: {}
m_RenderingPath: 1
m_MobileRenderingPath: 1
metroPackageName: 2D_BuiltInRenderer
metroPackageVersion:
metroCertificatePath:
metroCertificatePassword:
metroCertificateSubject:
metroCertificateIssuer:
metroCertificateNotAfter: 0000000000000000
metroApplicationDescription: 2D_BuiltInRenderer
wsaImages: {}
metroTileShortName:
metroTileShowName: 0
metroMediumTileShowName: 0
metroLargeTileShowName: 0
metroWideTileShowName: 0
metroSupportStreamingInstall: 0
metroLastRequiredScene: 0
metroDefaultTileSize: 1
metroTileForegroundText: 2
metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0}
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1}
metroSplashScreenUseBackgroundColor: 0
platformCapabilities: {}
metroTargetDeviceFamilies: {}
metroFTAName:
metroFTAFileTypes: []
metroProtocolName:
XboxOneProductId:
XboxOneUpdateKey:
XboxOneSandboxId:
XboxOneContentId:
XboxOneTitleId:
XboxOneSCId:
XboxOneGameOsOverridePath:
XboxOnePackagingOverridePath:
XboxOneAppManifestOverridePath:
XboxOneVersion: 1.0.0.0
XboxOnePackageEncryption: 0
XboxOnePackageUpdateGranularity: 2
XboxOneDescription:
XboxOneLanguage:
- enus
XboxOneCapability: []
XboxOneGameRating: {}
XboxOneIsContentPackage: 0
XboxOneEnhancedXboxCompatibilityMode: 0
XboxOneEnableGPUVariability: 1
XboxOneSockets: {}
XboxOneSplashScreen: {fileID: 0}
XboxOneAllowedProductIds: []
XboxOnePersistentLocalStorageSize: 0
XboxOneXTitleMemory: 8
XboxOneOverrideIdentityName:
XboxOneOverrideIdentityPublisher:
vrEditorSettings: {}
cloudServicesEnabled: {}
luminIcon:
m_Name:
m_ModelFolderPath:
m_PortalFolderPath:
luminCert:
m_CertPath:
m_SignPackage: 1
luminIsChannelApp: 0
luminVersion:
m_VersionCode: 1
m_VersionName:
apiCompatibilityLevel: 6
activeInputHandler: 0
cloudProjectId:
framebufferDepthMemorylessMode: 0
qualitySettingsNames: []
projectName:
organizationId:
cloudEnabled: 0
legacyClampBlendShapeWeights: 0
playerDataPath:
forceSRGBBlit: 1
virtualTexturingSupportEnabled: 0

View File

@@ -0,0 +1,2 @@
m_EditorVersion: 2021.2.8f1
m_EditorVersionWithRevision: 2021.2.8f1 (d0e5f0a7b06a)

View File

@@ -0,0 +1,236 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!47 &1
QualitySettings:
m_ObjectHideFlags: 0
serializedVersion: 5
m_CurrentQuality: 5
m_QualitySettings:
- serializedVersion: 2
name: Very Low
pixelLightCount: 0
shadows: 0
shadowResolution: 0
shadowProjection: 1
shadowCascades: 1
shadowDistance: 15
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
skinWeights: 1
textureQuality: 1
anisotropicTextures: 0
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
vSyncCount: 0
lodBias: 0.3
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 4
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
- serializedVersion: 2
name: Low
pixelLightCount: 0
shadows: 0
shadowResolution: 0
shadowProjection: 1
shadowCascades: 1
shadowDistance: 20
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
skinWeights: 2
textureQuality: 0
anisotropicTextures: 0
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
vSyncCount: 0
lodBias: 0.4
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 16
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
- serializedVersion: 2
name: Medium
pixelLightCount: 1
shadows: 1
shadowResolution: 0
shadowProjection: 1
shadowCascades: 1
shadowDistance: 20
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 0
skinWeights: 2
textureQuality: 0
anisotropicTextures: 1
antiAliasing: 0
softParticles: 0
softVegetation: 0
realtimeReflectionProbes: 0
billboardsFaceCameraPosition: 0
vSyncCount: 1
lodBias: 0.7
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 64
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
- serializedVersion: 2
name: High
pixelLightCount: 2
shadows: 2
shadowResolution: 1
shadowProjection: 1
shadowCascades: 2
shadowDistance: 40
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
skinWeights: 2
textureQuality: 0
anisotropicTextures: 1
antiAliasing: 0
softParticles: 0
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
vSyncCount: 1
lodBias: 1
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 256
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
- serializedVersion: 2
name: Very High
pixelLightCount: 3
shadows: 2
shadowResolution: 2
shadowProjection: 1
shadowCascades: 2
shadowDistance: 70
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
skinWeights: 4
textureQuality: 0
anisotropicTextures: 2
antiAliasing: 2
softParticles: 1
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
vSyncCount: 1
lodBias: 1.5
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 1024
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
- serializedVersion: 2
name: Ultra
pixelLightCount: 4
shadows: 2
shadowResolution: 2
shadowProjection: 1
shadowCascades: 4
shadowDistance: 150
shadowNearPlaneOffset: 3
shadowCascade2Split: 0.33333334
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
shadowmaskMode: 1
skinWeights: 255
textureQuality: 0
anisotropicTextures: 2
antiAliasing: 2
softParticles: 1
softVegetation: 1
realtimeReflectionProbes: 1
billboardsFaceCameraPosition: 1
vSyncCount: 1
lodBias: 2
maximumLODLevel: 0
streamingMipmapsActive: 0
streamingMipmapsAddAllCameras: 1
streamingMipmapsMemoryBudget: 512
streamingMipmapsRenderersPerFrame: 512
streamingMipmapsMaxLevelReduction: 2
streamingMipmapsMaxFileIORequests: 1024
particleRaycastBudget: 4096
asyncUploadTimeSlice: 2
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
customRenderPipeline: {fileID: 0}
excludedTargetPlatforms: []
m_PerPlatformDefaultQuality:
Android: 2
Lumin: 5
Nintendo Switch: 5
PS4: 5
Stadia: 5
Standalone: 5
WebGL: 3
Windows Store Apps: 5
XboxOne: 5
iPhone: 2
tvOS: 2

View File

@@ -0,0 +1,43 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!78 &1
TagManager:
serializedVersion: 2
tags: []
layers:
- Default
- TransparentFX
- Ignore Raycast
-
- Water
- UI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
m_SortingLayers:
- name: Default
uniqueID: 0
locked: 0

View File

@@ -0,0 +1,9 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!5 &1
TimeManager:
m_ObjectHideFlags: 0
Fixed Timestep: 0.02
Maximum Allowed Timestep: 0.33333334
m_TimeScale: 1
Maximum Particle Timestep: 0.03

View File

@@ -0,0 +1,35 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!310 &1
UnityConnectSettings:
m_ObjectHideFlags: 0
serializedVersion: 1
m_Enabled: 0
m_TestMode: 0
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
m_ConfigUrl: https://config.uca.cloud.unity3d.com
m_DashboardUrl: https://dashboard.unity3d.com
m_TestInitMode: 0
CrashReportingSettings:
m_EventUrl: https://perf-events.cloud.unity3d.com
m_Enabled: 0
m_LogBufferSize: 10
m_CaptureEditorExceptions: 1
UnityPurchasingSettings:
m_Enabled: 0
m_TestMode: 0
UnityAnalyticsSettings:
m_Enabled: 0
m_TestMode: 0
m_InitializeOnStartup: 1
UnityAdsSettings:
m_Enabled: 0
m_InitializeOnStartup: 1
m_TestMode: 0
m_IosGameId:
m_AndroidGameId:
m_GameIds: {}
m_GameId:
PerformanceReportingSettings:
m_Enabled: 0

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!937362698 &1
VFXManager:
m_ObjectHideFlags: 0
m_IndirectShader: {fileID: 0}
m_CopyBufferShader: {fileID: 0}
m_SortShader: {fileID: 0}
m_StripUpdateShader: {fileID: 0}
m_RenderPipeSettingsPath:
m_FixedTimeStep: 0.016666668
m_MaxDeltaTime: 0.05
m_CompiledVersion: 0
m_RuntimeVersion: 0

View File

@@ -0,0 +1,8 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!890905787 &1
VersionControlSettings:
m_ObjectHideFlags: 0
m_Mode: Visible Meta Files
m_CollabEditorSettings:
inProgressEnabled: 1

View File

@@ -0,0 +1,10 @@
{
"m_SettingKeys": [
"VR Device Disabled",
"VR Device User Alert"
],
"m_SettingValues": [
"False",
"False"
]
}

View File

20
dist/Dockerfile vendored
View File

@@ -1,20 +0,0 @@
ARG IMAGE
FROM $IMAGE
LABEL "com.github.actions.name"="Unity - Builder"
LABEL "com.github.actions.description"="Build Unity projects for different platforms."
LABEL "com.github.actions.icon"="box"
LABEL "com.github.actions.color"="gray-dark"
LABEL "repository"="http://github.com/webbertakken/unity-actions"
LABEL "homepage"="http://github.com/webbertakken/unity-actions"
LABEL "maintainer"="Webber Takken <webber@takken.io>"
ADD default-build-script /UnityBuilderAction
ADD steps /steps
RUN chmod -R +x /steps
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
RUN ls
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -1,69 +0,0 @@
#!/bin/sh
# This creates a GKE Cluster
# - Will wait for any deletion to complete on a cluster with the same name before creating
# - Will wait for completion before continuing
# - If the script is run concurrently multiple times, only one cluster will be created, all instances will wait for availability
# Requires GCP Cloud SDK
# Installs retry https://github.com/kadwanev/retry
GKE_PROJECT=$1
GKE_CLUSTER=$2
GKE_ZONE=$3
# may update this to avoid repeated install, drop me a comment if needed
sudo sh -c "curl https://raw.githubusercontent.com/kadwanev/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry"
attempts=0
while [ $attempts -le 1 ]
do
retry -s 15 -t 20 -v '
STATUS=$(gcloud container clusters list --format="json" --project $GKE_PROJECT |
jq "
.[] |
{name: .name, status: .status} |
select(.name == \"$GKE_CLUSTER\")
" |
jq ".status")
if [ "$STATUS" == "\"STOPPING\"" ]; then echo "Cluster stopping waiting for completion" && exit 1; fi
exit 0
'
cluster=$(gcloud container clusters list --project $GKE_PROJECT --format="json" | jq '.[] | select(.name == "${GKE_CLUSTER}")')
if [ -z "$cluster" ];
then
echo "No clusters found for \"$GKE_CLUSTER\" in project \"$GKE_CLUSTER\" in zone \"$GKE_ZONE\""
# you may not need this, it installs GCP beta for additional command line options
gcloud components install beta -q
# replace this line with whatever type of cluster you want to create
gcloud beta container --project $GKE_PROJECT clusters create $GKE_CLUSTER --zone $GKE_ZONE --no-enable-basic-auth --cluster-version "1.15.12-gke.2" --machine-type "custom-1-3072" --image-type "COS" --disk-type "pd-standard" --disk-size "15" --metadata disable-legacy-endpoints=true --scopes "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append" --num-nodes "1" --enable-stackdriver-kubernetes --enable-ip-alias --default-max-pods-per-node "110" --enable-autoscaling --min-nodes "0" --max-nodes "3" --no-enable-master-authorized-networks --addons HorizontalPodAutoscaling,HttpLoadBalancing --enable-autoupgrade --enable-autorepair --max-surge-upgrade 1 --max-unavailable-upgrade 0
fi;
retry -s 15 -t 20 -v '
STATUS=$(gcloud container clusters list --format="json" --project $GKE_PROJECT |
jq "
.[] |
{name: .name, status: .status} |
select(.name == \"$GKE_CLUSTER\")
" |
jq ".status")
if [ "$STATUS" == "\"PROVISIONING\"" ]; then echo "Cluster provisioning waiting for available" && exit 1; fi
exit 0
'
echo "Cluster is available"
gcloud container clusters get-credentials $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT
kubectl version
NSID=$(cat /proc/sys/kernel/random/uuid)
echo "::set-env name=NSID::"$NSID
{
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: ns-unity-builder-$NSID
labels:
app: unity-builder
EOF
} && exit 0
attempts=$(($attempts+1))
done

View File

@@ -1,13 +0,0 @@
kubectl delete ns ns-unity-builder-$NSID
# do any unity-builder namespaces remain?
namespaceCount=$(kubectl get ns --output json | jq ".items | .[] | select(.metadata.labels.app == \"unity-builder\") | select(.status.phase != \"TERMINATING\")" | jq -s "length")
echo $namespaceCount
if [ "$namespaceCount" != "0" ]
then
echo "let next cluster delete"
exit 0
else
echo "delete cluster"
retry -s 15 -t 5 -v 'gcloud container clusters delete $GKE_CLUSTER --zone $GKE_ZONE --project $GKE_PROJECT --quiet'
fi

View File

@@ -7,6 +7,9 @@ Parameters:
Type: String
Default: development
Description: "Your deployment environment: DEV, QA , PROD"
Version:
Type: String
Description: "hash of template"
# ContainerPort:
# Type: Number
@@ -231,10 +234,6 @@ Resources:
Statement:
- Effect: Allow
Action:
# Allow upload to S3
- 's3:GetObject'
- 's3:GetObjectVersion'
- 's3:PutObject'
# Allow the use of secret manager
- 'secretsmanager:GetSecretValue'
@@ -250,7 +249,7 @@ Resources:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
DeleteCFNLambdaExecutionRole:
Type: "AWS::IAM::Role"
Properties:
@@ -348,12 +347,6 @@ Resources:
SecurityGroups:
- !Ref EFSServerSecurityGroup
S3Bucket:
Type: 'AWS::S3::Bucket'
DeletionPolicy: Retain
Properties:
BucketName: game-ci-storage
@@ -388,7 +381,7 @@ Outputs:
Value: !GetAtt 'ECSTaskExecutionRole.Arn'
Export:
Name: !Sub ${EnvironmentName}:ECSTaskExecutionRole
DeleteCFNLambdaExecutionRole:
Description: Lambda execution role for cleaning up cloud formations
Value: !GetAtt 'DeleteCFNLambdaExecutionRole.Arn'

View File

@@ -18,7 +18,7 @@ Parameters:
Type: String
Default: development
Description: 'Your deployment environment: DEV, QA , PROD'
BUILDID:
BUILDGUID:
Type: String
Default: ''
StackName:
@@ -34,16 +34,16 @@ Resources:
DeleteCFNLambda:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: !Join [ "", [ 'DeleteCFNLambda', !Ref BUILDID ] ]
FunctionName: !Join [ "", [ 'DeleteCFNLambda', !Ref BUILDGUID ] ]
Code:
ZipFile: |
import boto3
import os
import json
stack_name = os.environ['stackName']
delete_stack_name = os.environ['deleteStackName']
def delete_cfn(stack_name):
try:
cfn = boto3.resource('cloudformation')
@@ -51,8 +51,8 @@ Resources:
stack.delete()
return "SUCCESS"
except:
return "ERROR"
return "ERROR"
def handler(event, context):
print("Received event:")
print(json.dumps(event))
@@ -66,7 +66,7 @@ Resources:
Handler: "index.handler"
Runtime: "python3.6"
Timeout: "5"
Role:
Role:
'Fn::ImportValue': !Sub '${EnvironmentName}:DeleteCFNLambdaExecutionRole'
DeleteStackEventRule:
DependsOn:
@@ -74,27 +74,27 @@ Resources:
- GenerateCronExpression
Type: "AWS::Events::Rule"
Properties:
Name: !Join [ "", [ 'DeleteStackEventRule', !Ref BUILDID ] ]
Name: !Join [ "", [ 'DeleteStackEventRule', !Ref BUILDGUID ] ]
Description: Delete stack event
ScheduleExpression: !GetAtt GenerateCronExpression.cron_exp
State: "ENABLED"
Targets:
-
Targets:
-
Arn: !GetAtt DeleteCFNLambda.Arn
Id: 'DeleteCFNLambda'
PermissionForDeleteCFNLambda:
Id: 'DeleteCFNLambda'
PermissionForDeleteCFNLambda:
Type: "AWS::Lambda::Permission"
DependsOn:
- DeleteStackEventRule
Properties:
FunctionName: !Join [ "", [ 'DeleteCFNLambda', !Ref BUILDID ] ]
Properties:
FunctionName: !Join [ "", [ 'DeleteCFNLambda', !Ref BUILDGUID ] ]
Action: "lambda:InvokeFunction"
Principal: "events.amazonaws.com"
SourceArn: !GetAtt DeleteStackEventRule.Arn
GenerateCronExpLambda:
Type: "AWS::Lambda::Function"
Properties:
FunctionName: !Join [ "", [ 'GenerateCronExpressionLambda', !Ref BUILDID ] ]
FunctionName: !Join [ "", [ 'GenerateCronExpressionLambda', !Ref BUILDGUID ] ]
Code:
ZipFile: |
from datetime import datetime, timedelta
@@ -102,7 +102,7 @@ Resources:
import logging
import json
import cfnresponse
def deletion_time(ttl):
delete_at_time = datetime.now() + timedelta(minutes=int(ttl))
hh = delete_at_time.hour
@@ -113,7 +113,7 @@ Resources:
# minutes hours day month day-of-week year
cron_exp = "cron({} {} {} {} ? {})".format(mm, hh, dd, month, yyyy)
return cron_exp
def handler(event, context):
print('Received event: %s' % json.dumps(event))
status = cfnresponse.SUCCESS
@@ -132,12 +132,12 @@ Resources:
Handler: "index.handler"
Runtime: "python3.6"
Timeout: "5"
Role:
Role:
'Fn::ImportValue': !Sub '${EnvironmentName}:DeleteCFNLambdaExecutionRole'
GenerateCronExpression:
Type: "Custom::GenerateCronExpression"
Version: "1.0"
Properties:
Name: !Join [ "", [ 'GenerateCronExpression', !Ref BUILDID ] ]
Name: !Join [ "", [ 'GenerateCronExpression', !Ref BUILDGUID ] ]
ServiceToken: !GetAtt GenerateCronExpLambda.Arn
ttl: !Ref 'TTL'

View File

@@ -30,7 +30,7 @@ Parameters:
Type: Number
Default: 2048
Description: How much memory in megabytes to give the container
BUILDID:
BUILDGUID:
Type: String
Default: ''
Command:
@@ -47,40 +47,11 @@ Parameters:
Default: ''
Description: >-
(Optional) An IAM role to give the service's containers if the code within
needs to access other AWS resources like S3 buckets, DynamoDB tables, etc
needs to access other AWS resources
EFSMountDirectory:
Type: String
Default: '/efsdata'
GithubToken:
Type: String
Default: '0'
UnityLicense:
Type: String
Default: '0'
UnityEmail:
Type: String
Default: '0'
UnityPassword:
Type: String
Default: '0'
UnitySerial:
Type: String
Default: '0'
AndroidKeystoreBase64:
Type: String
Default: '0'
AndroidKeystorePass:
Type: String
Default: '0'
AndroidKeyAliasPass:
Type: String
Default: '0'
AWSAccessKeyID:
Type: String
Default: '0'
AWSSecretAccessKey:
Type: String
Default: '0'
# template secrets p1 - input
Mappings:
SubnetConfig:
VPC:
@@ -127,65 +98,9 @@ Resources:
Metadata:
'AWS::CloudFormation::Designer':
id: c6f18447-b879-4696-8873-f981b2cedd2b
GithubTokenSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'GithubToken', !Ref BUILDID ] ]
SecretString: !Ref GithubToken
UnityLicenseSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'UnityLicense', !Ref BUILDID ] ]
SecretString: !Ref UnityLicense
UnityEmailSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'UnityEmail', !Ref BUILDID ] ]
SecretString: !Ref UnityEmail
UnityPasswordSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'UnityPassword', !Ref BUILDID ] ]
SecretString: !Ref UnityPassword
UnitySerialSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'UnitySerial', !Ref BUILDID ] ]
SecretString: !Ref UnitySerial
AndroidKeystoreBase64Secret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'AndroidKeystoreBase64', !Ref BUILDID ] ]
SecretString: !Ref AndroidKeystoreBase64
AndroidKeystorePassSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'AndroidKeystorePass', !Ref BUILDID ] ]
SecretString: !Ref AndroidKeystorePass
AndroidKeyAliasPassSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'AndroidKeyAliasPass', !Ref BUILDID ] ]
SecretString: !Ref AndroidKeyAliasPass
AWSAccessKeyIDSecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'AWSAccessKeyID', !Ref BUILDID ] ]
SecretString: !Ref AWSAccessKeyID
AWSSecretAccessKeySecret:
Type: AWS::SecretsManager::Secret
Properties:
Name: !Join [ "", [ 'AWSSecretAccessKey', !Ref BUILDID ] ]
SecretString: !Ref AWSSecretAccessKey
# template secrets p2 - secret
TaskDefinition:
Type: 'AWS::ECS::TaskDefinition'
Properties:
@@ -225,29 +140,13 @@ Resources:
Environment:
- Name: ALLOW_EMPTY_PASSWORD
Value: 'yes'
# template - env vars
MountPoints:
- SourceVolume: efs-data
ContainerPath: !Ref EFSMountDirectory
ReadOnly: false
Secrets:
- Name: 'GITHUB_TOKEN'
ValueFrom: !Ref GithubTokenSecret
- Name: 'UNITY_LICENSE'
ValueFrom: !Ref UnityLicenseSecret
- Name: 'UNITY_EMAIL'
ValueFrom: !Ref UnityEmailSecret
- Name: 'UNITY_PASSWORD'
ValueFrom: !Ref UnityPasswordSecret
- Name: 'UNITY_SERIAL'
ValueFrom: !Ref UnitySerialSecret
- Name: 'ANDROID_KEYSTORE_BASE64'
ValueFrom: !Ref AndroidKeystoreBase64Secret
- Name: 'ANDROID_KEYSTORE_PASS'
ValueFrom: !Ref AndroidKeystorePassSecret
- Name: 'AWS_ACCESS_KEY_ID'
ValueFrom: !Ref AWSAccessKeyIDSecret
- Name: 'AWS_SECRET_ACCESS_KEY'
ValueFrom: !Ref AWSSecretAccessKeySecret
# template secrets p3 - container def
LogConfiguration:
LogDriver: awslogs
Options:

View File

@@ -39,12 +39,14 @@ namespace UnityBuilderAction
// Set version for this build
VersionApplicator.SetVersion(options["buildVersion"]);
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
// Apply Android settings
if (buildPlayerOptions.target == BuildTarget.Android)
{
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
AndroidSettings.Apply(options);
}
// Execute default AddressableAsset content build, if the package is installed.
// Version defines would be the best solution here, but Unity 2018 doesn't support that,
// so we fall back to using reflection instead.

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using UnityEditor;
namespace UnityBuilderAction.Input
@@ -16,6 +17,8 @@ namespace UnityBuilderAction.Input
PlayerSettings.Android.keyaliasName = keyaliasName;
if (options.TryGetValue("androidKeyaliasPass", out string keyaliasPass) && !string.IsNullOrEmpty(keyaliasPass))
PlayerSettings.Android.keyaliasPass = keyaliasPass;
if (options.TryGetValue("androidTargetSdkVersion", out string androidTargetSdkVersion) && !string.IsNullOrEmpty(androidTargetSdkVersion))
PlayerSettings.Android.targetSdkVersion = (AndroidSdkVersions) Enum.Parse(typeof(AndroidSdkVersions), androidTargetSdkVersion);
}
}
}

View File

@@ -15,7 +15,12 @@ namespace UnityBuilderAction.Versioning
}
public static void SetAndroidVersionCode(string androidVersionCode) {
PlayerSettings.Android.bundleVersionCode = Int32.Parse(androidVersionCode);
int bundleVersionCode = Int32.Parse(androidVersionCode);
if (bundleVersionCode <= 0) {
return;
}
PlayerSettings.Android.bundleVersionCode = bundleVersionCode;
}
static void Apply(string version)

394236
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

2227
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load Diff

48
dist/platforms/mac/entrypoint.sh vendored Executable file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
#
# Create directories for license activation
#
sudo mkdir /Library/Application\ Support/Unity
sudo chmod -R 777 /Library/Application\ Support/Unity
ACTIVATE_LICENSE_PATH="$ACTION_FOLDER/BlankProject"
mkdir -p "$ACTIVATE_LICENSE_PATH"
#
# Run steps
#
source $ACTION_FOLDER/platforms/mac/steps/activate.sh
source $ACTION_FOLDER/platforms/mac/steps/build.sh
source $ACTION_FOLDER/platforms/mac/steps/return_license.sh
#
# Remove license activation directory
#
sudo rm -r /Library/Application\ Support/Unity
rm -r "$ACTIVATE_LICENSE_PATH"
#
# Instructions for debugging
#
if [[ $BUILD_EXIT_CODE -gt 0 ]]; then
echo ""
echo "###########################"
echo "# Failure #"
echo "###########################"
echo ""
echo "Please note that the exit code is not very descriptive."
echo "Most likely it will not help you solve the issue."
echo ""
echo "To find the reason for failure: please search for errors in the log above."
echo ""
fi;
#
# Exit with code from the build step.
#
exit $BUILD_EXIT_CODE

37
dist/platforms/mac/steps/activate.sh vendored Executable file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# Run in ACTIVATE_LICENSE_PATH directory
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
pushd "$ACTIVATE_LICENSE_PATH"
echo "Requesting activation"
# Activate license
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logFile /dev/stdout \
-batchmode \
-nographics \
-quit \
-serial "$UNITY_SERIAL" \
-username "$UNITY_EMAIL" \
-password "$UNITY_PASSWORD" \
-projectPath "$ACTIVATE_LICENSE_PATH"
# Store the exit code from the verify command
UNITY_EXIT_CODE=$?
#
# Display information about the result
#
if [ $UNITY_EXIT_CODE -eq 0 ]; then
# Activation was a success
echo "Activation complete."
else
# Activation failed so exit with the code from the license verification step
echo "Unclassified error occured while trying to activate license."
echo "Exit code was: $UNITY_EXIT_CODE"
exit $UNITY_EXIT_CODE
fi
# Return to previous working directory
popd

188
dist/platforms/mac/steps/build.sh vendored Executable file
View File

@@ -0,0 +1,188 @@
#!/usr/bin/env bash
#
# Set project path
#
UNITY_PROJECT_PATH="$GITHUB_WORKSPACE/$PROJECT_PATH"
echo "Using project path \"$UNITY_PROJECT_PATH\"."
#
# Display the name for the build, doubles as the output name
#
echo "Using build name \"$BUILD_NAME\"."
#
# Display the build's target platform;
#
echo "Using build target \"$BUILD_TARGET\"."
#
# Display build path and file
#
echo "Using build path \"$BUILD_PATH\" to save file \"$BUILD_FILE\"."
BUILD_PATH_FULL="$GITHUB_WORKSPACE/$BUILD_PATH"
CUSTOM_BUILD_PATH="$BUILD_PATH_FULL/$BUILD_FILE"
#
# Set the build method, must reference one of:
#
# - <NamespaceName.ClassName.MethodName>
# - <ClassName.MethodName>
#
# For example: `BuildCommand.PerformBuild`
#
# The method must be declared static and placed in project/Assets/Editor
#
if [ -z "$BUILD_METHOD" ]; then
# User has not provided their own build command.
#
# Use the script from this action which builds the scenes that are enabled in
# the project.
#
echo "Using built-in build method."
# Create Editor directory if it does not exist
mkdir -p "$UNITY_PROJECT_PATH/Assets/Editor/"
# Copy the build script of Unity Builder action
cp -R "$ACTION_FOLDER/default-build-script/Assets/Editor/" "$UNITY_PROJECT_PATH/Assets/Editor/"
# Set the Build method to that of UnityBuilder Action
BUILD_METHOD="UnityBuilderAction.Builder.BuildProject"
# Verify recursive paths
ls -Ralph "$UNITY_PROJECT_PATH/Assets/Editor/"
#
else
# User has provided their own build method.
# Assume they also bring their own script.
#
echo "Using build method \"$BUILD_METHOD\"."
#
fi
#
# Prepare Android keystore and SDK, if needed
#
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_KEYSTORE_NAME" && -n "$ANDROID_KEYSTORE_BASE64" ]]; then
echo "Creating Android keystore."
echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$UNITY_PROJECT_PATH/$ANDROID_KEYSTORE_NAME"
echo "Created Android keystore."
else
echo "Not creating Android keystore."
fi
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
"$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)/tools/bin/sdkmanager" "$ANDROID_SDK_MANAGER_PARAMETERS"
echo "Updated Android SDK."
else
echo "Not updating Android SDK."
fi
#
# Pre-build debug information
#
echo ""
echo "###########################"
echo "# Custom parameters #"
echo "###########################"
echo ""
echo "$CUSTOM_PARAMETERS"
echo ""
echo "###########################"
echo "# Current build dir #"
echo "###########################"
echo ""
echo "Creating \"$BUILD_PATH_FULL\" if it does not exist."
mkdir -p "$BUILD_PATH_FULL"
ls -alh "$BUILD_PATH_FULL"
echo ""
echo "###########################"
echo "# Project directory #"
echo "###########################"
echo ""
ls -alh "$UNITY_PROJECT_PATH"
#
# Build
#
echo ""
echo "###########################"
echo "# Building project #"
echo "###########################"
echo ""
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logfile /dev/stdout \
-quit \
-batchmode \
-nographics \
-customBuildName "$BUILD_NAME" \
-projectPath "$UNITY_PROJECT_PATH" \
-buildTarget "$BUILD_TARGET" \
-customBuildTarget "$BUILD_TARGET" \
-customBuildPath "$CUSTOM_BUILD_PATH" \
-executeMethod "$BUILD_METHOD" \
-buildVersion "$VERSION" \
-androidVersionCode "$ANDROID_VERSION_CODE" \
-androidKeystoreName "$ANDROID_KEYSTORE_NAME" \
-androidKeystorePass "$ANDROID_KEYSTORE_PASS" \
-androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \
-androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \
-androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \
$CUSTOM_PARAMETERS
# Catch exit code
BUILD_EXIT_CODE=$?
# Display results
if [ $BUILD_EXIT_CODE -eq 0 ]; then
echo "Build succeeded";
else
echo "Build failed, with exit code $BUILD_EXIT_CODE";
fi
#
# Permissions
#
# Make a given user owner of all artifacts
if [[ -n "$CHOWN_FILES_TO" ]]; then
chown -R "$CHOWN_FILES_TO" "$BUILD_PATH_FULL"
chown -R "$CHOWN_FILES_TO" "$UNITY_PROJECT_PATH"
fi
# Add read permissions for everyone to all artifacts
chmod -R a+r "$BUILD_PATH_FULL"
chmod -R a+r "$UNITY_PROJECT_PATH"
# Add execute permissions to specific files
if [[ "$BUILD_TARGET" == "StandaloneOSX" ]]; then
OSX_EXECUTABLE_PATH="$BUILD_PATH_FULL/$BUILD_NAME.app/Contents/MacOS"
find "$OSX_EXECUTABLE_PATH" -type f -exec chmod +x {} \;
fi
#
# Results
#
echo ""
echo "###########################"
echo "# Build output #"
echo "###########################"
echo ""
ls -alh "$BUILD_PATH_FULL"

16
dist/platforms/mac/steps/return_license.sh vendored Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Run in ACTIVATE_LICENSE_PATH directory
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
pushd "$ACTIVATE_LICENSE_PATH"
/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app/Contents/MacOS/Unity \
-logFile /dev/stdout \
-batchmode \
-nographics \
-quit \
-returnlicense \
-projectPath "$ACTIVATE_LICENSE_PATH"
# Return to previous working directory
popd

View File

@@ -1,13 +1,26 @@
#!/usr/bin/env bash
#
# Create directory for license activation
#
ACTIVATE_LICENSE_PATH="$GITHUB_WORKSPACE/_activate-license~"
mkdir -p "$ACTIVATE_LICENSE_PATH"
#
# Run steps
#
source /steps/set_gitcredential.sh
source /steps/activate.sh
source /steps/build.sh
source /steps/return_license.sh
#
# Remove license activation directory
#
rm -r "$ACTIVATE_LICENSE_PATH"
#
# Instructions for debugging
#

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env bash
# Run in ACTIVATE_LICENSE_PATH directory
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
pushd "$ACTIVATE_LICENSE_PATH"
if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
#
# PERSONAL LICENSE MODE
@@ -25,7 +29,6 @@ if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
# Activate license
ACTIVATION_OUTPUT=$(unity-editor \
-nographics \
-logFile /dev/stdout \
-quit \
-manualLicenseFile $FILE_PATH)
@@ -62,8 +65,6 @@ elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
# Activate license
unity-editor \
-batchmode \
-nographics \
-logFile /dev/stdout \
-quit \
-serial "$UNITY_SERIAL" \
@@ -81,7 +82,7 @@ else
#
echo "License activation strategy could not be determined."
echo ""
echo "Visit https://github.com/webbertakken/unity-builder#usage for more"
echo "Visit https://game.ci/docs/github/getting-started for more"
echo "details on how to set up one of the possible activation strategies."
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
@@ -101,3 +102,6 @@ else
echo "Exit code was: $UNITY_EXIT_CODE"
exit $UNITY_EXIT_CODE
fi
# Return to previous working directory
popd

View File

@@ -63,14 +63,24 @@ else
fi
#
# Create Android keystore, if needed
# Prepare Android keystore and SDK, if needed
#
if [[ -z $ANDROID_KEYSTORE_NAME || -z $ANDROID_KEYSTORE_BASE64 ]]; then
echo "Not creating Android keystore."
else
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_KEYSTORE_NAME" && -n "$ANDROID_KEYSTORE_BASE64" ]]; then
echo "Creating Android keystore."
echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$UNITY_PROJECT_PATH/$ANDROID_KEYSTORE_NAME"
echo "Created Android keystore."
else
echo "Not creating Android keystore."
fi
if [[ "$BUILD_TARGET" == "Android" && -n "$ANDROID_SDK_MANAGER_PARAMETERS" ]]; then
echo "Updating Android SDK with parameters: $ANDROID_SDK_MANAGER_PARAMETERS"
export JAVA_HOME="$(awk -F'=' '/JAVA_HOME=/{print $2}' /usr/bin/unity-editor.d/*)"
"$(awk -F'=' '/ANDROID_HOME=/{print $2}' /usr/bin/unity-editor.d/*)/tools/bin/sdkmanager" "$ANDROID_SDK_MANAGER_PARAMETERS"
echo "Updated Android SDK."
else
echo "Not updating Android SDK."
fi
#
@@ -116,7 +126,6 @@ echo ""
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
unity-editor \
-nographics \
-logfile /dev/stdout \
-quit \
-customBuildName "$BUILD_NAME" \
@@ -131,6 +140,7 @@ unity-editor \
-androidKeystorePass "$ANDROID_KEYSTORE_PASS" \
-androidKeyaliasName "$ANDROID_KEYALIAS_NAME" \
-androidKeyaliasPass "$ANDROID_KEYALIAS_PASS" \
-androidTargetSdkVersion "$ANDROID_TARGET_SDK_VERSION" \
$CUSTOM_PARAMETERS
# Catch exit code
@@ -159,8 +169,8 @@ chmod -R a+r "$UNITY_PROJECT_PATH"
# Add execute permissions to specific files
if [[ "$BUILD_TARGET" == "StandaloneOSX" ]]; then
OSX_EXECUTABLE_PATH="$BUILD_PATH_FULL/StandaloneOSX.app/Contents/MacOS/*"
chmod +x "$OSX_EXECUTABLE_PATH"
OSX_EXECUTABLE_PATH="$BUILD_PATH_FULL/$BUILD_NAME.app/Contents/MacOS"
find "$OSX_EXECUTABLE_PATH" -type f -exec chmod +x {} \;
fi
#

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env bash
# Run in ACTIVATE_LICENSE_PATH directory
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
pushd "$ACTIVATE_LICENSE_PATH"
if [[ -n "$UNITY_SERIAL" ]]; then
#
# PROFESSIONAL (SERIAL) LICENSE MODE
@@ -7,8 +11,10 @@ if [[ -n "$UNITY_SERIAL" ]]; then
# This will return the license that is currently in use.
#
unity-editor \
-nographics \
-logFile /dev/stdout \
-quit \
-returnlicense
fi
# Return to previous working directory
popd

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
if [ -z "${GIT_PRIVATE_TOKEN}" ]
then
echo "GIT_PRIVATE_TOKEN unset skipping"
else
echo "GIT_PRIVATE_TOKEN is set configuring git credentials"
git config --global credential.helper store
git config --global --replace-all url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf ssh://git@github.com/
git config --global --add url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf git@github.com
git config --global url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
git config --global url."https://ssh:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
git config --global url."https://git:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
fi
echo "---------- git config --list -------------"
git config --list
echo "---------- git config --list --show-origin -------------"
git config --list --show-origin

7
dist/platforms/windows/activate.ps1 vendored Normal file
View File

@@ -0,0 +1,7 @@
# Activates Unity
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -nographics `
-username $Env:UNITY_EMAIL `
-password $Env:UNITY_PASSWORD `
-serial $Env:UNITY_SERIAL `
-projectPath "c:/BlankProject" `
-logfile | Out-Host

147
dist/platforms/windows/build.ps1 vendored Normal file
View File

@@ -0,0 +1,147 @@
#
# Set project path
#
$Env:UNITY_PROJECT_PATH="$Env:GITHUB_WORKSPACE\$Env:PROJECT_PATH"
Write-Output "$('Using project path "')$($Env:UNITY_PROJECT_PATH)$('".')"
#
# Display the name for the build, doubles as the output name
#
Write-Output "$('Using build name "')$($Env:BUILD_NAME)$('".')"
#
# Display the build's target platform;
#
Write-Output "$('Using build target "')$($Env:BUILD_TARGET)$('".')"
#
# Display build path and file
#
Write-Output "$('Using build path "')$($Env:BUILD_PATH)$('" to save file "')$($Env:BUILD_FILE)$('".')"
$Env:BUILD_PATH_FULL="$Env:GITHUB_WORKSPACE\$Env:BUILD_PATH"
$Env:CUSTOM_BUILD_PATH="$Env:BUILD_PATH_FULL\$Env:BUILD_FILE"
#
# Set the build method, must reference one of:
#
# - <NamespaceName.ClassName.MethodName>
# - <ClassName.MethodName>
#
# For example: `BuildCommand.PerformBuild`
#
# The method must be declared static and placed in project/Assets/Editor
#
if ($Env:BUILD_METHOD)
{
# User has provided their own build method.
# Assume they also bring their own script.
Write-Output "$('Using build method "')$($Env:BUILD_METHOD)$('".')"
}
else
{
# User has not provided their own build command.
#
# Use the script from this action which builds the scenes that are enabled in
# the project.
#
Write-Output "Using built-in build method."
# Create Editor directory if it does not exist
if(-Not (Test-Path -Path $Env:UNITY_PROJECT_PATH\Assets\Editor))
{
# We use -Force to suppress output, doesn't overwrite anything
New-Item -ItemType Directory -Force -Path $Env:UNITY_PROJECT_PATH\Assets\Editor
}
# Copy the build script of Unity Builder action
Copy-Item -Path "c:\UnityBuilderAction" -Destination $Env:UNITY_PROJECT_PATH\Assets\Editor -Recurse
# Set the Build method to that of UnityBuilder Action
$Env:BUILD_METHOD="UnityBuilderAction.Builder.BuildProject"
# Verify recursive paths
Get-ChildItem -Path $Env:UNITY_PROJECT_PATH\Assets\Editor -Recurse
}
#
# Pre-build debug information
#
Write-Output ""
Write-Output "###########################"
Write-Output "# Custom parameters #"
Write-Output "###########################"
Write-Output ""
Write-Output "$('"')$($Env:CUSTOM_PARAMETERS)$('"')"
Write-Output ""
Write-Output "###########################"
Write-Output "# Current build dir #"
Write-Output "###########################"
Write-Output ""
Write-Output "$('Creating "')$($Env:BUILD_PATH_FULL)$('" if it does not exist.')"
if (-Not (Test-Path -Path $Env:BUILD_PATH_FULL))
{
mkdir "$Env:BUILD_PATH_FULL"
}
Get-ChildItem $Env:BUILD_PATH_FULL
Write-Output ""
Write-Output "###########################"
Write-Output "# Project directory #"
Write-Output "###########################"
Write-Output ""
Get-ChildItem $Env:UNITY_PROJECT_PATH
#
# Build
#
Write-Output ""
Write-Output "###########################"
Write-Output "# Building project #"
Write-Output "###########################"
Write-Output ""
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -quit -batchmode -nographics `
-projectPath $Env:UNITY_PROJECT_PATH `
-executeMethod $Env:BUILD_METHOD `
-buildTarget $Env:BUILD_TARGET `
-customBuildTarget $Env:BUILD_TARGET `
-customBuildPath $Env:CUSTOM_BUILD_PATH `
-buildVersion $Env:VERSION `
$Env:CUSTOM_PARAMETERS `
-logfile | Out-Host
# Catch exit code
$Env:BUILD_EXIT_CODE=$?
# Display results
if ($Env:BUILD_EXIT_CODE -eq 0)
{
Write-Output "Build Succeeded!"
} else
{
Write-Output "$('Build failed, with exit code ')$($Env:BUILD_EXIT_CODE)$('"')"
}
# TODO: Determine if we need to set permissions on any files
#
# Results
#
Write-Output ""
Write-Output "###########################"
Write-Output "# Build output #"
Write-Output "###########################"
Write-Output ""
Get-ChildItem $Env:BUILD_PATH_FULL
Write-Output ""

15
dist/platforms/windows/entrypoint.ps1 vendored Normal file
View File

@@ -0,0 +1,15 @@
# Activate Unity
& "c:\steps\activate.ps1"
# Import any necessary registry keys, ie: location of windows 10 sdk
# No guarantee that there will be any necessary registry keys, ie: tvOS
Get-ChildItem -Path c:\regkeys -File | Foreach {reg import $_.fullname}
# Register the Visual Studio installation so Unity can find it
regsvr32 C:\ProgramData\Microsoft\VisualStudio\Setup\x64\Microsoft.VisualStudio.Setup.Configuration.Native.dll
# Build the project
& "c:\steps\build.ps1"
# Free the seat for the activated license
& "c:\steps\return_license.ps1"

View File

@@ -0,0 +1,7 @@
# Return the active Unity license
& "C:\Program Files\Unity\Hub\Editor\$Env:UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -nographics `
-username $Env:UNITY_EMAIL `
-password $Env:UNITY_PASSWORD `
-returnlicense `
-projectPath "c:/BlankProject" `
-logfile | Out-Host

3911
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

60
dist/xhr-sync-worker.js vendored Normal file
View File

@@ -0,0 +1,60 @@
"use strict";
/* eslint-disable no-process-exit */
const util = require("util");
const { JSDOM } = require("../../../..");
const { READY_STATES } = require("./xhr-utils");
const idlUtils = require("../generated/utils");
const tough = require("tough-cookie");
const dom = new JSDOM();
const xhr = new dom.window.XMLHttpRequest();
const xhrImpl = idlUtils.implForWrapper(xhr);
const chunks = [];
process.stdin.on("data", chunk => {
chunks.push(chunk);
});
process.stdin.on("end", () => {
const buffer = Buffer.concat(chunks);
const flag = JSON.parse(buffer.toString());
if (flag.body && flag.body.type === "Buffer" && flag.body.data) {
flag.body = Buffer.from(flag.body.data);
}
if (flag.cookieJar) {
flag.cookieJar = tough.CookieJar.fromJSON(flag.cookieJar);
}
flag.synchronous = false;
Object.assign(xhrImpl.flag, flag);
const { properties } = xhrImpl;
xhrImpl.readyState = READY_STATES.OPENED;
try {
xhr.addEventListener("loadend", () => {
if (properties.error) {
properties.error = properties.error.stack || util.inspect(properties.error);
}
process.stdout.write(JSON.stringify({
responseURL: xhrImpl.responseURL,
status: xhrImpl.status,
statusText: xhrImpl.statusText,
properties
}), () => {
process.exit(0);
});
}, false);
xhr.send(flag.body);
} catch (error) {
properties.error += error.stack || util.inspect(error);
process.stdout.write(JSON.stringify({
responseURL: xhrImpl.responseURL,
status: xhrImpl.status,
statusText: xhrImpl.statusText,
properties
}), () => {
process.exit(0);
});
}
});

View File

@@ -1,11 +1,30 @@
module.exports = {
// Automatically clear mock calls and instances between every test
clearMocks: true,
// An array of file extensions your modules use
moduleFileExtensions: ['js', 'ts'],
// The test environment that will be used for testing
testEnvironment: 'node',
// The glob patterns Jest uses to detect test files
testMatch: ['**/*.test.ts'],
// This option allows use of a custom test runner
testRunner: 'jest-circus/runner',
// A map with regular expressions for transformers to paths
transform: {
'^.+\\.ts$': 'ts-jest',
},
// Indicates whether each individual test should be reported during the run
verbose: true,
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
modulePathIgnorePatterns: ['<rootDir>/lib/', '<rootDir>/dist/'],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
setupFilesAfterEnv: ['<rootDir>/src/jest.setup.ts'],
};

38
lefthook.yml Normal file
View File

@@ -0,0 +1,38 @@
# EXAMPLE USAGE
# Refer for explanation to following link:
# https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md
#
color: true
extends: {}
pre-push:
parallel: true
commands:
packages-audit:
tags: security
run: yarn audit
pre-commit:
parallel: true
commands:
format documents:
glob: '*.{md,mdx}'
run: yarn prettier --write {staged_files}
format configs:
glob: '*.{json,yml,yaml}'
run: yarn prettier --write {staged_files}
format code:
glob: '*.{js,jsx,ts,tsx}'
exclude: 'dist/'
run: yarn prettier --write {staged_files} && yarn eslint {staged_files} && git add {staged_files}
run tests:
glob: '*.{js,jsx,ts,tsx}'
exclude: 'dist/'
run: yarn jest --passWithNoTests --findRelatedTests {staged_files}
build distributables:
skip: ['merge', 'rebase']
run: yarn build && git add dist
make shell script executable:
glob: '*.sh'
run: git update-index --chmod=+x

View File

@@ -7,61 +7,59 @@
"author": "Webber <webber@takken.io>",
"license": "MIT",
"scripts": {
"prebuild": "yarn",
"build": "tsc && ncc build lib --source-map --license licenses.txt",
"prepare": "lefthook install",
"build": "yarn && tsc && ncc build lib --source-map --license licenses.txt",
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src/**/*.ts",
"format": "prettier --write \"src/**/*.{js,ts}\"",
"test": "jest"
"cli": "yarn ts-node src/index.ts -m cli",
"cli-aws": "cross-env cloudRunnerCluster=aws yarn run test-cli",
"cli-k8s": "cross-env cloudRunnerCluster=k8s yarn run test-cli",
"test-cli": "cross-env cloudRunnerTests=true yarn ts-node src/index.ts -m cli --projectPath test-project",
"test": "jest",
"test-i": "yarn run test-i-aws && yarn run test-i-k8s",
"test-i-f": "yarn run test-i-aws && yarn run test-i-k8s && yarn run cli-k8s && yarn run cli-aws",
"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\""
},
"dependencies": {
"@actions/core": "^1.2.6",
"@actions/exec": "^1.0.4",
"@actions/github": "^2.2.0",
"aws-sdk": "^2.812.0",
"@actions/core": "^1.6.0",
"@actions/exec": "^1.1.0",
"@actions/github": "^5.0.0",
"@kubernetes/client-node": "^0.16.3",
"@octokit/core": "^3.5.1",
"async-wait-until": "^2.0.12",
"aws-sdk": "^2.1081.0",
"base-64": "^1.0.0",
"commander": "^9.0.0",
"commander-ts": "^0.2.0",
"kubernetes-client": "^9.0.0",
"nanoid": "3.1.20",
"semver": "^7.3.2"
"nanoid": "^3.3.1",
"reflect-metadata": "^0.1.13",
"semver": "^7.3.5",
"unity-changeset": "^1.6.0",
"yaml": "^1.10.2"
},
"devDependencies": {
"@types/jest": "^26.0.15",
"@types/node": "^14.14.9",
"@types/semver": "^7.3.4",
"@typescript-eslint/parser": "^4.8.1",
"@vercel/ncc": "^0.25.1",
"eslint": "^7.17.0",
"eslint-config-prettier": "^8.1.0",
"@arkweid/lefthook": "^0.7.7",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.21",
"@types/semver": "^7.3.9",
"@typescript-eslint/parser": "4.8.1",
"@vercel/ncc": "^0.33.3",
"cross-env": "^7.0.3",
"eslint": "7.17.0",
"eslint-config-prettier": "8.1.0",
"eslint-plugin-github": "^4.1.1",
"eslint-plugin-jest": "^24.1.3",
"eslint-plugin-jest": "24.1.3",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-unicorn": "^28.0.2",
"husky": "4.2.5",
"jest": "^26.6.3",
"jest-circus": "^26.6.3",
"js-yaml": "^3.14.0",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"ts-jest": "^26.4.4",
"typescript": "^4.1.3"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged && yarn build && git add dist/index.*"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint",
"git add",
"jest --findRelatedTests"
],
"*.{json,md,yaml,yml}": [
"prettier --write",
"git add"
],
"*.sh": [
"git update-index --chmod=+x"
]
"eslint-plugin-unicorn": "28.0.2",
"jest": "^27.5.1",
"jest-circus": "^27.5.1",
"jest-fail-on-console": "^2.3.0",
"js-yaml": "^4.1.0",
"prettier": "^2.5.1",
"ts-jest": "^27.1.3",
"ts-node": "10.4.0",
"typescript": "4.1.3"
}
}

5
scripts/cleanupGCPResources.sh Executable file
View File

@@ -0,0 +1,5 @@
kubectl delete job $(kubectl get jobs -o custom-columns=:.metadata.name)
kubectl delete cronjob $(kubectl get cronjobs -o custom-columns=:.metadata.name)
kubectl delete pod $(kubectl get pods -o custom-columns=:.metadata.name)
kubectl delete pvc $(kubectl get pvc -o custom-columns=:.metadata.name)
kubectl delete secret $(kubectl get secrets -o custom-columns=:.metadata.name)

View File

@@ -1,41 +1,43 @@
import * as core from '@actions/core';
import { Action, BuildParameters, Cache, Docker, ImageTag, Kubernetes, Output, AWS } from './model';
async function run() {
import { Action, BuildParameters, Cache, Docker, ImageTag, Output, CloudRunner } from './model';
import { CLI } from './model/cli/cli';
import MacBuilder from './model/mac-builder';
import PlatformSetup from './model/platform-setup';
async function runMain() {
try {
Action.checkCompatibility();
Cache.verify();
const { dockerfile, workspace, actionFolder } = Action;
const { workspace, actionFolder } = Action;
const buildParameters = await BuildParameters.create();
const baseImage = new ImageTag(buildParameters);
let builtImage;
switch (buildParameters.remoteBuildCluster) {
case 'k8s':
core.info('Building with Kubernetes');
await Kubernetes.runBuildJob(buildParameters, baseImage);
break;
case 'aws':
core.info('Building with AWS');
await AWS.runBuildJob(buildParameters, baseImage);
break;
// default and local case
default:
core.info('Building locally');
builtImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
await Docker.run(builtImage, { workspace, ...buildParameters });
break;
if (
buildParameters.cloudRunnerCluster &&
buildParameters.cloudRunnerCluster !== '' &&
buildParameters.cloudRunnerCluster !== 'local'
) {
await CloudRunner.run(buildParameters, baseImage.toString());
} else {
core.info('Building locally');
await PlatformSetup.setup(buildParameters, actionFolder);
if (process.platform === 'darwin') {
MacBuilder.run(actionFolder, workspace, buildParameters);
} else {
await Docker.run(baseImage, { workspace, actionFolder, ...buildParameters });
}
}
// Set output
await Output.setBuildVersion(buildParameters.buildVersion);
} catch (error) {
core.setFailed(error.message);
core.setFailed((error as Error).message);
}
}
run();
const options = CLI.SetupCli();
if (CLI.isCliMode(options)) {
CLI.RunCli(options);
} else {
runMain();
}

9
src/jest.setup.ts Normal file
View File

@@ -0,0 +1,9 @@
import failOnConsole from 'jest-fail-on-console';
// Fail when console logs something inside a test - use spyOn instead
failOnConsole({
shouldFailOnWarn: true,
shouldFailOnError: true,
shouldFailOnLog: true,
shouldFailOnAssert: true,
});

View File

@@ -2,7 +2,7 @@
import Platform from '../platform';
export const mockGetFromUser = jest.fn().mockResolvedValue({
version: '',
editorVersion: '',
targetPlatform: Platform.types.Test,
projectPath: '.',
buildName: Platform.types.Test,
@@ -10,7 +10,9 @@ export const mockGetFromUser = jest.fn().mockResolvedValue({
buildMethod: undefined,
buildVersion: '1.3.37',
customParameters: '',
sshAgent: '',
chownFilesTo: '',
gitPrivateToken: '',
});
export default {

View File

@@ -1,4 +1,4 @@
/* eslint-disable unicorn/prevent-abbreviations */
/* eslint unicorn/prevent-abbreviations: "off" */
// Import these named export into your test file:
export const mockProjectPath = jest.fn().mockResolvedValue('mockProjectPath');

View File

@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Versioning determineVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
exports[`Versioning determineBuildVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;

View File

@@ -4,11 +4,15 @@ import Action from './action';
describe('Action', () => {
describe('compatibility check', () => {
it('throws for anything other than linux', () => {
if (process.platform !== 'linux') {
expect(() => Action.checkCompatibility()).toThrow();
} else {
expect(() => Action.checkCompatibility()).not.toThrow();
it('throws for anything other than linux, windows, or mac', () => {
switch (process.platform) {
case 'linux':
case 'win32':
case 'darwin':
expect(() => Action.checkCompatibility()).not.toThrow();
break;
default:
expect(() => Action.checkCompatibility()).toThrow();
}
});
});
@@ -26,11 +30,4 @@ describe('Action', () => {
expect(path.basename(actionFolder)).toStrictEqual('dist');
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
});
it('returns the docker file', () => {
const { dockerfile } = Action;
expect(path.basename(dockerfile)).toStrictEqual('Dockerfile');
expect(fs.existsSync(dockerfile)).toStrictEqual(true);
});
});

View File

@@ -2,7 +2,7 @@ import path from 'path';
class Action {
static get supportedPlatforms() {
return ['linux'];
return ['linux', 'win32', 'darwin'];
}
static get isRunningLocally() {
@@ -29,10 +29,6 @@ class Action {
return `${Action.rootFolder}/dist`;
}
static get dockerfile() {
return `${Action.actionFolder}/Dockerfile`;
}
static get workspace() {
return process.env.GITHUB_WORKSPACE;
}

View File

@@ -2,6 +2,10 @@ import AndroidVersioning from './android-versioning';
describe('Android Versioning', () => {
describe('versionToVersionCode', () => {
it('defaults to 0 when versioning strategy is none', () => {
expect(AndroidVersioning.versionToVersionCode('none')).toBe(0);
});
it('defaults to 1 when version is not a valid semver', () => {
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe(1);
});
@@ -11,7 +15,7 @@ describe('Android Versioning', () => {
});
it('throw when generated version code is too large', () => {
expect(() => AndroidVersioning.versionToVersionCode('1234.0.0')).toThrow();
expect(() => AndroidVersioning.versionToVersionCode('2050.0.0')).toThrow();
});
});
@@ -24,4 +28,14 @@ describe('Android Versioning', () => {
expect(AndroidVersioning.determineVersionCode('1.2.3', 2)).toBe(2);
});
});
describe('determineSdkManagerParameters', () => {
it('defaults to blank', () => {
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevelAuto')).toBe('');
});
it('uses the specified api level', () => {
expect(AndroidVersioning.determineSdkManagerParameters('AndroidApiLevel30')).toBe('platforms;android-30');
});
});
});

View File

@@ -10,6 +10,11 @@ export default class AndroidVersioning {
}
static versionToVersionCode(version) {
if (version === 'none') {
core.info(`Versioning strategy is set to ${version}, so android version code should not be applied.`);
return 0;
}
const parsedVersion = semver.parse(version);
if (!parsedVersion) {
@@ -21,7 +26,7 @@ export default class AndroidVersioning {
// Allow for 3 patch digits, 3 minor digits and 3 major digits.
const versionCode = parsedVersion.major * 1000000 + parsedVersion.minor * 1000 + parsedVersion.patch;
if (versionCode >= 1000000000) {
if (versionCode >= 2050000000) {
throw new Error(
`Generated versionCode ${versionCode} is dangerously close to the maximum allowed number 2100000000. Consider a different versioning scheme to be able to continue updating your application.`,
);
@@ -29,4 +34,9 @@ export default class AndroidVersioning {
core.info(`Using android versionCode ${versionCode}`);
return versionCode;
}
static determineSdkManagerParameters(targetSdkVersion) {
const parsedVersion = Number.parseInt(targetSdkVersion.slice(-2), 10);
return Number.isNaN(parsedVersion) ? '' : `platforms;android-${parsedVersion}`;
}
}

View File

@@ -1,611 +0,0 @@
import * as SDK from 'aws-sdk';
import { customAlphabet } from 'nanoid';
import * as fs from 'fs';
import * as core from '@actions/core';
import * as zlib from 'zlib';
const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const repositoryDirectoryName = 'repo';
const efsDirectoryName = 'data';
const cacheDirectoryName = 'cache';
class AWS {
static async runBuildJob(buildParameters, baseImage) {
try {
const nanoid = customAlphabet(alphabet, 4);
const buildUid = `${process.env.GITHUB_RUN_NUMBER}-${buildParameters.platform
.replace('Standalone', '')
.replace('standalone', '')}-${nanoid()}`;
const branchName = process.env.GITHUB_REF?.split('/').reverse()[0];
core.info('Starting part 1/4 (clone from github and restore cache)');
await this.run(
buildUid,
buildParameters.awsStackName,
'alpine/git',
['/bin/sh'],
[
'-c',
`apk update;
apk add unzip;
apk add git-lfs;
apk add jq;
# Get source repo for project to be built and game-ci repo for utilties
git clone https://${buildParameters.githubToken}@github.com/${process.env.GITHUB_REPOSITORY}.git ${buildUid}/${repositoryDirectoryName} -q
git clone https://${buildParameters.githubToken}@github.com/game-ci/unity-builder.git ${buildUid}/builder -q
cd /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/
git checkout $GITHUB_SHA
cd /${efsDirectoryName}/
# Look for usable cache
if [ ! -d ${cacheDirectoryName} ]; then
mkdir ${cacheDirectoryName}
fi
cd ${cacheDirectoryName}
if [ ! -d "${branchName}" ]; then
mkdir "${branchName}"
fi
cd "${branchName}"
echo " "
echo "Cached Libraries for ${branchName} from previous builds:"
ls
echo " "
libDir="/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library"
if [ -d "$libDir" ]; then
rm -r "$libDir"
echo "Setup .gitignore to ignore Library folder and remove it from builds"
fi
echo 'Checking cache'
# Restore cache
latest=$(ls -t | head -1)
if [ ! -z "$latest" ]; then
echo "Library cache exists from build $latest from ${branchName}"
echo 'Creating empty Library folder for cache'
mkdir "$libDir"
unzip -q $latest -d '/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library/.'
else
echo 'Cache does not exist'
fi
# Print out important directories
echo ' '
echo 'Repo:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/
echo ' '
echo 'Project:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}
echo ' '
echo 'Library:'
ls /${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}/Library/
echo ' '
`,
],
`/${efsDirectoryName}`,
`/${efsDirectoryName}/`,
[
{
name: 'GITHUB_SHA',
value: process.env.GITHUB_SHA,
},
],
[
{
ParameterKey: 'GithubToken',
ParameterValue: buildParameters.githubToken,
},
],
);
core.info('Starting part 2/4 (build unity project)');
await this.run(
buildUid,
buildParameters.awsStackName,
baseImage.toString(),
['/bin/sh'],
[
'-c',
`
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/default-build-script/ /UnityBuilderAction;
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/entrypoint.sh /entrypoint.sh;
cp -r /${efsDirectoryName}/${buildUid}/builder/dist/steps/ /steps;
chmod -R +x /entrypoint.sh;
chmod -R +x /steps;
/entrypoint.sh;
`,
],
`/${efsDirectoryName}`,
`/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/`,
[
{
name: 'ContainerMemory',
value: buildParameters.remoteBuildMemory,
},
{
name: 'ContainerCpu',
value: buildParameters.remoteBuildCpu,
},
{
name: 'GITHUB_WORKSPACE',
value: `/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/`,
},
{
name: 'PROJECT_PATH',
value: buildParameters.projectPath,
},
{
name: 'BUILD_PATH',
value: buildParameters.buildPath,
},
{
name: 'BUILD_FILE',
value: buildParameters.buildFile,
},
{
name: 'BUILD_NAME',
value: buildParameters.buildName,
},
{
name: 'BUILD_METHOD',
value: buildParameters.buildMethod,
},
{
name: 'CUSTOM_PARAMETERS',
value: buildParameters.customParameters,
},
{
name: 'CHOWN_FILES_TO',
value: buildParameters.chownFilesTo,
},
{
name: 'BUILD_TARGET',
value: buildParameters.platform,
},
{
name: 'ANDROID_VERSION_CODE',
value: buildParameters.androidVersionCode.toString(),
},
{
name: 'ANDROID_KEYSTORE_NAME',
value: buildParameters.androidKeystoreName,
},
{
name: 'ANDROID_KEYALIAS_NAME',
value: buildParameters.androidKeyaliasName,
},
],
[
{
ParameterKey: 'GithubToken',
ParameterValue: buildParameters.githubToken,
},
{
ParameterKey: 'UnityLicense',
ParameterValue: process.env.UNITY_LICENSE ? process.env.UNITY_LICENSE : '0',
},
{
ParameterKey: 'UnityEmail',
ParameterValue: process.env.UNITY_EMAIL ? process.env.UNITY_EMAIL : '0',
},
{
ParameterKey: 'UnityPassword',
ParameterValue: process.env.UNITY_PASSWORD ? process.env.UNITY_PASSWORD : '0',
},
{
ParameterKey: 'UnitySerial',
ParameterValue: process.env.UNITY_SERIAL ? process.env.UNITY_SERIAL : '0',
},
{
ParameterKey: 'AndroidKeystoreBase64',
ParameterValue: buildParameters.androidKeystoreBase64 ? buildParameters.androidKeystoreBase64 : '0',
},
{
ParameterKey: 'AndroidKeystorePass',
ParameterValue: buildParameters.androidKeystorePass ? buildParameters.androidKeystorePass : '0',
},
{
ParameterKey: 'AndroidKeyAliasPass',
ParameterValue: buildParameters.androidKeyaliasPass ? buildParameters.androidKeyaliasPass : '0',
},
],
);
core.info('Starting part 3/4 (zip unity build and Library for caching)');
// Cleanup
await this.run(
buildUid,
buildParameters.awsStackName,
'alpine',
['/bin/sh'],
[
'-c',
`
apk update
apk add zip
cd Library
zip -q -r lib-${buildUid}.zip .*
mv lib-${buildUid}.zip /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip
cd ../../
zip -q -r build-${buildUid}.zip ${buildParameters.buildPath}/*
mv build-${buildUid}.zip /${efsDirectoryName}/${buildUid}/build-${buildUid}.zip
`,
],
`/${efsDirectoryName}`,
`/${efsDirectoryName}/${buildUid}/${repositoryDirectoryName}/${buildParameters.projectPath}`,
[
{
name: 'GITHUB_SHA',
value: process.env.GITHUB_SHA,
},
],
[
{
ParameterKey: 'GithubToken',
ParameterValue: buildParameters.githubToken,
},
],
);
core.info('Starting part 4/4 (upload build to s3)');
await this.run(
buildUid,
buildParameters.awsStackName,
'amazon/aws-cli',
['/bin/sh'],
[
'-c',
`
aws s3 cp ${buildUid}/build-${buildUid}.zip s3://game-ci-storage/
# no need to upload Library cache for now
# aws s3 cp /${efsDirectoryName}/${cacheDirectoryName}/${branchName}/lib-${buildUid}.zip s3://game-ci-storage/
rm -r ${buildUid}
`,
],
`/${efsDirectoryName}`,
`/${efsDirectoryName}/`,
[
{
name: 'GITHUB_SHA',
value: process.env.GITHUB_SHA,
},
{
name: 'AWS_DEFAULT_REGION',
value: process.env.AWS_DEFAULT_REGION,
},
],
[
{
ParameterKey: 'GithubToken',
ParameterValue: buildParameters.githubToken,
},
{
ParameterKey: 'AWSAccessKeyID',
ParameterValue: process.env.AWS_ACCESS_KEY_ID,
},
{
ParameterKey: 'AWSSecretAccessKey',
ParameterValue: process.env.AWS_SECRET_ACCESS_KEY,
},
],
);
} catch (error) {
core.setFailed(error);
core.error(error);
}
}
static async run(
buildUid: string,
stackName: string,
image: string,
entrypoint: string[],
commands,
mountdir,
workingdir,
environment,
secrets,
) {
const ECS = new SDK.ECS();
const CF = new SDK.CloudFormation();
const taskDef = await this.setupCloudFormations(
CF,
buildUid,
stackName,
image,
entrypoint,
commands,
mountdir,
workingdir,
secrets,
);
await this.runTask(taskDef, ECS, CF, environment, buildUid);
await this.cleanupResources(CF, taskDef);
}
static async setupCloudFormations(
CF,
buildUid: string,
stackName: string,
image: string,
entrypoint: string[],
commands,
mountdir,
workingdir,
secrets,
) {
const logid = customAlphabet(alphabet, 9)();
commands[1] += `
echo "${logid}"
`;
const taskDefStackName = `${stackName}-${buildUid}`;
const taskDefCloudFormation = fs.readFileSync(`${__dirname}/cloud-formations/task-def-formation.yml`, 'utf8');
await CF.createStack({
StackName: taskDefStackName,
TemplateBody: taskDefCloudFormation,
Parameters: [
{
ParameterKey: 'ImageUrl',
ParameterValue: image,
},
{
ParameterKey: 'ServiceName',
ParameterValue: taskDefStackName,
},
{
ParameterKey: 'Command',
ParameterValue: commands.join(','),
},
{
ParameterKey: 'EntryPoint',
ParameterValue: entrypoint.join(','),
},
{
ParameterKey: 'WorkingDirectory',
ParameterValue: workingdir,
},
{
ParameterKey: 'EFSMountDirectory',
ParameterValue: mountdir,
},
{
ParameterKey: 'BUILDID',
ParameterValue: buildUid,
},
...secrets,
],
}).promise();
core.info('Creating worker cluster...');
const cleanupTaskDefStackName = `${taskDefStackName}-cleanup`;
const cleanupCloudFormation = fs.readFileSync(`${__dirname}/cloud-formations/cloudformation-stack-ttl.yml`, 'utf8');
await CF.createStack({
StackName: cleanupTaskDefStackName,
TemplateBody: cleanupCloudFormation,
Capabilities: ['CAPABILITY_IAM'],
Parameters: [
{
ParameterKey: 'StackName',
ParameterValue: taskDefStackName,
},
{
ParameterKey: 'DeleteStackName',
ParameterValue: cleanupTaskDefStackName,
},
{
ParameterKey: 'TTL',
ParameterValue: '100',
},
{
ParameterKey: 'BUILDID',
ParameterValue: buildUid,
},
],
}).promise();
core.info('Creating cleanup cluster...');
try {
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
} catch (error) {
core.error(error);
}
const taskDefResources = await CF.describeStackResources({
StackName: taskDefStackName,
}).promise();
const baseResources = await CF.describeStackResources({ StackName: stackName }).promise();
// in the future we should offer a parameter to choose if you want the guarnteed shutdown.
core.info('Worker cluster created successfully (skipping wait for cleanup cluster to be ready)');
return {
taskDefStackName,
taskDefCloudFormation,
taskDefStackNameTTL: cleanupTaskDefStackName,
ttlCloudFormation: cleanupCloudFormation,
taskDefResources,
baseResources,
logid,
};
}
static async runTask(taskDef, ECS, CF, environment, buildUid) {
const cluster =
taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ECSCluster')?.PhysicalResourceId || '';
const taskDefinition =
taskDef.taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'TaskDefinition')
?.PhysicalResourceId || '';
const SubnetOne =
taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')
?.PhysicalResourceId || '';
const SubnetTwo =
taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')
?.PhysicalResourceId || '';
const ContainerSecurityGroup =
taskDef.baseResources.StackResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')
?.PhysicalResourceId || '';
const streamName =
taskDef.taskDefResources.StackResources?.find((x) => x.LogicalResourceId === 'KinesisStream')
?.PhysicalResourceId || '';
const task = await ECS.runTask({
cluster,
taskDefinition,
platformVersion: '1.4.0',
overrides: {
containerOverrides: [
{
name: taskDef.taskDefStackName,
environment: [...environment, { name: 'BUILDID', value: buildUid }],
},
],
},
launchType: 'FARGATE',
networkConfiguration: {
awsvpcConfiguration: {
subnets: [SubnetOne, SubnetTwo],
assignPublicIp: 'ENABLED',
securityGroups: [ContainerSecurityGroup],
},
},
}).promise();
core.info('Task is starting on worker cluster');
const taskArn = task.tasks?.[0].taskArn || '';
try {
await ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
} catch (error) {
await new Promise((resolve) => setTimeout(resolve, 3000));
const describeTasks = await ECS.describeTasks({
tasks: [taskArn],
cluster,
}).promise();
core.info(`Task has ended ${describeTasks.tasks?.[0].containers?.[0].lastStatus}`);
core.setFailed(error);
core.error(error);
}
core.info(`Task is running on worker cluster`);
await this.streamLogsUntilTaskStops(ECS, CF, taskDef, cluster, taskArn, streamName);
await ECS.waitFor('tasksStopped', { cluster, tasks: [taskArn] }).promise();
const exitCode = (
await ECS.describeTasks({
tasks: [taskArn],
cluster,
}).promise()
).tasks?.[0].containers?.[0].exitCode;
if (exitCode !== 0) {
try {
await this.cleanupResources(CF, taskDef);
} catch (error) {
core.warning(`failed to cleanup ${error}`);
}
core.error(`job failed with exit code ${exitCode}`);
throw new Error(`job failed with exit code ${exitCode}`);
} else {
core.info(`Task has finished successfully`);
}
}
static async streamLogsUntilTaskStops(ECS: AWS.ECS, CF, taskDef, clusterName, taskArn, kinesisStreamName) {
// watching logs
const kinesis = new SDK.Kinesis();
const getTaskData = async () => {
const tasks = await ECS.describeTasks({
cluster: clusterName,
tasks: [taskArn],
}).promise();
return tasks.tasks?.[0];
};
const stream = await kinesis
.describeStream({
StreamName: kinesisStreamName,
})
.promise();
let iterator =
(
await kinesis
.getShardIterator({
ShardIteratorType: 'TRIM_HORIZON',
StreamName: stream.StreamDescription.StreamName,
ShardId: stream.StreamDescription.Shards[0].ShardId,
})
.promise()
).ShardIterator || '';
await CF.waitFor('stackCreateComplete', { StackName: taskDef.taskDefStackNameTTL }).promise();
core.info(`Task status is ${(await getTaskData())?.lastStatus}`);
const logBaseUrl = `https://${SDK.config.region}.console.aws.amazon.com/cloudwatch/home?region=${SDK.config.region}#logsV2:log-groups/log-group/${taskDef.taskDefStackName}`;
core.info(`You can also see the logs at AWS Cloud Watch: ${logBaseUrl}`);
let readingLogs = true;
let timestamp: number = 0;
while (readingLogs) {
await new Promise((resolve) => setTimeout(resolve, 1500));
const taskData = await getTaskData();
if (taskData?.lastStatus !== 'RUNNING') {
if (timestamp === 0) {
core.info('Task stopped, streaming end of logs');
timestamp = Date.now();
}
if (timestamp !== 0 && Date.now() - timestamp < 30000) {
core.info('Task status is not RUNNING for 30 seconds, last query for logs');
readingLogs = false;
}
}
const records = await kinesis
.getRecords({
ShardIterator: iterator,
})
.promise();
iterator = records.NextShardIterator || '';
if (records.Records.length > 0 && iterator) {
for (let index = 0; index < records.Records.length; index++) {
const json = JSON.parse(
zlib.gunzipSync(Buffer.from(records.Records[index].Data as string, 'base64')).toString('utf8'),
);
if (json.messageType === 'DATA_MESSAGE') {
for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) {
if (json.logEvents[logEventsIndex].message.includes(taskDef.logid)) {
core.info('End of task logs');
readingLogs = false;
} else {
core.info(json.logEvents[logEventsIndex].message);
}
}
}
}
}
}
}
static async cleanupResources(CF, taskDef) {
await CF.deleteStack({
StackName: taskDef.taskDefStackName,
}).promise();
await CF.deleteStack({
StackName: taskDef.taskDefStackNameTTL,
}).promise();
await CF.waitFor('stackDeleteComplete', {
StackName: taskDef.taskDefStackName,
}).promise();
// Currently too slow and causes too much waiting
await CF.waitFor('stackDeleteComplete', {
StackName: taskDef.taskDefStackNameTTL,
}).promise();
core.info('Cleanup complete');
}
static onlog(batch) {
for (const log of batch) {
core.info(`log: ${log}`);
}
}
}
export default AWS;

View File

@@ -1,14 +1,22 @@
import Versioning from './versioning';
import UnityVersioning from './unity-versioning';
import AndroidVersioning from './android-versioning';
import BuildParameters from './build-parameters';
import Input from './input';
import Platform from './platform';
const determineVersion = jest.spyOn(Versioning, 'determineVersion').mockImplementation(async () => '1.3.37');
// Todo - Don't use process.env directly, that's what the input model class is for.
const testLicense =
'<?xml version="1.0" encoding="UTF-8"?><root>\n <License id="Terms">\n <MachineBindings>\n <Binding Key="1" Value="576562626572264761624c65526f7578"/>\n <Binding Key="2" Value="576562626572264761624c65526f7578"/>\n </MachineBindings>\n <MachineID Value="D7nTUnjNAmtsUMcnoyrqkgIbYdM="/>\n <SerialHash Value="2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80"/>\n <Features>\n <Feature Value="33"/>\n <Feature Value="1"/>\n <Feature Value="12"/>\n <Feature Value="2"/>\n <Feature Value="24"/>\n <Feature Value="3"/>\n <Feature Value="36"/>\n <Feature Value="17"/>\n <Feature Value="19"/>\n <Feature Value="62"/>\n </Features>\n <DeveloperData Value="AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg=="/>\n <SerialMasked Value="F4-BGRX-XD4E-ZCWV-C5JW-XXXX"/>\n <StartDate Value="2021-02-08T00:00:00"/>\n <UpdateDate Value="2021-02-09T00:34:57"/>\n <InitialActivationDate Value="2021-02-08T00:34:56"/>\n <LicenseVersion Value="6.x"/>\n <ClientProvidedVersion Value="2018.4.30f1"/>\n <AlwaysOnline Value="false"/>\n <Entitlements>\n <Entitlement Ns="unity_editor" Tag="UnityPersonal" Type="EDITOR" ValidTo="9999-12-31T00:00:00"/>\n <Entitlement Ns="unity_editor" Tag="DarkSkin" Type="EDITOR_FEATURE" ValidTo="9999-12-31T00:00:00"/>\n </Entitlements>\n </License>\n<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#Terms"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>';
process.env.UNITY_LICENSE = testLicense;
const determineVersion = jest.spyOn(Versioning, 'determineBuildVersion').mockImplementation(async () => '1.3.37');
const determineUnityVersion = jest
.spyOn(UnityVersioning, 'determineUnityVersion')
.mockImplementation(() => '2019.2.11f1');
const determineSdkManagerParameters = jest
.spyOn(AndroidVersioning, 'determineSdkManagerParameters')
.mockImplementation(() => 'platforms;android-30');
afterEach(() => {
jest.clearAllMocks();
@@ -33,33 +41,36 @@ describe('BuildParameters', () => {
it('returns the android version code with provided input', async () => {
const mockValue = '42';
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidVersionCode: mockValue }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidVersionCode: mockValue }));
});
it('returns the android version code from version by default', async () => {
const mockValue = '';
jest.spyOn(Input, 'androidVersionCode', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidVersionCode: 1003037 }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidVersionCode: 1003037 }));
});
it('returns the platform', async () => {
it('determines the android sdk manager parameters only once', async () => {
await BuildParameters.create();
expect(determineSdkManagerParameters).toHaveBeenCalledTimes(1);
});
it('returns the targetPlatform', async () => {
const mockValue = 'somePlatform';
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ platform: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ targetPlatform: mockValue }));
});
it('returns the project path', async () => {
const mockValue = 'path/to/project';
jest.spyOn(Input, 'projectPath', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ projectPath: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ projectPath: mockValue }));
});
it('returns the build name', async () => {
const mockValue = 'someBuildName';
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildName: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildName: mockValue }));
});
it('returns the build path', async () => {
@@ -68,15 +79,13 @@ describe('BuildParameters', () => {
const expectedBuildPath = `${mockPath}/${mockPlatform}`;
jest.spyOn(Input, 'buildsPath', 'get').mockReturnValue(mockPath);
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockPlatform);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildPath: expectedBuildPath }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildPath: expectedBuildPath }));
});
it('returns the build file', async () => {
const mockValue = 'someBuildName';
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildFile: mockValue }));
});
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
@@ -84,7 +93,7 @@ describe('BuildParameters', () => {
async (targetPlatform) => {
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
await expect(BuildParameters.create()).resolves.toEqual(
expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildFile: `${targetPlatform}.exe` }),
);
},
@@ -94,7 +103,7 @@ describe('BuildParameters', () => {
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(false);
await expect(BuildParameters.create()).resolves.toEqual(
expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildFile: `${targetPlatform}.apk` }),
);
});
@@ -103,7 +112,7 @@ describe('BuildParameters', () => {
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(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ buildFile: `${targetPlatform}.aab` }),
);
});
@@ -111,53 +120,51 @@ describe('BuildParameters', () => {
it('returns the build method', async () => {
const mockValue = 'Namespace.ClassName.BuildMethod';
jest.spyOn(Input, 'buildMethod', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildMethod: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ buildMethod: mockValue }));
});
it('returns the android keystore name', async () => {
const mockValue = 'keystore.keystore';
jest.spyOn(Input, 'androidKeystoreName', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidKeystoreName: mockValue }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidKeystoreName: mockValue }));
});
it('returns the android keystore base64-encoded content', async () => {
const mockValue = 'secret';
jest.spyOn(Input, 'androidKeystoreBase64', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidKeystoreBase64: mockValue }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidKeystoreBase64: mockValue }));
});
it('returns the android keystore pass', async () => {
const mockValue = 'secret';
jest.spyOn(Input, 'androidKeystorePass', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidKeystorePass: mockValue }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidKeystorePass: mockValue }));
});
it('returns the android keyalias name', async () => {
const mockValue = 'secret';
jest.spyOn(Input, 'androidKeyaliasName', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidKeyaliasName: mockValue }),
);
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidKeyaliasName: mockValue }));
});
it('returns the android keyalias pass', async () => {
const mockValue = 'secret';
jest.spyOn(Input, 'androidKeyaliasPass', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidKeyaliasPass: mockValue }),
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ androidKeyaliasPass: mockValue }));
});
it('returns the android target sdk version', async () => {
const mockValue = 'AndroidApiLevelAuto';
jest.spyOn(Input, 'androidTargetSdkVersion', 'get').mockReturnValue(mockValue);
expect(BuildParameters.create()).resolves.toEqual(
expect.objectContaining({ androidTargetSdkVersion: mockValue }),
);
});
it('returns the custom parameters', async () => {
const mockValue = '-profile SomeProfile -someBoolean -someValue exampleValue';
jest.spyOn(Input, 'customParameters', 'get').mockReturnValue(mockValue);
await expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ customParameters: mockValue }));
expect(BuildParameters.create()).resolves.toEqual(expect.objectContaining({ customParameters: mockValue }));
});
});
});

View File

@@ -1,25 +1,90 @@
import { customAlphabet } from 'nanoid';
import * as core from '@actions/core';
import AndroidVersioning from './android-versioning';
import CloudRunnerConstants from './cloud-runner/services/cloud-runner-constants';
import CloudRunnerNamespace from './cloud-runner/services/cloud-runner-namespace';
import Input from './input';
import Platform from './platform';
import UnityVersioning from './unity-versioning';
import Versioning from './versioning';
class BuildParameters {
static async create() {
public editorVersion!: string;
public customImage!: string;
public unitySerial!: string;
public runnerTempPath: string | undefined;
public targetPlatform!: string;
public projectPath!: string;
public buildName!: string;
public buildPath!: string;
public buildFile!: string;
public buildMethod!: string;
public buildVersion!: string;
public androidVersionCode!: string;
public androidKeystoreName!: string;
public androidKeystoreBase64!: string;
public androidKeystorePass!: string;
public androidKeyaliasName!: string;
public androidKeyaliasPass!: string;
public androidTargetSdkVersion!: string;
public androidSdkManagerParameters!: string;
public customParameters!: string;
public sshAgent!: string;
public cloudRunnerCluster!: string;
public awsBaseStackName!: string;
public gitPrivateToken!: string;
public remoteBuildCluster!: string;
public awsStackName!: string;
public kubeConfig!: string;
public githubToken!: string;
public cloudRunnerMemory!: string;
public cloudRunnerCpu!: string;
public kubeVolumeSize!: string;
public kubeVolume!: string;
public chownFilesTo!: string;
public postBuildSteps!: string;
public preBuildSteps!: string;
public customJob!: string;
public runNumber!: string;
public branch!: string;
public githubRepo!: string;
public gitSha!: string;
public logId!: string;
public buildGuid!: string;
static async create(): Promise<BuildParameters> {
const buildFile = this.parseBuildFile(Input.buildName, Input.targetPlatform, Input.androidAppBundle);
const unityVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
const buildVersion = await Versioning.determineVersion(Input.versioningStrategy, Input.specifiedVersion);
const editorVersion = UnityVersioning.determineUnityVersion(Input.projectPath, Input.unityVersion);
const buildVersion = await Versioning.determineBuildVersion(Input.versioningStrategy, Input.specifiedVersion);
const androidVersionCode = AndroidVersioning.determineVersionCode(buildVersion, Input.androidVersionCode);
const androidSdkManagerParameters = AndroidVersioning.determineSdkManagerParameters(Input.androidTargetSdkVersion);
// Todo - Don't use process.env directly, that's what the input model class is for.
// ---
let unitySerial = '';
if (!process.env.UNITY_SERIAL) {
//No serial was present so it is a personal license that we need to convert
if (!process.env.UNITY_LICENSE) {
throw new Error(`Missing Unity License File and no Serial was found. If this
is a personal license, make sure to follow the activation
steps and set the UNITY_LICENSE GitHub secret or enter a Unity
serial number inside the UNITY_SERIAL GitHub secret.`);
}
unitySerial = this.getSerialFromLicenseFile(process.env.UNITY_LICENSE);
} else {
unitySerial = process.env.UNITY_SERIAL!;
}
core.setSecret(unitySerial);
// ---
return {
version: unityVersion,
editorVersion,
customImage: Input.customImage,
unitySerial,
runnerTempPath: process.env.RUNNER_TEMP,
platform: Input.targetPlatform,
targetPlatform: Input.targetPlatform,
projectPath: Input.projectPath,
buildName: Input.buildName,
buildPath: `${Input.buildsPath}/${Input.targetPlatform}`,
@@ -32,16 +97,32 @@ class BuildParameters {
androidKeystorePass: Input.androidKeystorePass,
androidKeyaliasName: Input.androidKeyaliasName,
androidKeyaliasPass: Input.androidKeyaliasPass,
androidTargetSdkVersion: Input.androidTargetSdkVersion,
androidSdkManagerParameters,
customParameters: Input.customParameters,
sshAgent: Input.sshAgent,
gitPrivateToken: await Input.gitPrivateToken(),
chownFilesTo: Input.chownFilesTo,
remoteBuildCluster: Input.remoteBuildCluster,
awsStackName: Input.awsStackName,
cloudRunnerCluster: Input.cloudRunnerCluster,
awsBaseStackName: Input.awsBaseStackName,
kubeConfig: Input.kubeConfig,
githubToken: Input.githubToken,
remoteBuildMemory: Input.remoteBuildMemory,
remoteBuildCpu: Input.remoteBuildCpu,
githubToken: await Input.githubToken(),
cloudRunnerMemory: Input.cloudRunnerMemory,
cloudRunnerCpu: Input.cloudRunnerCpu,
kubeVolumeSize: Input.kubeVolumeSize,
kubeVolume: Input.kubeVolume,
postBuildSteps: Input.postBuildSteps,
preBuildSteps: Input.preBuildSteps,
customJob: Input.customJob,
runNumber: Input.runNumber,
branch: await Input.branch(),
// Todo - move this out of UserInput and into some class that determines additional information (as needed)
githubRepo: await Input.githubRepo(),
remoteBuildCluster: Input.cloudRunnerCluster,
awsStackName: Input.awsBaseStackName,
gitSha: Input.gitSha,
logId: customAlphabet(CloudRunnerConstants.alphabet, 9)(),
buildGuid: CloudRunnerNamespace.generateBuildName(Input.runNumber, Input.targetPlatform),
};
}
@@ -56,6 +137,18 @@ class BuildParameters {
return filename;
}
static getSerialFromLicenseFile(license) {
const startKey = `<DeveloperData Value="`;
const endKey = `"/>`;
const startIndex = license.indexOf(startKey) + startKey.length;
if (startIndex < 0) {
throw new Error(`License File was corrupted, unable to locate serial`);
}
const endIndex = license.indexOf(endKey, startIndex);
// Slice off the first 4 characters as they are garbage values
return Buffer.from(license.slice(startIndex, endIndex), 'base64').toString('binary').slice(4);
}
}
export default BuildParameters;

View File

@@ -0,0 +1,23 @@
const targets = new Array();
export function CliFunction(key: string, description: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
targets.push({
target,
propertyKey,
descriptor,
key,
description,
});
};
}
export function GetCliFunctions(key) {
return targets.find((x) => x.key === key);
}
export function GetAllCliModes() {
return targets.map((x) => {
return {
key: x.key,
description: x.description,
};
});
}

88
src/model/cli/cli.ts Normal file
View File

@@ -0,0 +1,88 @@
import { Command } from 'commander-ts';
import { BuildParameters, CloudRunner, ImageTag, Input } from '..';
import * as core from '@actions/core';
import { ActionYamlReader } from '../input-readers/action-yaml';
import CloudRunnerLogger from '../cloud-runner/services/cloud-runner-logger';
import { CliFunction, GetAllCliModes, GetCliFunctions } from './cli-decorator';
import { RemoteClientLogger } from './remote-client/remote-client-services/remote-client-logger';
import { CloudRunnerState } from '../cloud-runner/state/cloud-runner-state';
import { SetupCloudRunnerRepository } from './remote-client/setup-cloud-runner-repository';
import * as SDK from 'aws-sdk';
export class CLI {
static async RunCli(options: any): Promise<void> {
Input.githubInputEnabled = false;
const results = GetCliFunctions(options.mode);
if (results === undefined || results.length === 0) {
throw new Error('no CLI mode found');
}
CloudRunnerLogger.log(`Entrypoint: ${results.key}`);
options.versioning = 'None';
Input.cliOptions = options;
return await results.target[results.propertyKey]();
}
static isCliMode(options: any) {
return options.mode !== undefined && options.mode !== '';
}
public static SetupCli() {
const program = new Command();
program.version('0.0.1');
const properties = Object.getOwnPropertyNames(Input);
core.info(`\n`);
core.info(`INPUT:`);
const actionYamlReader: ActionYamlReader = new ActionYamlReader();
for (const element of properties) {
program.option(`--${element} <${element}>`, actionYamlReader.GetActionYamlValue(element));
if (Input[element] !== undefined && Input[element] !== '' && typeof Input[element] !== `function`) {
core.info(`${element} ${Input[element]}`);
}
}
core.info(`\n`);
program.option(
'-m, --mode <mode>',
GetAllCliModes()
.map((x) => `${x.key} (${x.description})`)
.join(` | `),
);
program.parse(process.argv);
return program.opts();
}
@CliFunction(`cli`, `runs a cloud runner build`)
public static async CLIBuild(): Promise<string> {
const buildParameter = await BuildParameters.create();
const baseImage = new ImageTag(buildParameter);
return await CloudRunner.run(buildParameter, baseImage.toString());
}
@CliFunction(`remote-cli`, `sets up a repository, usually before a game-ci build`)
static async runRemoteClientJob() {
const buildParameter = JSON.parse(process.env.BUILD_PARAMETERS || '{}');
RemoteClientLogger.log(`Build Params:
${JSON.stringify(buildParameter, undefined, 4)}
`);
CloudRunnerState.setup(buildParameter);
await SetupCloudRunnerRepository.run();
}
@CliFunction(`cach-push`, `push to cache`)
static async cachePush() {}
@CliFunction(`cach-pull`, `pull from cache`)
static async cachePull() {}
@CliFunction(`garbage-collect-aws`, `garbage collect aws`)
static async garbageCollectAws() {
process.env.AWS_REGION = Input.region;
const CF = new SDK.CloudFormation();
const stacks = await CF.listStacks().promise();
CloudRunnerLogger.log(JSON.stringify(stacks, undefined, 4));
}
}

View File

@@ -0,0 +1,117 @@
import { assert } from 'console';
import fs from 'fs';
import path from 'path';
import { Input } from '../../..';
import CloudRunnerLogger from '../../../cloud-runner/services/cloud-runner-logger';
import { CloudRunnerState } from '../../../cloud-runner/state/cloud-runner-state';
import { CloudRunnerSystem } from './cloud-runner-system';
import { LFSHashing } from './lfs-hashing';
import { RemoteClientLogger } from './remote-client-logger';
export class Caching {
public static async PushToCache(cacheFolder: string, sourceFolder: string, cacheKey: string) {
const startPath = process.cwd();
try {
if (!fs.existsSync(cacheFolder)) {
await CloudRunnerSystem.Run(`mkdir -p ${cacheFolder}`);
}
process.chdir(path.resolve(sourceFolder, '..'));
if (Input.cloudRunnerTests) {
CloudRunnerLogger.log(
`Hashed cache folder ${await LFSHashing.hashAllFiles(sourceFolder)} ${sourceFolder} ${path.basename(
sourceFolder,
)}`,
);
}
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`ls ${path.basename(sourceFolder)}`);
}
await CloudRunnerSystem.Run(`zip ${cacheKey}.zip ${path.basename(sourceFolder)}`);
assert(fs.existsSync(`${cacheKey}.zip`), 'cache zip exists');
assert(fs.existsSync(path.basename(sourceFolder)), 'source folder exists');
await CloudRunnerSystem.Run(`mv ${cacheKey}.zip ${cacheFolder}`);
RemoteClientLogger.log(`moved ${cacheKey}.zip to ${cacheFolder}`);
assert(fs.existsSync(`${path.join(cacheFolder, cacheKey)}.zip`), 'cache zip exists inside cache folder');
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`ls ${cacheFolder}`);
}
} catch (error) {
process.chdir(`${startPath}`);
throw error;
}
process.chdir(`${startPath}`);
}
public static async PullFromCache(cacheFolder: string, destinationFolder: string, cacheKey: string = ``) {
const startPath = process.cwd();
RemoteClientLogger.log(`Caching for ${path.basename(destinationFolder)}`);
try {
if (!fs.existsSync(cacheFolder)) {
fs.mkdirSync(cacheFolder);
}
if (!fs.existsSync(destinationFolder)) {
fs.mkdirSync(destinationFolder);
}
const latestInBranch = await (await CloudRunnerSystem.Run(`ls -t "${cacheFolder}" | grep .zip$ | head -1`))
.replace(/\n/g, ``)
.replace('.zip', '');
process.chdir(cacheFolder);
const cacheSelection = cacheKey !== `` && fs.existsSync(`${cacheKey}.zip`) ? cacheKey : latestInBranch;
await CloudRunnerLogger.log(`cache key ${cacheKey} selection ${cacheSelection}`);
if (fs.existsSync(`${cacheSelection}.zip`)) {
const resultsFolder = `results${CloudRunnerState.buildParams.buildGuid}`;
await CloudRunnerSystem.Run(`mkdir -p ${resultsFolder}`);
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`tree ${destinationFolder}`);
}
RemoteClientLogger.log(`cache item exists ${cacheFolder}/${cacheSelection}.zip`);
assert(`${fs.existsSync(destinationFolder)}`);
assert(`${fs.existsSync(`${cacheSelection}.zip`)}`);
const fullResultsFolder = path.join(cacheFolder, resultsFolder);
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`tree ${cacheFolder}`);
}
await CloudRunnerSystem.Run(`unzip ${cacheSelection}.zip -d ${path.basename(resultsFolder)}`);
RemoteClientLogger.log(`cache item extracted to ${fullResultsFolder}`);
assert(`${fs.existsSync(fullResultsFolder)}`);
const destinationParentFolder = path.resolve(destinationFolder, '..');
if (fs.existsSync(destinationFolder)) {
fs.rmSync(destinationFolder, { recursive: true, force: true });
}
await CloudRunnerSystem.Run(
`mv "${fullResultsFolder}/${path.basename(destinationFolder)}" "${destinationParentFolder}"`,
);
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`tree ${destinationParentFolder}`);
}
} else {
RemoteClientLogger.logWarning(`cache item ${cacheKey} doesn't exist ${destinationFolder}`);
if (cacheSelection !== ``) {
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`tree ${cacheFolder}`);
}
RemoteClientLogger.logWarning(`cache item ${cacheKey}.zip doesn't exist ${destinationFolder}`);
throw new Error(`Failed to get cache item, but cache hit was found: ${cacheSelection}`);
}
}
} catch (error) {
process.chdir(`${startPath}`);
throw error;
}
process.chdir(`${startPath}`);
}
public static handleCachePurging() {
if (process.env.PURGE_REMOTE_BUILDER_CACHE !== undefined) {
RemoteClientLogger.log(`purging ${CloudRunnerState.purgeRemoteCaching}`);
fs.rmdirSync(CloudRunnerState.cacheFolder, { recursive: true });
}
}
}

View File

@@ -0,0 +1,37 @@
import { exec } from 'child_process';
import { RemoteClientLogger } from './remote-client-logger';
export class CloudRunnerSystem {
public static async Run(command: string, suppressError = false) {
for (const element of command.split(`\n`)) {
RemoteClientLogger.log(element);
}
return await new Promise<string>((promise) => {
let output = '';
const child = exec(command, (error, stdout, stderr) => {
if (error && !suppressError) {
throw error;
}
if (stderr) {
const diagnosticOutput = `${stderr.toString()}`;
RemoteClientLogger.logCliDiagnostic(diagnosticOutput);
output += diagnosticOutput;
return;
}
const outputChunk = `${stdout}`;
output += outputChunk;
});
child.on('close', function (code) {
RemoteClientLogger.log(`[Exit code ${code}]`);
if (code !== 0 && !suppressError) {
throw new Error(output);
}
const outputLines = output.split(`\n`);
for (const element of outputLines) {
RemoteClientLogger.log(element);
}
promise(output);
});
});
}
}

View File

@@ -0,0 +1,42 @@
import path from 'path';
import { CloudRunnerState } from '../../../cloud-runner/state/cloud-runner-state';
import { CloudRunnerSystem } from './cloud-runner-system';
import fs from 'fs';
import { assert } from 'console';
import { Input } from '../../..';
import { RemoteClientLogger } from './remote-client-logger';
export class LFSHashing {
public static async createLFSHashFiles() {
try {
await CloudRunnerSystem.Run(`git lfs ls-files -l | cut -d ' ' -f1 | sort > .lfs-assets-guid`);
await CloudRunnerSystem.Run(`md5sum .lfs-assets-guid > .lfs-assets-guid-sum`);
assert(fs.existsSync(`.lfs-assets-guid-sum`));
assert(fs.existsSync(`.lfs-assets-guid`));
const lfsHashes = {
lfsGuid: fs
.readFileSync(`${path.join(CloudRunnerState.repoPathFull, `.lfs-assets-guid`)}`, 'utf8')
.replace(/\n/g, ``),
lfsGuidSum: fs
.readFileSync(`${path.join(CloudRunnerState.repoPathFull, `.lfs-assets-guid-sum`)}`, 'utf8')
.replace(/\n/g, ``),
};
if (Input.cloudRunnerTests) {
RemoteClientLogger.log(lfsHashes.lfsGuid);
RemoteClientLogger.log(lfsHashes.lfsGuidSum);
}
return lfsHashes;
} catch (error) {
throw error;
}
}
public static async hashAllFiles(folder: string) {
const startPath = process.cwd();
process.chdir(folder);
const result = await (await CloudRunnerSystem.Run(`find -type f -exec md5sum "{}" + | sort | md5sum`))
.replace(/\n/g, '')
.split(` `)[0];
process.chdir(startPath);
return result;
}
}

View File

@@ -0,0 +1,19 @@
import CloudRunnerLogger from '../../../cloud-runner/services/cloud-runner-logger';
export class RemoteClientLogger {
public static log(message: string) {
CloudRunnerLogger.log(`[Client] ${message}`);
}
public static logCliError(message: string) {
CloudRunnerLogger.log(`[Client][Error] ${message}`);
}
public static logCliDiagnostic(message: string) {
CloudRunnerLogger.log(`[Client][Diagnostic] ${message}`);
}
public static logWarning(message) {
CloudRunnerLogger.logWarning(message);
}
}

View File

@@ -0,0 +1,81 @@
import fs from 'fs';
import { CloudRunnerState } from '../../cloud-runner/state/cloud-runner-state';
import { Caching } from './remote-client-services/caching';
import { LFSHashing } from './remote-client-services/lfs-hashing';
import { CloudRunnerSystem } from './remote-client-services/cloud-runner-system';
import { Input } from '../..';
import { RemoteClientLogger } from './remote-client-services/remote-client-logger';
import path from 'path';
import { assert } from 'console';
export class SetupCloudRunnerRepository {
public static async run() {
try {
await CloudRunnerSystem.Run(`mkdir -p ${CloudRunnerState.buildPathFull}`);
await CloudRunnerSystem.Run(`mkdir -p ${CloudRunnerState.repoPathFull}`);
await CloudRunnerSystem.Run(`mkdir -p ${CloudRunnerState.cacheFolderFull}`);
process.chdir(CloudRunnerState.repoPathFull);
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`ls -lh`);
await CloudRunnerSystem.Run(`tree`);
}
await SetupCloudRunnerRepository.cloneRepoWithoutLFSFiles();
if (Input.cloudRunnerTests) {
await CloudRunnerSystem.Run(`ls -lh`);
await CloudRunnerSystem.Run(`tree`);
}
const lfsHashes = await LFSHashing.createLFSHashFiles();
if (fs.existsSync(CloudRunnerState.libraryFolderFull)) {
RemoteClientLogger.logWarning(`!Warning!: The Unity library was included in the git repository`);
}
await Caching.PullFromCache(
CloudRunnerState.lfsCacheFolderFull,
CloudRunnerState.lfsDirectoryFull,
`${lfsHashes.lfsGuid}`,
);
await SetupCloudRunnerRepository.pullLatestLFS();
await Caching.PushToCache(
CloudRunnerState.lfsCacheFolderFull,
CloudRunnerState.lfsDirectoryFull,
`${lfsHashes.lfsGuid}`,
);
await Caching.PullFromCache(CloudRunnerState.libraryCacheFolderFull, CloudRunnerState.libraryFolderFull);
Caching.handleCachePurging();
} catch (error) {
throw error;
}
}
private static async cloneRepoWithoutLFSFiles() {
try {
process.chdir(`${CloudRunnerState.repoPathFull}`);
RemoteClientLogger.log(`Initializing source repository for cloning with caching of LFS files`);
await CloudRunnerSystem.Run(`git config --global advice.detachedHead false`);
RemoteClientLogger.log(`Cloning the repository being built:`);
await CloudRunnerSystem.Run(`git lfs install --skip-smudge`);
await CloudRunnerSystem.Run(
`git clone -b ${CloudRunnerState.branchName} ${CloudRunnerState.targetBuildRepoUrl} ${path.resolve(
`..`,
path.basename(CloudRunnerState.repoPathFull),
)}`,
);
assert(fs.existsSync(`.git`));
RemoteClientLogger.log(`${CloudRunnerState.buildParams.branch}`);
await CloudRunnerSystem.Run(`git checkout ${CloudRunnerState.buildParams.branch}`);
assert(fs.existsSync(path.join(`.git`, `lfs`)), 'LFS folder should not exist before caching');
RemoteClientLogger.log(`Checked out ${process.env.GITHUB_SHA}`);
} catch (error) {
throw error;
}
}
private static async pullLatestLFS() {
await CloudRunnerSystem.Run(`ls -lh ${CloudRunnerState.lfsDirectoryFull}/..`);
process.chdir(CloudRunnerState.repoPathFull);
await CloudRunnerSystem.Run(`git lfs pull`);
RemoteClientLogger.log(`pulled latest LFS files`);
assert(fs.existsSync(CloudRunnerState.lfsDirectoryFull));
await CloudRunnerSystem.Run(`ls -lh ${CloudRunnerState.lfsDirectoryFull}/..`);
}
}

View File

@@ -0,0 +1,106 @@
import CloudRunnerLogger from '../services/cloud-runner-logger';
import * as core from '@actions/core';
import * as SDK from 'aws-sdk';
import * as fs from 'fs';
import path from 'path';
const crypto = require('crypto');
export class AWSBaseStack {
constructor(baseStackName: string) {
this.baseStackName = baseStackName;
}
private baseStackName: string;
async setupBaseStack(CF: SDK.CloudFormation) {
const baseStackName = this.baseStackName;
const baseStack = fs.readFileSync(path.join(__dirname, 'cloud-formations', 'base-setup.yml'), 'utf8');
// Cloud Formation Input
const describeStackInput: SDK.CloudFormation.DescribeStacksInput = {
StackName: baseStackName,
};
const parametersWithoutHash: SDK.CloudFormation.Parameter[] = [
{ ParameterKey: 'EnvironmentName', ParameterValue: baseStackName },
];
const parametersHash = crypto
.createHash('md5')
.update(baseStack + JSON.stringify(parametersWithoutHash))
.digest('hex');
const parameters: SDK.CloudFormation.Parameter[] = [
...parametersWithoutHash,
...[{ ParameterKey: 'Version', ParameterValue: parametersHash }],
];
const updateInput: SDK.CloudFormation.UpdateStackInput = {
StackName: baseStackName,
TemplateBody: baseStack,
Parameters: parameters,
Capabilities: ['CAPABILITY_IAM'],
};
const createStackInput: SDK.CloudFormation.CreateStackInput = {
StackName: baseStackName,
TemplateBody: baseStack,
Parameters: parameters,
Capabilities: ['CAPABILITY_IAM'],
};
const stacks = await CF.listStacks({
StackStatusFilter: ['UPDATE_COMPLETE', 'CREATE_COMPLETE', 'ROLLBACK_COMPLETE'],
}).promise();
const stackNames = stacks.StackSummaries?.map((x) => x.StackName) || [];
const stackExists: Boolean = stackNames.includes(baseStackName) || false;
const describeStack = async () => {
return await CF.describeStacks(describeStackInput).promise();
};
try {
if (!stackExists) {
CloudRunnerLogger.log(`${baseStackName} stack does not exist (${JSON.stringify(stackNames)})`);
await CF.createStack(createStackInput).promise();
CloudRunnerLogger.log(`created stack (version: ${parametersHash})`);
}
const CFState = await describeStack();
let stack = CFState.Stacks?.[0];
if (!stack) {
throw new Error(`Base stack doesn't exist, even after creation, stackExists check: ${stackExists}`);
}
const stackVersion = stack.Parameters?.find((x) => x.ParameterKey === 'Version')?.ParameterValue;
if (stack.StackStatus === 'CREATE_IN_PROGRESS') {
await CF.waitFor('stackCreateComplete', describeStackInput).promise();
}
if (stackExists) {
CloudRunnerLogger.log(`Base stack exists (version: ${stackVersion}, local version: ${parametersHash})`);
if (parametersHash !== stackVersion) {
CloudRunnerLogger.log(`Attempting update of base stack`);
try {
await CF.updateStack(updateInput).promise();
} catch (error: any) {
if (error['message'].includes('No updates are to be performed')) {
CloudRunnerLogger.log(`No updates are to be performed`);
} else {
CloudRunnerLogger.log(`Update Failed (Stack name: ${baseStackName})`);
CloudRunnerLogger.log(error['message']);
}
CloudRunnerLogger.log(`Continuing...`);
}
} else {
CloudRunnerLogger.log(`No update required`);
}
stack = (await describeStack()).Stacks?.[0];
if (!stack) {
throw new Error(
`Base stack doesn't exist, even after updating and creation, stackExists check: ${stackExists}`,
);
}
if (stack.StackStatus === 'UPDATE_IN_PROGRESS') {
await CF.waitFor('stackUpdateComplete', describeStackInput).promise();
}
}
CloudRunnerLogger.log('base stack is now ready');
} catch (error) {
core.error(JSON.stringify(await describeStack(), undefined, 4));
throw error;
}
}
}

View File

@@ -0,0 +1,16 @@
import CloudRunnerLogger from '../services/cloud-runner-logger';
import * as SDK from 'aws-sdk';
import * as core from '@actions/core';
import { Input } from '../..';
export class AWSError {
static async handleStackCreationFailure(error: any, CF: SDK.CloudFormation, taskDefStackName: string) {
CloudRunnerLogger.log('aws error: ');
core.error(JSON.stringify(error, undefined, 4));
if (Input.cloudRunnerTests) {
CloudRunnerLogger.log('Getting events and resources for task stack');
const events = (await CF.describeStackEvents({ StackName: taskDefStackName }).promise()).StackEvents;
CloudRunnerLogger.log(JSON.stringify(events, undefined, 4));
}
}
}

View File

@@ -0,0 +1,141 @@
import * as SDK from 'aws-sdk';
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
import CloudRunnerSecret from '../services/cloud-runner-secret';
import { AWSTemplates } from './aws-templates';
import CloudRunnerLogger from '../services/cloud-runner-logger';
import { AWSError } from './aws-error';
export class AWSJobStack {
private baseStackName: string;
constructor(baseStackName: string) {
this.baseStackName = baseStackName;
}
public async setupCloudFormations(
CF: SDK.CloudFormation,
buildGuid: string,
image: string,
entrypoint: string[],
commands: string,
mountdir: string,
workingdir: string,
secrets: CloudRunnerSecret[],
): Promise<CloudRunnerAWSTaskDef> {
const taskDefStackName = `${this.baseStackName}-${buildGuid}`;
let taskDefCloudFormation = AWSTemplates.readTaskCloudFormationTemplate();
for (const secret of secrets) {
secret.ParameterKey = `${buildGuid.replace(/[^\dA-Za-z]/g, '')}${secret.ParameterKey.replace(
/[^\dA-Za-z]/g,
'',
)}`;
if (typeof secret.ParameterValue == 'number') {
secret.ParameterValue = `${secret.ParameterValue}`;
}
if (!secret.ParameterValue || secret.ParameterValue === '') {
secrets = secrets.filter((x) => x !== secret);
continue;
}
taskDefCloudFormation = AWSTemplates.insertAtTemplate(
taskDefCloudFormation,
'p1 - input',
AWSTemplates.getParameterTemplate(secret.ParameterKey),
);
taskDefCloudFormation = AWSTemplates.insertAtTemplate(
taskDefCloudFormation,
'p2 - secret',
AWSTemplates.getSecretTemplate(`${secret.ParameterKey}`),
);
taskDefCloudFormation = AWSTemplates.insertAtTemplate(
taskDefCloudFormation,
'p3 - container def',
AWSTemplates.getSecretDefinitionTemplate(secret.EnvironmentVariable, secret.ParameterKey),
);
}
const secretsMappedToCloudFormationParameters = secrets.map((x) => {
return { ParameterKey: x.ParameterKey.replace(/[^\dA-Za-z]/g, ''), ParameterValue: x.ParameterValue };
});
const parameters = [
{
ParameterKey: 'EnvironmentName',
ParameterValue: this.baseStackName,
},
{
ParameterKey: 'ImageUrl',
ParameterValue: image,
},
{
ParameterKey: 'ServiceName',
ParameterValue: taskDefStackName,
},
{
ParameterKey: 'Command',
ParameterValue: 'echo "this template should be overwritten when running a task"',
},
{
ParameterKey: 'EntryPoint',
ParameterValue: entrypoint.join(','),
},
{
ParameterKey: 'WorkingDirectory',
ParameterValue: workingdir,
},
{
ParameterKey: 'EFSMountDirectory',
ParameterValue: mountdir,
},
...secretsMappedToCloudFormationParameters,
];
let previousStackExists = true;
while (previousStackExists) {
previousStackExists = false;
const stacks = await CF.listStacks().promise();
if (!stacks.StackSummaries) {
throw new Error('Faild to get stacks');
}
for (let index = 0; index < stacks.StackSummaries.length; index++) {
const element = stacks.StackSummaries[index];
if (element.StackName === taskDefStackName && element.StackStatus !== 'DELETE_COMPLETE') {
previousStackExists = true;
CloudRunnerLogger.log(`Previous stack still exists: ${JSON.stringify(element)}`);
}
}
}
try {
await CF.createStack({
StackName: taskDefStackName,
TemplateBody: taskDefCloudFormation,
Capabilities: ['CAPABILITY_IAM'],
Parameters: parameters,
}).promise();
CloudRunnerLogger.log('Creating cloud runner job');
await CF.waitFor('stackCreateComplete', { StackName: taskDefStackName }).promise();
} catch (error) {
await AWSError.handleStackCreationFailure(
error,
CF,
taskDefStackName,
//taskDefCloudFormation,
//parameters,
//secrets,
);
throw error;
}
const taskDefResources = (
await CF.describeStackResources({
StackName: taskDefStackName,
}).promise()
).StackResources;
const baseResources = (await CF.describeStackResources({ StackName: this.baseStackName }).promise()).StackResources;
return {
taskDefStackName,
taskDefCloudFormation,
taskDefResources,
baseResources,
};
}
}

View File

@@ -0,0 +1,228 @@
import * as AWS from 'aws-sdk';
import CloudRunnerEnvironmentVariable from '../services/cloud-runner-environment-variable';
import * as core from '@actions/core';
import CloudRunnerAWSTaskDef from './cloud-runner-aws-task-def';
import * as zlib from 'zlib';
import CloudRunnerLogger from '../services/cloud-runner-logger';
import { Input } from '../..';
import { CloudRunnerState } from '../state/cloud-runner-state';
import { CloudRunnerStatics } from '../cloud-runner-statics';
import { CloudRunnerBuildCommandProcessor } from '../services/cloud-runner-build-command-process';
class AWSTaskRunner {
static async runTask(
taskDef: CloudRunnerAWSTaskDef,
ECS: AWS.ECS,
CF: AWS.CloudFormation,
environment: CloudRunnerEnvironmentVariable[],
buildGuid: string,
commands: string,
) {
const cluster = taskDef.baseResources?.find((x) => x.LogicalResourceId === 'ECSCluster')?.PhysicalResourceId || '';
const taskDefinition =
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'TaskDefinition')?.PhysicalResourceId || '';
const SubnetOne =
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'PublicSubnetOne')?.PhysicalResourceId || '';
const SubnetTwo =
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'PublicSubnetTwo')?.PhysicalResourceId || '';
const ContainerSecurityGroup =
taskDef.baseResources?.find((x) => x.LogicalResourceId === 'ContainerSecurityGroup')?.PhysicalResourceId || '';
const streamName =
taskDef.taskDefResources?.find((x) => x.LogicalResourceId === 'KinesisStream')?.PhysicalResourceId || '';
const task = await ECS.runTask({
cluster,
taskDefinition,
platformVersion: '1.4.0',
overrides: {
containerOverrides: [
{
name: taskDef.taskDefStackName,
environment,
command: ['-c', CloudRunnerBuildCommandProcessor.ProcessCommands(commands, CloudRunnerState.buildParams)],
},
],
},
launchType: 'FARGATE',
networkConfiguration: {
awsvpcConfiguration: {
subnets: [SubnetOne, SubnetTwo],
assignPublicIp: 'ENABLED',
securityGroups: [ContainerSecurityGroup],
},
},
}).promise();
CloudRunnerLogger.log('Cloud runner job is starting');
const taskArn = task.tasks?.[0].taskArn || '';
try {
await ECS.waitFor('tasksRunning', { tasks: [taskArn], cluster }).promise();
} catch (error_) {
const error = error_ as Error;
await new Promise((resolve) => setTimeout(resolve, 3000));
CloudRunnerLogger.log(
`Cloud runner job has ended ${
(await AWSTaskRunner.describeTasks(ECS, cluster, taskArn)).containers?.[0].lastStatus
}`,
);
core.setFailed(error);
core.error(error);
}
CloudRunnerLogger.log(`Cloud runner job is running`);
const output = await this.streamLogsUntilTaskStops(ECS, CF, taskDef, cluster, taskArn, streamName);
const exitCode = (await AWSTaskRunner.describeTasks(ECS, cluster, taskArn)).containers?.[0].exitCode;
CloudRunnerLogger.log(`Cloud runner job exit code ${exitCode}`);
if (exitCode !== 0 && exitCode !== undefined) {
core.error(
`job failed with exit code ${exitCode} ${JSON.stringify(
await ECS.describeTasks({ tasks: [taskArn], cluster }).promise(),
undefined,
4,
)}`,
);
throw new Error(`job failed with exit code ${exitCode}`);
} else {
CloudRunnerLogger.log(`Cloud runner job has finished successfully`);
return output;
}
}
static async describeTasks(ECS: AWS.ECS, clusterName: string, taskArn: string) {
const tasks = await ECS.describeTasks({
cluster: clusterName,
tasks: [taskArn],
}).promise();
if (tasks.tasks?.[0]) {
return tasks.tasks?.[0];
} else {
throw new Error('No task found');
}
}
static async streamLogsUntilTaskStops(
ECS: AWS.ECS,
CF: AWS.CloudFormation,
taskDef: CloudRunnerAWSTaskDef,
clusterName: string,
taskArn: string,
kinesisStreamName: string,
) {
const kinesis = new AWS.Kinesis();
const stream = await AWSTaskRunner.getLogStream(kinesis, kinesisStreamName);
let iterator = await AWSTaskRunner.getLogIterator(kinesis, stream);
CloudRunnerLogger.log(
`Cloud runner job status is ${(await AWSTaskRunner.describeTasks(ECS, clusterName, taskArn))?.lastStatus}`,
);
const logBaseUrl = `https://${Input.region}.console.aws.amazon.com/cloudwatch/home?region=${CF.config.region}#logsV2:log-groups/log-group/${taskDef.taskDefStackName}`;
CloudRunnerLogger.log(`You can also see the logs at AWS Cloud Watch: ${logBaseUrl}`);
let shouldReadLogs = true;
let timestamp: number = 0;
let output = '';
while (shouldReadLogs) {
await new Promise((resolve) => setTimeout(resolve, 1500));
const taskData = await AWSTaskRunner.describeTasks(ECS, clusterName, taskArn);
({ timestamp, shouldReadLogs } = AWSTaskRunner.checkStreamingShouldContinue(taskData, timestamp, shouldReadLogs));
({ iterator, shouldReadLogs, output } = await AWSTaskRunner.handleLogStreamIteration(
kinesis,
iterator,
shouldReadLogs,
taskDef,
output,
));
}
return output;
}
private static async handleLogStreamIteration(
kinesis: AWS.Kinesis,
iterator: string,
shouldReadLogs: boolean,
taskDef: CloudRunnerAWSTaskDef,
output: string,
) {
const records = await kinesis
.getRecords({
ShardIterator: iterator,
})
.promise();
iterator = records.NextShardIterator || '';
({ shouldReadLogs, output } = AWSTaskRunner.logRecords(records, iterator, taskDef, shouldReadLogs, output));
return { iterator, shouldReadLogs, output };
}
private static checkStreamingShouldContinue(taskData: AWS.ECS.Task, timestamp: number, shouldReadLogs: boolean) {
if (taskData?.lastStatus !== 'RUNNING') {
if (timestamp === 0) {
CloudRunnerLogger.log('## Cloud runner job stopped, streaming end of logs');
timestamp = Date.now();
}
if (timestamp !== 0 && Date.now() - timestamp > 30000) {
CloudRunnerLogger.log('## Cloud runner status is not RUNNING for 30 seconds, last query for logs');
shouldReadLogs = false;
}
CloudRunnerLogger.log(`## Status of job: ${taskData.lastStatus}`);
}
return { timestamp, shouldReadLogs };
}
private static logRecords(
records,
iterator: string,
taskDef: CloudRunnerAWSTaskDef,
shouldReadLogs: boolean,
output: string,
) {
if (records.Records.length > 0 && iterator) {
for (let index = 0; index < records.Records.length; index++) {
const json = JSON.parse(
zlib.gunzipSync(Buffer.from(records.Records[index].Data as string, 'base64')).toString('utf8'),
);
if (json.messageType === 'DATA_MESSAGE') {
for (let logEventsIndex = 0; logEventsIndex < json.logEvents.length; logEventsIndex++) {
let message = json.logEvents[logEventsIndex].message;
if (json.logEvents[logEventsIndex].message.includes(`---${CloudRunnerState.buildParams.logId}`)) {
CloudRunnerLogger.log('End of log transmission received');
shouldReadLogs = false;
} else if (message.includes('Rebuilding Library because the asset database could not be found!')) {
core.warning('LIBRARY NOT FOUND!');
}
message = `[${CloudRunnerStatics.logPrefix}] ${message}`;
if (Input.cloudRunnerTests) {
output += message;
}
CloudRunnerLogger.log(message);
}
}
}
}
return { shouldReadLogs, output };
}
private static async getLogStream(kinesis: AWS.Kinesis, kinesisStreamName: string) {
return await kinesis
.describeStream({
StreamName: kinesisStreamName,
})
.promise();
}
private static async getLogIterator(kinesis: AWS.Kinesis, stream) {
return (
(
await kinesis
.getShardIterator({
ShardIteratorType: 'TRIM_HORIZON',
StreamName: stream.StreamDescription.StreamName,
ShardId: stream.StreamDescription.Shards[0].ShardId,
})
.promise()
).ShardIterator || ''
);
}
}
export default AWSTaskRunner;

Some files were not shown because too many files have changed in this diff Show More