mirror of
https://github.com/game-ci/unity-builder.git
synced 2026-01-29 12:19:06 +08:00
Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17c28995b2 | ||
|
|
21c985b8e9 | ||
|
|
e6d3daedbe | ||
|
|
ef74241772 | ||
|
|
3d7e4a8018 | ||
|
|
91da660786 | ||
|
|
f42f7923ed | ||
|
|
22bc9a9bad | ||
|
|
6a53a9e853 | ||
|
|
cccd5074ea | ||
|
|
977683cd5f | ||
|
|
89bdaa5e46 | ||
|
|
24e9c186fd | ||
|
|
92cfb31622 | ||
|
|
67b76584b8 | ||
|
|
3ee15170fd | ||
|
|
3e0842dda0 | ||
|
|
1f8d196ed0 | ||
|
|
e003f9e2ca | ||
|
|
21634107c1 | ||
|
|
196fe8fc5b | ||
|
|
ec0cde0c85 | ||
|
|
72ff2983a1 | ||
|
|
fdf71758a9 | ||
|
|
91ec427695 | ||
|
|
6fb8550919 | ||
|
|
cb913cd286 | ||
|
|
96eeaf940a | ||
|
|
6ece6447b2 | ||
|
|
3523c6a934 | ||
|
|
bf702784d2 | ||
|
|
bdc3a88d22 | ||
|
|
401ddcaae0 | ||
|
|
1245bfefc8 | ||
|
|
229b0d02f8 | ||
|
|
c68bdf8177 | ||
|
|
938926799f | ||
|
|
5efb4868ad | ||
|
|
7749b8862d | ||
|
|
98a56c4169 | ||
|
|
720ee0c896 | ||
|
|
d42c251af3 | ||
|
|
bfe6be7ce2 | ||
|
|
f15f40d265 | ||
|
|
866f364f64 | ||
|
|
a245f08e75 | ||
|
|
21c211bbdd | ||
|
|
3718e05961 | ||
|
|
0159028bb1 | ||
|
|
054c6bfab3 | ||
|
|
8c9ff3249e | ||
|
|
7386c669ad | ||
|
|
ce865270c4 | ||
|
|
7e17091251 | ||
|
|
02ff5bbef2 | ||
|
|
8c177b1bad | ||
|
|
699621ed21 | ||
|
|
44bde7feb9 | ||
|
|
5328bda08e | ||
|
|
34e4b86924 | ||
|
|
e9514b4e37 | ||
|
|
d4d91e75c3 | ||
|
|
2085eff264 | ||
|
|
98a1b078fc | ||
|
|
afef854ea0 | ||
|
|
a0a5de2a83 | ||
|
|
c146049b33 | ||
|
|
e46399169f | ||
|
|
b41026b36e | ||
|
|
cd1d215dfa | ||
|
|
d01e844eea | ||
|
|
40564afbaf | ||
|
|
b6f8040f4a | ||
|
|
22c7d0e516 | ||
|
|
f85e50e499 | ||
|
|
d75d7890d0 | ||
|
|
2e81e61af3 | ||
|
|
ac76e9d562 | ||
|
|
39a160b789 | ||
|
|
e8a2eaad72 | ||
|
|
6f1d03d8a8 | ||
|
|
5ee9c59113 | ||
|
|
03510d4a55 | ||
|
|
ad65b0ece4 | ||
|
|
a513e5b640 | ||
|
|
328b0d8ac0 | ||
|
|
e53dcf13e3 | ||
|
|
3338b392a0 | ||
|
|
7e115b5cc3 | ||
|
|
758108295c | ||
|
|
8684472273 | ||
|
|
38b6a42f5e | ||
|
|
fbeaf77867 | ||
|
|
6f3a2bd992 | ||
|
|
e1eda1e876 | ||
|
|
0088ca3094 | ||
|
|
465f15a945 | ||
|
|
ffe381e28a | ||
|
|
085359d24f | ||
|
|
b47dcdab84 | ||
|
|
0c23c7d0a3 | ||
|
|
f3099b6226 | ||
|
|
a969d3322f | ||
|
|
8f63acf12b | ||
|
|
1813ee2895 | ||
|
|
6e377601bf | ||
|
|
f7321735d5 | ||
|
|
19429bf324 | ||
|
|
04eaffcd1f | ||
|
|
2c1ef01beb | ||
|
|
dfccf539d1 | ||
|
|
c1a7c5f70b | ||
|
|
7e4851cc3a | ||
|
|
bbb5661b43 | ||
|
|
678fb210be | ||
|
|
90af9768a7 | ||
|
|
6ab433b631 | ||
|
|
d5c4c09fc4 | ||
|
|
3e69d63ec4 | ||
|
|
c47d5a4d2e | ||
|
|
9dd75201b0 | ||
|
|
308a9e173d | ||
|
|
f5a61eed4a | ||
|
|
051513bf4a | ||
|
|
d9382df690 | ||
|
|
0df7fa7855 | ||
|
|
d1c1d276e0 | ||
|
|
ad1f47dd3a | ||
|
|
a0d197e1fa | ||
|
|
cc244fa58b | ||
|
|
c70fdac383 | ||
|
|
81487e2140 | ||
|
|
ef06de9255 | ||
|
|
64499d66cc | ||
|
|
59ab903a78 | ||
|
|
2fa5b33111 | ||
|
|
0399609b07 | ||
|
|
1c91a3bf31 | ||
|
|
ae7f659e9f | ||
|
|
b781b891ec | ||
|
|
f3a984165e | ||
|
|
d8896dc4f5 | ||
|
|
4051832dc0 | ||
|
|
fe2311ef4b | ||
|
|
37d5ce498f | ||
|
|
6bff9d7c68 | ||
|
|
7d51d12262 | ||
|
|
b382ae9023 | ||
|
|
4c8f96d75c | ||
|
|
afddcfa5fd | ||
|
|
ca2bcea3ad | ||
|
|
d5552eaa01 | ||
|
|
32081adc59 | ||
|
|
ad034dd2a5 | ||
|
|
cad4a8a0e5 | ||
|
|
1d1f81c0bb |
@@ -2,4 +2,4 @@
|
|||||||
*
|
*
|
||||||
|
|
||||||
# Files required for the action
|
# Files required for the action
|
||||||
!builder/
|
!action/
|
||||||
|
|||||||
@@ -14,5 +14,8 @@ trim_trailing_whitespace = true
|
|||||||
max_line_length = off
|
max_line_length = off
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
max_line_length = off
|
||||||
|
|
||||||
[COMMIT_EDITMSG]
|
[COMMIT_EDITMSG]
|
||||||
max_line_length = 0
|
max_line_length = off
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
**/node_modules/**
|
**/node_modules/**
|
||||||
**/builder/**
|
**/action/**
|
||||||
|
|||||||
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Bug description**
|
||||||
|
|
||||||
|
<!--A clear and concise description of what the bug is.-->
|
||||||
|
|
||||||
|
**How to reproduce**
|
||||||
|
|
||||||
|
<!--Steps to reproduce the behavior:-->
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
|
||||||
|
<!--A clear and concise description of what you expected to happen.-->
|
||||||
|
|
||||||
|
**Additional details**
|
||||||
|
|
||||||
|
<!--Please add context, links, reasons, screenshots, etc.-->
|
||||||
23
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an improvement or now feature
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Context**
|
||||||
|
|
||||||
|
<!--Please describe a proper context-->
|
||||||
|
|
||||||
|
**Suggested solution**
|
||||||
|
|
||||||
|
<!--Tell us what you would suggest-->
|
||||||
|
|
||||||
|
**Considered alternatives**
|
||||||
|
|
||||||
|
<!--Please add any alternative solutions that you have considered-->
|
||||||
|
|
||||||
|
**Additional details**
|
||||||
|
|
||||||
|
<!--Please add context, links, reasons, screenshots, etc.-->
|
||||||
7
.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
name: Other
|
||||||
|
about: Everything else
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
11
.github/pull_request_template.md
vendored
Normal file
11
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#### Changes
|
||||||
|
|
||||||
|
- ...
|
||||||
|
|
||||||
|
#### Checklist
|
||||||
|
|
||||||
|
<!-- please check all items and add your own -->
|
||||||
|
|
||||||
|
- [x] Read the contribution [guide](../CONTRIBUTING.md) and accept the [code](../CODE_OF_CONDUCT.md) of conduct
|
||||||
|
- [ ] Readme (updated or not needed)
|
||||||
|
- [ ] Tests (added, updated or not needed)
|
||||||
13
.github/workflows/cleanup.yml
vendored
Normal file
13
.github/workflows/cleanup.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
name: Delete old artifacts
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '30 10 * * *' # every day at 10:30
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
delete-artifacts:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: kolpav/purge-artifacts-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
expire-in: 21 days
|
||||||
104
.github/workflows/main.yml
vendored
104
.github/workflows/main.yml
vendored
@@ -1,13 +1,31 @@
|
|||||||
name: Actions 😎
|
name: Actions
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request: {}
|
pull_request: {}
|
||||||
push: { branches: [master] }
|
push: { branches: [main] }
|
||||||
|
|
||||||
env:
|
env:
|
||||||
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n <Binding Key=\"2\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n </MachineBindings>\n <MachineID Value=\"Xxo1ZKbdPu/IATrc0mPBYANJFF0=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\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=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2019-11-25T18:23:38\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.2.11f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" 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>JHdOBFmBNq2H8BrGFzir/StLoYo=</DigestValue></Reference></SignedInfo><SignatureValue>aENLHd37a51RtP2/g7YU0Pexf5mx0/ENXYGtrPzqwZ8NQt2AsSdxGnl0CUB45/GuNXfJVDt2HWot\ncNYZB2OylVBn1WHQbKZlPmm8gEAMz0MYbr4Isb5i5buryBrZlmbEOjnRI+pEg1CBwlgMo6xdtjjE\n/d7cC293QIUO91kdzRXftYou1dNaUyuPL9ZH65vdB2pDXGRNxgUVD+GnnqZA7b5L2HXqNQclcWAK\n5Yd1BeF3VzR1iLw9G/SmH5oOhnpXSmqbL4qk7LVP2/mgXpFk5kP4X8VC3z47obNhBIGq40dwWyEe\nUYk5/nRAOkZawDT+tcu96e06gPC9Cxk5PdbRbA==</SignatureValue></Signature></root>"
|
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
|
||||||
|
GKE_ZONE: 'us-central1-c'
|
||||||
|
GKE_REGION: 'us-central1'
|
||||||
|
GKE_PROJECT: 'unitykubernetesbuilder'
|
||||||
|
GKE_CLUSTER: 'unity-builder-cluster'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
tests:
|
||||||
|
name: Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 12.x
|
||||||
|
- run: yarn
|
||||||
|
- run: yarn lint
|
||||||
|
- run: yarn test --coverage
|
||||||
|
- run: bash <(curl -s https://codecov.io/bash)
|
||||||
|
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
|
||||||
|
# - run: yarn build --quiet && git diff --quiet action || { echo "action should be auto generated" ; git diff action ; exit 62; }
|
||||||
buildForAllPlatforms:
|
buildForAllPlatforms:
|
||||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -18,29 +36,93 @@ jobs:
|
|||||||
- test-project
|
- test-project
|
||||||
unityVersion:
|
unityVersion:
|
||||||
- 2019.2.11f1
|
- 2019.2.11f1
|
||||||
# - 2019.3.0f1 # requires different license file/method
|
- 2019.3.15f1
|
||||||
|
include:
|
||||||
|
# Please be polite; don't copy my personal licenses.
|
||||||
|
# These are here because they are needed to allowing pull requests from forks to unity-builder.
|
||||||
|
# You should be using ${{ secrets.UNITY_LICENSE_2019_3_15 }} here.
|
||||||
|
- unityVersion: 2019.2.11f1
|
||||||
|
license: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n <Binding Key=\"2\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n </MachineBindings>\n <MachineID Value=\"Xxo1ZKbdPu/IATrc0mPBYANJFF0=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\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=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2019-11-25T18:23:38\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.2.11f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" 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>JHdOBFmBNq2H8BrGFzir/StLoYo=</DigestValue></Reference></SignedInfo><SignatureValue>aENLHd37a51RtP2/g7YU0Pexf5mx0/ENXYGtrPzqwZ8NQt2AsSdxGnl0CUB45/GuNXfJVDt2HWot\ncNYZB2OylVBn1WHQbKZlPmm8gEAMz0MYbr4Isb5i5buryBrZlmbEOjnRI+pEg1CBwlgMo6xdtjjE\n/d7cC293QIUO91kdzRXftYou1dNaUyuPL9ZH65vdB2pDXGRNxgUVD+GnnqZA7b5L2HXqNQclcWAK\n5Yd1BeF3VzR1iLw9G/SmH5oOhnpXSmqbL4qk7LVP2/mgXpFk5kP4X8VC3z47obNhBIGq40dwWyEe\nUYk5/nRAOkZawDT+tcu96e06gPC9Cxk5PdbRbA==</SignatureValue></Signature></root>"
|
||||||
|
- unityVersion: 2019.3.15f1
|
||||||
|
license: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"33bf639e81e54693a8f9bf57c8900e5a\"/>\n <Binding Key=\"2\" Value=\"33bf639e81e54693a8f9bf57c8900e5a\"/>\n </MachineBindings>\n <MachineID Value=\"xWka2iXdDJejhZdi/zU2RUeXUi4=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\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=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2020-06-14T13:49:47\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.3.15f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" 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>bpzWx3PZ0lqWDo1m9aLQuZ4cweo=</DigestValue></Reference></SignedInfo><SignatureValue>QcDm4/qAXZuUMQbUVk63vO6u66Bp8PnqqWQcZZOcym/rGUZLj1sr66EquF3X3w1L7aqiwMGtbY2b\nkPttcalFeaBkc5NsJMrexWjuBCxQvhbmVFQnTjvC6vNS+k1wrkz7If1oPkz/XaDtCfUs8oxc9iPe\nPzzUJIVYLZoDtpPq2XbgVn9/TiVb3Zu6ldKgvtNRYUjrB3KywtvL9OcIFll3htRcBZPG43kxryJc\nDD2TL5Nw1JuX6MejBBuYTZsZNpGX9Pjop9+uFUZ4GI9h8a5g6wJUfXzsGw7j4gkvDkC9MvyWiksi\n2hNXw1QNeB6JfQsd4sAuhYh/CqTm2gCz9i9ZpA==</SignatureValue></Signature></root>"
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
||||||
- StandaloneWindows # Build a Windows standalone.
|
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
||||||
- iOS # Build an iOS player.
|
- iOS # Build an iOS player.
|
||||||
# - Android # Build an Android .apk standalone app.
|
# - Android # Build an Android .apk.
|
||||||
- WebGL # WebGL.
|
# - StandaloneWindows # Build a Windows standalone.
|
||||||
|
# - WebGL # WebGL.
|
||||||
# - WSAPlayer # Build an Windows Store Apps player.
|
# - WSAPlayer # Build an Windows Store Apps player.
|
||||||
# - PS4 # Build a PS4 Standalone.
|
# - PS4 # Build a PS4 Standalone.
|
||||||
# - XboxOne # Build a Xbox One Standalone.
|
# - XboxOne # Build a Xbox One Standalone.
|
||||||
# - tvOS # Build to Apple's tvOS platform.
|
# - tvOS # Build to Apple's tvOS platform.
|
||||||
# - Switch # Build a Nintendo Switch player.
|
# - Switch # Build a Nintendo Switch player
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
- uses: actions/cache@v1.1.0
|
||||||
|
with:
|
||||||
|
path: ${{ matrix.projectPath }}/Library
|
||||||
|
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
|
||||||
|
restore-keys: |
|
||||||
|
Library-${{ matrix.projectPath }}-
|
||||||
|
Library-
|
||||||
- uses: ./
|
- uses: ./
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE: ${{ matrix.license }}
|
||||||
with:
|
with:
|
||||||
projectPath: ${{ matrix.projectPath }}
|
projectPath: ${{ matrix.projectPath }}
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
unityVersion: ${{ matrix.unityVersion }}
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: Build
|
name: Build (${{ matrix.unityVersion }})
|
||||||
path: build
|
path: build
|
||||||
|
k8sBuilds:
|
||||||
|
name: K8s build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
targetPlatform:
|
||||||
|
- StandaloneLinux64
|
||||||
|
- StandaloneWindows64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
- uses: GoogleCloudPlatform/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 }}
|
||||||
|
- run: ./action/bootstrapper/ApplyClusterAndAcquireLock.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
||||||
|
- uses: frostebite/File-To-Base64@master
|
||||||
|
id: read-base64
|
||||||
|
with:
|
||||||
|
filePath: ~/.kube/config
|
||||||
|
- uses: ./
|
||||||
|
id: k8s-unity-build
|
||||||
|
env:
|
||||||
|
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"33bf639e81e54693a8f9bf57c8900e5a\"/>\n <Binding Key=\"2\" Value=\"33bf639e81e54693a8f9bf57c8900e5a\"/>\n </MachineBindings>\n <MachineID Value=\"xWka2iXdDJejhZdi/zU2RUeXUi4=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\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=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2020-06-14T13:49:47\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.3.15f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" 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>bpzWx3PZ0lqWDo1m9aLQuZ4cweo=</DigestValue></Reference></SignedInfo><SignatureValue>QcDm4/qAXZuUMQbUVk63vO6u66Bp8PnqqWQcZZOcym/rGUZLj1sr66EquF3X3w1L7aqiwMGtbY2b\nkPttcalFeaBkc5NsJMrexWjuBCxQvhbmVFQnTjvC6vNS+k1wrkz7If1oPkz/XaDtCfUs8oxc9iPe\nPzzUJIVYLZoDtpPq2XbgVn9/TiVb3Zu6ldKgvtNRYUjrB3KywtvL9OcIFll3htRcBZPG43kxryJc\nDD2TL5Nw1JuX6MejBBuYTZsZNpGX9Pjop9+uFUZ4GI9h8a5g6wJUfXzsGw7j4gkvDkC9MvyWiksi\n2hNXw1QNeB6JfQsd4sAuhYh/CqTm2gCz9i9ZpA==</SignatureValue></Signature></root>"
|
||||||
|
with:
|
||||||
|
targetPlatform: ${{ matrix.targetPlatform }}
|
||||||
|
kubeConfig: ${{ steps.read-base64.outputs.base64 }}
|
||||||
|
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
projectPath: test-project
|
||||||
|
unityVersion: 2019.3.15f1
|
||||||
|
- 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@v1
|
||||||
|
with:
|
||||||
|
name: Kubernetes Build (${{ matrix.targetPlatform }})
|
||||||
|
path: k8s-volume-download
|
||||||
|
- run: ./action/bootstrapper/ReleaseLockAndAttemptShutdown.sh ${{ env.GKE_PROJECT }} ${{ env.GKE_CLUSTER }} ${{ env.GKE_ZONE }}
|
||||||
|
if: ${{ always() }}
|
||||||
|
|||||||
19
.github/workflows/test.yml
vendored
19
.github/workflows/test.yml
vendored
@@ -1,19 +0,0 @@
|
|||||||
name: Test Action
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request: {}
|
|
||||||
push: { branches: [master] }
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 12.x
|
|
||||||
- run: yarn
|
|
||||||
- run: yarn lint
|
|
||||||
- run: yarn test
|
|
||||||
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
|
|
||||||
- run: yarn build --quiet && git diff --quiet builder || { echo "builder should be auto generated" ; exit 62; }
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
node_modules
|
node_modules
|
||||||
|
coverage/
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
**/node_modules/**
|
**/node_modules/**
|
||||||
**/dist/**
|
**/action/**
|
||||||
|
|||||||
185
README.md
185
README.md
@@ -1,173 +1,50 @@
|
|||||||
# Unity - Builder
|
<div align="center">
|
||||||
|
<a href="https://github.com/marketplace/actions/unity-builder">
|
||||||
[](https://github.com/webbertakken/unity-builder/actions?query=branch%3Amaster+event%3Apush+workflow%3A%22Actions+%F0%9F%98%8E%22)
|
<img width="800" src="media/UnityBuilder-Logo.png" alt="Unity Builder">
|
||||||
|
</a>
|
||||||
---
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
GitHub Action to
|
GitHub Action to
|
||||||
[build Unity projects](https://github.com/marketplace/actions/unity-builder)
|
[build Unity projects](https://github.com/marketplace/actions/unity-builder)
|
||||||
for different platforms.
|
for different platforms.
|
||||||
|
|
||||||
Part of the
|
Part of the <a href="https://unity-ci.com"><img height="30" src="media/UnityCI-ReferenceLogo.png" alt="Unity CI"></a> open source project.
|
||||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
<br />
|
||||||
collection.
|
<br />
|
||||||
|
|
||||||
---
|
[](https://github.com/webbertakken/unity-builder/actions?query=branch%3Amaster+event%3Apush+workflow%3A%22Actions)
|
||||||
|
[](https://lgtm.com/projects/g/webbertakken/unity-builder/context:javascript)
|
||||||
|
[](https://codecov.io/gh/webbertakken/unity-builder)
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
[Github Action](https://github.com/features/actions)
|
</div>
|
||||||
to build Unity projects for different platforms.
|
|
||||||
|
|
||||||
It is recommended to run the
|
## How to use
|
||||||
[Test](https://github.com/webbertakken/unity-actions#test)
|
|
||||||
action from the
|
|
||||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
|
||||||
collection before running this action. This action also requires the [Activation](https://github.com/marketplace/actions/unity-activate) step.
|
|
||||||
|
|
||||||
## Documentation
|
Find the
|
||||||
|
[docs](https://unity-ci.com/docs/github)
|
||||||
|
on the Unity CI
|
||||||
|
[website](https://unity-ci.com/).
|
||||||
|
|
||||||
See the
|
## Related actions
|
||||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
|
||||||
collection repository for workflow documentation and reference implementation.
|
|
||||||
|
|
||||||
## Usage
|
Visit the
|
||||||
|
<a href="https://github.com/webbertakken/unity-actions"><img height="30" src="media/UnityActions-ReferenceLogo.png" alt="Unity Actions"></a>
|
||||||
|
status repository for related Actions.
|
||||||
|
|
||||||
Create or edit the file called `.github/workflows/main.yml` and add a job to it.
|
## Community
|
||||||
|
|
||||||
```yaml
|
Feel free to join us on
|
||||||
- uses: webbertakken/unity-builder@v0.5
|
<a href="http://unity-ci.com/discord"><img height="30" src="media/Discord-Logo.svg" alt="Discord" /></a>
|
||||||
env:
|
and engage with the community.
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
with:
|
|
||||||
projectPath: path/to/your/project
|
|
||||||
unityVersion: 2020.X.XXXX
|
|
||||||
targetPlatform: WebGL
|
|
||||||
```
|
|
||||||
|
|
||||||
A complete workflow that builds every available platform could look like this:
|
## Contributing
|
||||||
|
|
||||||
```yaml
|
To help out sharpen the documentation, please find the docs [repository](https://github.com/Unity-CI/Website).
|
||||||
name: Build project
|
|
||||||
|
|
||||||
on:
|
To contribute to Unity Builder, kindly read the [contribution guide](./CONTRIBUTING.md).
|
||||||
pull_request: {}
|
|
||||||
push: { branches: [master] }
|
|
||||||
|
|
||||||
env:
|
|
||||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
buildForSomePlatforms:
|
|
||||||
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
projectPath:
|
|
||||||
- path/to/your/project
|
|
||||||
unityVersion:
|
|
||||||
- 2019.2.11f1
|
|
||||||
- 2019.3.0f1
|
|
||||||
targetPlatform:
|
|
||||||
- StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
|
||||||
- StandaloneWindows # Build a Windows standalone.
|
|
||||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
|
||||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
|
||||||
- iOS # Build an iOS player.
|
|
||||||
- Android # Build an Android .apk standalone app.
|
|
||||||
- WebGL # WebGL.
|
|
||||||
- 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:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- uses: webbertakken/unity-builder@v0.5
|
|
||||||
with:
|
|
||||||
projectPath: ${{ matrix.projectPath }}
|
|
||||||
unityVersion: ${{ matrix.unityVersion }}
|
|
||||||
targetPlatform: ${{ matrix.targetPlatform }}
|
|
||||||
- uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: Build
|
|
||||||
path: build
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Notes:**
|
|
||||||
>
|
|
||||||
> - Don't forget to replace _<test-project>_ with your project name.
|
|
||||||
> - By default the enabled scenes from the project's settings will be built.
|
|
||||||
|
|
||||||
## Configuration options
|
|
||||||
|
|
||||||
Below options can be specified under `with:` for the `unity-builder` action.
|
|
||||||
|
|
||||||
#### projectPath
|
|
||||||
|
|
||||||
Specify the path to your Unity project to be built.
|
|
||||||
The path should be relative to the root of your project.
|
|
||||||
|
|
||||||
_**required:** `false`_
|
|
||||||
_**default:** `<your project root>`_
|
|
||||||
|
|
||||||
#### unityVersion
|
|
||||||
|
|
||||||
Version of Unity to use for building the project.
|
|
||||||
|
|
||||||
_**required:** `false`_
|
|
||||||
_**default:** `2019.2.1f11`_
|
|
||||||
|
|
||||||
#### targetPlatform
|
|
||||||
|
|
||||||
Platform that the build should target.
|
|
||||||
|
|
||||||
Must be one of the [allowed values](https://docs.unity3d.com/ScriptReference/BuildTarget.html) listed in the Unity scripting manual.
|
|
||||||
|
|
||||||
_**required:** `true`_
|
|
||||||
|
|
||||||
#### buildName
|
|
||||||
|
|
||||||
Name of the build.
|
|
||||||
|
|
||||||
_**required:** `false`_
|
|
||||||
_**default:** `testBuild`_
|
|
||||||
|
|
||||||
#### buildsPath
|
|
||||||
|
|
||||||
Path where the builds should be stored.
|
|
||||||
|
|
||||||
In this folder a folder will be created for every targetPlatform.
|
|
||||||
|
|
||||||
_**required:** `false`_
|
|
||||||
_**default:** `build`_
|
|
||||||
|
|
||||||
#### buildMethod
|
|
||||||
|
|
||||||
Custom command to run your build.
|
|
||||||
|
|
||||||
There are two conditions for a custom buildCommand:
|
|
||||||
|
|
||||||
- Must reference a valid path to a `static` method.
|
|
||||||
- The class must reside in the `Assets/Editor` directory.
|
|
||||||
|
|
||||||
_**example:**_
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: webbertakken/unity-builder@master
|
|
||||||
with:
|
|
||||||
buildMethod: EditorNamespace.BuilderClassName.StaticBulidMethod
|
|
||||||
```
|
|
||||||
|
|
||||||
_**required:** `false`_
|
|
||||||
_**default:** Built-in script that will run a build out of the box._
|
|
||||||
|
|
||||||
## More actions
|
|
||||||
|
|
||||||
Visit
|
|
||||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
|
||||||
to find related actions for Unity.
|
|
||||||
|
|
||||||
Feel free to contribute.
|
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
|
|||||||
89
action.yml
89
action.yml
@@ -6,6 +6,10 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Version of unity to use for building the project.'
|
description: 'Version of unity to use for building the project.'
|
||||||
|
customImage:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'Specific docker image that should be used for building the project'
|
||||||
targetPlatform:
|
targetPlatform:
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@@ -26,10 +30,91 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
|
description: 'Path to a Namespace.Class.StaticMethod to run to perform the build.'
|
||||||
outputs: {}
|
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.'
|
||||||
|
kubeContainerMemory:
|
||||||
|
default: '800M'
|
||||||
|
required: false
|
||||||
|
description: 'Amount of memory to assign the build container in Kubernetes (https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes)'
|
||||||
|
kubeContainerCPU:
|
||||||
|
default: '0.25'
|
||||||
|
required: false
|
||||||
|
description: 'Amount of CPU time to assign the build container in Kubernetes (https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes)'
|
||||||
|
kubeVolumeSize:
|
||||||
|
default: '5Gi'
|
||||||
|
required: false
|
||||||
|
description: 'Amount of disc space to assign the Kubernetes Persistent Volume (https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes)'
|
||||||
|
githubToken:
|
||||||
|
default: ''
|
||||||
|
required: false
|
||||||
|
description: 'GitHub token for cloning, only needed when kubeconfig is used.'
|
||||||
|
versioning:
|
||||||
|
required: false
|
||||||
|
default: 'Semantic'
|
||||||
|
description: 'The versioning scheme to use when building the project'
|
||||||
|
version:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The version, when used with the "Custom" versioning scheme'
|
||||||
|
androidVersionCode:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The android versionCode'
|
||||||
|
androidAppBundle:
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
description: 'Whether to build .aab instead of .apk'
|
||||||
|
androidKeystoreName:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The android keystoreName'
|
||||||
|
androidKeystoreBase64:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The base64 contents of the android keystore file'
|
||||||
|
androidKeystorePass:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The android keystorePass'
|
||||||
|
androidKeyaliasName:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The android keyaliasName'
|
||||||
|
androidKeyaliasPass:
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
description: 'The android keyaliasPass'
|
||||||
|
customParameters:
|
||||||
|
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).
|
||||||
|
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).
|
||||||
|
outputs:
|
||||||
|
volume:
|
||||||
|
description: 'The Persistent Volume (PV) where the build artifacts have been stored by Kubernetes'
|
||||||
|
buildVersion:
|
||||||
|
description: 'The generated version used for the Unity build'
|
||||||
branding:
|
branding:
|
||||||
icon: 'box'
|
icon: 'box'
|
||||||
color: 'gray-dark'
|
color: 'gray-dark'
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'builder/index.js'
|
main: 'action/index.js'
|
||||||
|
|||||||
69
action/bootstrapper/ApplyClusterAndAcquireLock.sh
Executable file
69
action/bootstrapper/ApplyClusterAndAcquireLock.sh
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/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
|
||||||
13
action/bootstrapper/ReleaseLockAndAttemptShutdown.sh
Executable file
13
action/bootstrapper/ReleaseLockAndAttemptShutdown.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
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
|
||||||
4
action/default-build-script/.editorconfig
Normal file
4
action/default-build-script/.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
resharper_check_namespace_highlighting = do_not_show
|
||||||
@@ -57,6 +57,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Assets\Editor\Builder.cs" />
|
<Compile Include="Assets\Editor\Builder.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Input\ArgumentsParser.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Reporting\StdOutReporter.cs" />
|
||||||
|
<Compile Include="Assets\Editor\System\ProcessExtensions.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Versioning\VersionApplicator.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Versioning\Git.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Versioning\VersionGenerator.cs" />
|
||||||
|
<Compile Include="Assets\Editor\Versioning\GitException.cs" />
|
||||||
<Reference Include="UnityEditor.TestRunner">
|
<Reference Include="UnityEditor.TestRunner">
|
||||||
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.TestRunner.dll</HintPath>
|
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.TestRunner.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -688,6 +695,9 @@
|
|||||||
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/Boo.Lang.dll</HintPath>
|
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/Boo.Lang.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include=".editorconfig" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
49
action/default-build-script/Assets/Editor/Builder.cs
Normal file
49
action/default-build-script/Assets/Editor/Builder.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityBuilderAction.Input;
|
||||||
|
using UnityBuilderAction.Reporting;
|
||||||
|
using UnityBuilderAction.Versioning;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction
|
||||||
|
{
|
||||||
|
static class Builder
|
||||||
|
{
|
||||||
|
public static void BuildProject()
|
||||||
|
{
|
||||||
|
// Gather values from args
|
||||||
|
var options = ArgumentsParser.GetValidatedOptions();
|
||||||
|
|
||||||
|
// Gather values from project
|
||||||
|
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
|
||||||
|
|
||||||
|
// Define BuildPlayer Options
|
||||||
|
var buildOptions = new BuildPlayerOptions {
|
||||||
|
scenes = scenes,
|
||||||
|
locationPathName = options["customBuildPath"],
|
||||||
|
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set version for this build
|
||||||
|
VersionApplicator.SetVersion(options["buildVersion"]);
|
||||||
|
VersionApplicator.SetAndroidVersionCode(options["androidVersionCode"]);
|
||||||
|
|
||||||
|
// Apply Android settings
|
||||||
|
if (buildOptions.target == BuildTarget.Android)
|
||||||
|
AndroidSettings.Apply(options);
|
||||||
|
|
||||||
|
// Perform build
|
||||||
|
BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions);
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
BuildSummary summary = buildReport.summary;
|
||||||
|
StdOutReporter.ReportSummary(summary);
|
||||||
|
|
||||||
|
// Result
|
||||||
|
BuildResult result = summary.result;
|
||||||
|
StdOutReporter.ExitWithResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
action/default-build-script/Assets/Editor/Input.meta
Normal file
3
action/default-build-script/Assets/Editor/Input.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b6e5ef18d769419d887b56665969442b
|
||||||
|
timeCreated: 1587503329
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Input
|
||||||
|
{
|
||||||
|
public class AndroidSettings
|
||||||
|
{
|
||||||
|
public static void Apply(Dictionary<string, string> options)
|
||||||
|
{
|
||||||
|
EditorUserBuildSettings.buildAppBundle = options["customBuildPath"].EndsWith(".aab");
|
||||||
|
if (options.TryGetValue("androidKeystoreName", out string keystoreName) && !string.IsNullOrEmpty(keystoreName))
|
||||||
|
PlayerSettings.Android.keystoreName = keystoreName;
|
||||||
|
if (options.TryGetValue("androidKeystorePass", out string keystorePass) && !string.IsNullOrEmpty(keystorePass))
|
||||||
|
PlayerSettings.Android.keystorePass = keystorePass;
|
||||||
|
if (options.TryGetValue("androidKeyaliasName", out string keyaliasName) && !string.IsNullOrEmpty(keyaliasName))
|
||||||
|
PlayerSettings.Android.keyaliasName = keyaliasName;
|
||||||
|
if (options.TryGetValue("androidKeyaliasPass", out string keyaliasPass) && !string.IsNullOrEmpty(keyaliasPass))
|
||||||
|
PlayerSettings.Android.keyaliasPass = keyaliasPass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0d51cf8acfff8c941bb753e82750b60a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Input
|
||||||
|
{
|
||||||
|
public class ArgumentsParser
|
||||||
|
{
|
||||||
|
static string EOL = Environment.NewLine;
|
||||||
|
static readonly string[] Secrets = { "androidKeystorePass", "androidKeyaliasName", "androidKeyaliasPass" };
|
||||||
|
|
||||||
|
public static Dictionary<string, string> GetValidatedOptions()
|
||||||
|
{
|
||||||
|
ParseCommandLineArguments(out var validatedOptions);
|
||||||
|
|
||||||
|
if (!validatedOptions.TryGetValue("projectPath", out var projectPath)) {
|
||||||
|
Console.WriteLine("Missing argument -projectPath");
|
||||||
|
EditorApplication.Exit(110);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validatedOptions.TryGetValue("buildTarget", out var buildTarget)) {
|
||||||
|
Console.WriteLine("Missing argument -buildTarget");
|
||||||
|
EditorApplication.Exit(120);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
||||||
|
EditorApplication.Exit(121);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validatedOptions.TryGetValue("customBuildPath", out var customBuildPath)) {
|
||||||
|
Console.WriteLine("Missing argument -customBuildPath");
|
||||||
|
EditorApplication.Exit(130);
|
||||||
|
}
|
||||||
|
|
||||||
|
const string defaultCustomBuildName = "TestBuild";
|
||||||
|
if (!validatedOptions.TryGetValue("customBuildName", out var customBuildName)) {
|
||||||
|
Console.WriteLine($"Missing argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
||||||
|
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
||||||
|
} else if (customBuildName == "") {
|
||||||
|
Console.WriteLine($"Invalid argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
||||||
|
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validatedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ParseCommandLineArguments(out Dictionary<string, string> providedArguments)
|
||||||
|
{
|
||||||
|
providedArguments = new Dictionary<string, string>();
|
||||||
|
string[] args = Environment.GetCommandLineArgs();
|
||||||
|
|
||||||
|
Console.WriteLine(
|
||||||
|
$"{EOL}" +
|
||||||
|
$"###########################{EOL}" +
|
||||||
|
$"# Parsing settings #{EOL}" +
|
||||||
|
$"###########################{EOL}" +
|
||||||
|
$"{EOL}"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extract flags with optional values
|
||||||
|
for (int current = 0, next = 1; current < args.Length; current++, next++) {
|
||||||
|
// Parse flag
|
||||||
|
bool isFlag = args[current].StartsWith("-");
|
||||||
|
if (!isFlag) continue;
|
||||||
|
string flag = args[current].TrimStart('-');
|
||||||
|
|
||||||
|
// Parse optional value
|
||||||
|
bool flagHasValue = next < args.Length && !args[next].StartsWith("-");
|
||||||
|
string value = flagHasValue ? args[next].TrimStart('-') : "";
|
||||||
|
bool secret = Secrets.Contains(flag);
|
||||||
|
string displayValue = secret ? "*HIDDEN*" : "\"" + value + "\"";
|
||||||
|
|
||||||
|
// Assign
|
||||||
|
Console.WriteLine($"Found flag \"{flag}\" with value {displayValue}.");
|
||||||
|
providedArguments.Add(flag, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 46d2ec4a86604575be2b2d02b0df7b74
|
||||||
|
timeCreated: 1587503354
|
||||||
3
action/default-build-script/Assets/Editor/Reporting.meta
Normal file
3
action/default-build-script/Assets/Editor/Reporting.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 166f919334c44e7a80ae916667974e7d
|
||||||
|
timeCreated: 1587503566
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Reporting
|
||||||
|
{
|
||||||
|
public class StdOutReporter
|
||||||
|
{
|
||||||
|
static string EOL = Environment.NewLine;
|
||||||
|
|
||||||
|
public static void ReportSummary(BuildSummary summary)
|
||||||
|
{
|
||||||
|
Console.WriteLine(
|
||||||
|
$"{EOL}" +
|
||||||
|
$"###########################{EOL}" +
|
||||||
|
$"# Build results #{EOL}" +
|
||||||
|
$"###########################{EOL}" +
|
||||||
|
$"{EOL}" +
|
||||||
|
$"Duration: {summary.totalTime.ToString()}{EOL}" +
|
||||||
|
$"Warnings: {summary.totalWarnings.ToString()}{EOL}" +
|
||||||
|
$"Errors: {summary.totalErrors.ToString()}{EOL}" +
|
||||||
|
$"Size: {summary.totalSize.ToString()} bytes{EOL}" +
|
||||||
|
$"{EOL}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExitWithResult(BuildResult result)
|
||||||
|
{
|
||||||
|
if (result == BuildResult.Succeeded) {
|
||||||
|
Console.WriteLine("Build succeeded!");
|
||||||
|
EditorApplication.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == BuildResult.Failed) {
|
||||||
|
Console.WriteLine("Build failed!");
|
||||||
|
EditorApplication.Exit(101);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == BuildResult.Cancelled) {
|
||||||
|
Console.WriteLine("Build cancelled!");
|
||||||
|
EditorApplication.Exit(102);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == BuildResult.Unknown) {
|
||||||
|
Console.WriteLine("Build result is unknown!");
|
||||||
|
EditorApplication.Exit(103);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e59b491a4124442ea7277f76761cdc8a
|
||||||
|
timeCreated: 1587503545
|
||||||
3
action/default-build-script/Assets/Editor/System.meta
Normal file
3
action/default-build-script/Assets/Editor/System.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b5da3bd7e18c43d79243410166c8dc9a
|
||||||
|
timeCreated: 1587493708
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public static class ProcessExtensions
|
||||||
|
{
|
||||||
|
// Execute an application or binary with given arguments
|
||||||
|
//
|
||||||
|
// See: https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output
|
||||||
|
public static int Run(this Process process, string application,
|
||||||
|
string arguments, string workingDirectory, out string output,
|
||||||
|
out string errors)
|
||||||
|
{
|
||||||
|
// Configure how to run the application
|
||||||
|
process.StartInfo = new ProcessStartInfo {
|
||||||
|
CreateNoWindow = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
FileName = application,
|
||||||
|
Arguments = arguments,
|
||||||
|
WorkingDirectory = workingDirectory
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read the output
|
||||||
|
var outputBuilder = new StringBuilder();
|
||||||
|
var errorsBuilder = new StringBuilder();
|
||||||
|
process.OutputDataReceived += (_, args) => outputBuilder.AppendLine(args.Data);
|
||||||
|
process.ErrorDataReceived += (_, args) => errorsBuilder.AppendLine(args.Data);
|
||||||
|
|
||||||
|
// Run the application and wait for it to complete
|
||||||
|
process.Start();
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
// Format the output
|
||||||
|
output = outputBuilder.ToString().TrimEnd();
|
||||||
|
errors = errorsBuilder.ToString().TrimEnd();
|
||||||
|
|
||||||
|
return process.ExitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29c1880a390c4af7be821b7877602815
|
||||||
|
timeCreated: 1587494270
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1c3bddf6d8984cde9208e3f0fe584879
|
||||||
|
timeCreated: 1587490700
|
||||||
116
action/default-build-script/Assets/Editor/Versioning/Git.cs
Normal file
116
action/default-build-script/Assets/Editor/Versioning/Git.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Versioning
|
||||||
|
{
|
||||||
|
public static class Git
|
||||||
|
{
|
||||||
|
const string application = @"git";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate a version based on the latest tag and the amount of commits.
|
||||||
|
/// Format: 0.1.2 (where 2 is the amount of commits).
|
||||||
|
///
|
||||||
|
/// If no tag is present in the repository then v0.0 is assumed.
|
||||||
|
/// This would result in 0.0.# where # is the amount of commits.
|
||||||
|
/// </summary>
|
||||||
|
public static string GenerateSemanticCommitVersion()
|
||||||
|
{
|
||||||
|
string version;
|
||||||
|
if (HasAnyVersionTags()) {
|
||||||
|
version = GetSemanticCommitVersion();
|
||||||
|
Console.WriteLine("Repository has a valid version tag.");
|
||||||
|
} else {
|
||||||
|
version = $"0.0.{GetTotalNumberOfCommits()}";
|
||||||
|
Console.WriteLine("Repository does not have tags to base the version on.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Version is {version}");
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the version of the current tag.
|
||||||
|
///
|
||||||
|
/// The tag must point at HEAD for this method to work.
|
||||||
|
///
|
||||||
|
/// Output Format:
|
||||||
|
/// #.* (where # is the major version and * can be any number of any type of character)
|
||||||
|
/// </summary>
|
||||||
|
public static string GetTagVersion()
|
||||||
|
{
|
||||||
|
string version = Run(@"tag --points-at HEAD | grep v[0-9]*");
|
||||||
|
|
||||||
|
version = version.Substring(1);
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the total number of commits.
|
||||||
|
/// </summary>
|
||||||
|
static int GetTotalNumberOfCommits()
|
||||||
|
{
|
||||||
|
string numberOfCommitsAsString = Run(@"git rev-list --count HEAD");
|
||||||
|
|
||||||
|
return int.Parse(numberOfCommitsAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the repository has any version tags yet.
|
||||||
|
/// </summary>
|
||||||
|
static bool HasAnyVersionTags()
|
||||||
|
{
|
||||||
|
return "0" != Run(@"tag --list --merged HEAD | grep v[0-9]* | wc -l");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the build version from git based on the most recent matching tag and
|
||||||
|
/// commit history. This returns the version as: {major.minor.build} where 'build'
|
||||||
|
/// represents the nth commit after the tagged commit.
|
||||||
|
/// Note: The initial 'v' and the commit hash are removed.
|
||||||
|
/// </summary>
|
||||||
|
static string GetSemanticCommitVersion()
|
||||||
|
{
|
||||||
|
// v0.1-2-g12345678 (where 2 is the amount of commits, g stands for git)
|
||||||
|
string version = GetVersionString();
|
||||||
|
// 0.1-2
|
||||||
|
version = version.Substring(1, version.LastIndexOf('-') - 1);
|
||||||
|
// 0.1.2
|
||||||
|
version = version.Replace('-', '.');
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get version string.
|
||||||
|
///
|
||||||
|
/// Format: `v0.1-2-g12345678` (where 2 is the amount of commits since the last tag)
|
||||||
|
///
|
||||||
|
/// See: https://softwareengineering.stackexchange.com/questions/141973/how-do-you-achieve-a-numeric-versioning-scheme-with-git
|
||||||
|
/// </summary>
|
||||||
|
static string GetVersionString()
|
||||||
|
{
|
||||||
|
return Run(@"describe --tags --long --match ""v[0-9]*""");
|
||||||
|
|
||||||
|
// Todo - implement split function based on this more complete query
|
||||||
|
// return Run(@"describe --long --tags --dirty --always");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs git binary with any given arguments and returns the output.
|
||||||
|
/// </summary>
|
||||||
|
static string Run(string arguments)
|
||||||
|
{
|
||||||
|
using (var process = new System.Diagnostics.Process()) {
|
||||||
|
string workingDirectory = Application.dataPath;
|
||||||
|
|
||||||
|
int exitCode = process.Run(application, arguments, workingDirectory, out string output, out string errors);
|
||||||
|
if (exitCode != 0) { throw new GitException(exitCode, errors); }
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cdec7fa0f5bb44958fdf74d4658a4601
|
||||||
|
timeCreated: 1587495075
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Versioning
|
||||||
|
{
|
||||||
|
public class GitException : InvalidOperationException
|
||||||
|
{
|
||||||
|
public readonly int code;
|
||||||
|
|
||||||
|
public GitException(int code, string errors) : base(errors)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4d375e209fd14fc5bc2f3dc3c78ac574
|
||||||
|
timeCreated: 1587490750
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace UnityBuilderAction.Versioning
|
||||||
|
{
|
||||||
|
public class VersionApplicator
|
||||||
|
{
|
||||||
|
public static void SetVersion(string version)
|
||||||
|
{
|
||||||
|
if (version == "none") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Apply(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetAndroidVersionCode(string androidVersionCode) {
|
||||||
|
PlayerSettings.Android.bundleVersionCode = Int32.Parse(androidVersionCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Apply(string version)
|
||||||
|
{
|
||||||
|
PlayerSettings.bundleVersion = version;
|
||||||
|
PlayerSettings.macOS.buildNumber = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 30483367ddc84699a0da377ccb93769a
|
||||||
|
timeCreated: 1587504315
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace UnityBuilderAction.Versioning
|
||||||
|
{
|
||||||
|
public static class VersionGenerator
|
||||||
|
{
|
||||||
|
public static string Generate()
|
||||||
|
{
|
||||||
|
return Git.GenerateSemanticCommitVersion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9892e03ae8314b7eacd793c8002de007
|
||||||
|
timeCreated: 1587490842
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Untracked/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Versioning/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
32
action/entrypoint.sh
Executable file
32
action/entrypoint.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Run steps
|
||||||
|
#
|
||||||
|
|
||||||
|
source /steps/activate.sh
|
||||||
|
source /steps/build.sh
|
||||||
|
source /steps/return_license.sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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
|
||||||
39
action/exec-child.js
Normal file
39
action/exec-child.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
if (require.main !== module) {
|
||||||
|
throw new Error('This file should not be required');
|
||||||
|
}
|
||||||
|
|
||||||
|
var childProcess = require('child_process');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var paramFilePath = process.argv[2];
|
||||||
|
|
||||||
|
var serializedParams = fs.readFileSync(paramFilePath, 'utf8');
|
||||||
|
var params = JSON.parse(serializedParams);
|
||||||
|
|
||||||
|
var cmd = params.command;
|
||||||
|
var execOptions = params.execOptions;
|
||||||
|
var pipe = params.pipe;
|
||||||
|
var stdoutFile = params.stdoutFile;
|
||||||
|
var stderrFile = params.stderrFile;
|
||||||
|
|
||||||
|
var c = childProcess.exec(cmd, execOptions, function (err) {
|
||||||
|
if (!err) {
|
||||||
|
process.exitCode = 0;
|
||||||
|
} else if (err.code === undefined) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
} else {
|
||||||
|
process.exitCode = err.code;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var stdoutStream = fs.createWriteStream(stdoutFile);
|
||||||
|
var stderrStream = fs.createWriteStream(stderrFile);
|
||||||
|
|
||||||
|
c.stdout.pipe(stdoutStream);
|
||||||
|
c.stderr.pipe(stderrStream);
|
||||||
|
c.stdout.pipe(process.stdout);
|
||||||
|
c.stderr.pipe(process.stderr);
|
||||||
|
|
||||||
|
if (pipe) {
|
||||||
|
c.stdin.end(pipe);
|
||||||
|
}
|
||||||
1
action/index.js
Normal file
1
action/index.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,29 +1,29 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [[ -n "$UNITY_LICENSE" ]]; then
|
if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
||||||
#
|
#
|
||||||
# PERSONAL LICENSE MODE
|
# PERSONAL LICENSE MODE
|
||||||
#
|
#
|
||||||
# This will activate Unity, using a license file
|
# This will activate Unity, using a license file
|
||||||
#
|
#
|
||||||
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2019.
|
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
|
||||||
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
|
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
|
||||||
#
|
#
|
||||||
# The license file can be acquired using `webbertakken/request-manual-activation-file` action.
|
# The license file can be acquired using `webbertakken/request-manual-activation-file` action.
|
||||||
LICENSE_MODE="personal"
|
echo "Requesting activation (personal license)"
|
||||||
|
|
||||||
# Set the license file path
|
# Set the license file path
|
||||||
FILE_PATH=UnityLicenseFile.ulf
|
FILE_PATH=UnityLicenseFile.ulf
|
||||||
|
|
||||||
# Copy license file from Github variables
|
if [[ -n "$UNITY_LICENSE" ]]; then
|
||||||
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
|
# Copy license file from Github variables
|
||||||
|
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
|
||||||
|
elif [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
||||||
|
# Copy license file from file system
|
||||||
|
cat "$UNITY_LICENSE_FILE" | tr -d '\r' > $FILE_PATH
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
|
||||||
# Activate license
|
# Activate license
|
||||||
#
|
|
||||||
# This is expected to always exit with code 1 (both success and failure).
|
|
||||||
#
|
|
||||||
echo "Requesting activation"
|
|
||||||
ACTIVATION_OUTPUT=$(xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
ACTIVATION_OUTPUT=$(xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||||
/opt/Unity/Editor/Unity \
|
/opt/Unity/Editor/Unity \
|
||||||
-batchmode \
|
-batchmode \
|
||||||
@@ -31,17 +31,23 @@ if [[ -n "$UNITY_LICENSE" ]]; then
|
|||||||
-logFile /dev/stdout \
|
-logFile /dev/stdout \
|
||||||
-quit \
|
-quit \
|
||||||
-manualLicenseFile $FILE_PATH)
|
-manualLicenseFile $FILE_PATH)
|
||||||
# Convert to exit code 0 by echoing the current exit code.
|
|
||||||
echo $?
|
|
||||||
# Exit code is now 0
|
|
||||||
|
|
||||||
# TODO - remove debugging
|
# Store the exit code from the verify command
|
||||||
echo $ACTIVATION_OUTPUT
|
UNITY_EXIT_CODE=$?
|
||||||
echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default'
|
|
||||||
echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default' | wc -l
|
|
||||||
|
|
||||||
# TODO - Derive exit code by grepping success statement
|
# The exit code for personal activation is always 1;
|
||||||
UNITY_EXIT_CODE=$(echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default' | wc -l)
|
# Determine whether activation was successful.
|
||||||
|
#
|
||||||
|
# Successful output should include the following:
|
||||||
|
#
|
||||||
|
# "LICENSE SYSTEM [2020120 18:51:20] Next license update check is after 2019-11-25T18:23:38"
|
||||||
|
#
|
||||||
|
ACTIVATION_SUCCESSFUL=$(echo $ACTIVATION_OUTPUT | grep 'Next license update check is after' | wc -l)
|
||||||
|
|
||||||
|
# Set exit code to 0 if activation was successful
|
||||||
|
if [[ $ACTIVATION_SUCCESSFUL -eq 1 ]]; then
|
||||||
|
UNITY_EXIT_CODE=0
|
||||||
|
fi;
|
||||||
|
|
||||||
# Remove license file
|
# Remove license file
|
||||||
rm -f $FILE_PATH
|
rm -f $FILE_PATH
|
||||||
@@ -54,8 +60,9 @@ elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
|||||||
#
|
#
|
||||||
# Note: This is the preferred way for PROFESSIONAL LICENSES.
|
# Note: This is the preferred way for PROFESSIONAL LICENSES.
|
||||||
#
|
#
|
||||||
LICENSE_MODE="professional"
|
echo "Requesting activation (professional license)"
|
||||||
|
|
||||||
|
# Activate license
|
||||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||||
/opt/Unity/Editor/Unity \
|
/opt/Unity/Editor/Unity \
|
||||||
-batchmode \
|
-batchmode \
|
||||||
@@ -71,16 +78,18 @@ elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
|||||||
|
|
||||||
else
|
else
|
||||||
#
|
#
|
||||||
# LICENSE ACTIVATION FAILED
|
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||||
#
|
#
|
||||||
# This will exit since both personal and professional activation modes failed
|
# This will exit since no activation strategies could be matched.
|
||||||
#
|
#
|
||||||
echo "No personal or professional licenses provided!"
|
echo "License activation strategy could not be determined."
|
||||||
echo "Please ensure you have setup one of these licensing methods:"
|
echo ""
|
||||||
echo " - Personal: Set the UNITY_LICENSE environment variable."
|
echo "Visit https://github.com/webbertakken/unity-builder#usage for more"
|
||||||
echo " - Professional: Set the UNITY_EMAIL, UNITY_PASSWORD and UNITY_SERIAL environment variables."
|
echo "details on how to set up one of the possible activation strategies."
|
||||||
echo "See https://github.com/webbertakken/unity-builder#usage for details."
|
|
||||||
|
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
|
||||||
exit 1;
|
exit 1;
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -88,10 +97,10 @@ fi
|
|||||||
#
|
#
|
||||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
||||||
# Activation was a success
|
# Activation was a success
|
||||||
echo "Activation ($LICENSE_MODE) complete."
|
echo "Activation complete."
|
||||||
else
|
else
|
||||||
# Activation failed so exit with the code from the license verification step
|
# Activation failed so exit with the code from the license verification step
|
||||||
echo "Unclassified error occured while trying to activate ($LICENSE_MODE) license."
|
echo "Unclassified error occured while trying to activate license."
|
||||||
echo "Exit code was: $UNITY_EXIT_CODE"
|
echo "Exit code was: $UNITY_EXIT_CODE"
|
||||||
exit $UNITY_EXIT_CODE
|
exit $UNITY_EXIT_CODE
|
||||||
fi
|
fi
|
||||||
97
builder/steps/build.sh → action/steps/build.sh
Normal file → Executable file
97
builder/steps/build.sh → action/steps/build.sh
Normal file → Executable file
@@ -4,53 +4,28 @@
|
|||||||
# Set project path
|
# Set project path
|
||||||
#
|
#
|
||||||
|
|
||||||
UNITY_PROJECT_PATH=$GITHUB_WORKSPACE/$PROJECT_PATH
|
UNITY_PROJECT_PATH="$GITHUB_WORKSPACE/$PROJECT_PATH"
|
||||||
echo "Using project path \"$UNITY_PROJECT_PATH\"."
|
echo "Using project path \"$UNITY_PROJECT_PATH\"."
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set the name for the build
|
# Display the name for the build, doubles as the output name
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -z "$BUILD_NAME" ]; then
|
|
||||||
BUILD_NAME="build-$(date '+%F-%H%M')"
|
|
||||||
fi
|
|
||||||
echo "Using build name \"$BUILD_NAME\"."
|
echo "Using build name \"$BUILD_NAME\"."
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set the builds target platform;
|
# Display the build's target platform;
|
||||||
#
|
|
||||||
# Web: WebGL
|
|
||||||
# Desktop: StandaloneOSX, StandaloneWindows, StandaloneWindows64, StandaloneLinux64
|
|
||||||
# Console: PS4, XboxOne, Switch
|
|
||||||
# Mobile: Android, iOS
|
|
||||||
# Other: tvOS, Lumin, BJM, WSAPlayer
|
|
||||||
#
|
|
||||||
# Default to WebGL (no particular reason)
|
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -z "$BUILD_TARGET" ]; then
|
|
||||||
BUILD_TARGET=WebGL
|
|
||||||
fi
|
|
||||||
echo "Using build target \"$BUILD_TARGET\"."
|
echo "Using build target \"$BUILD_TARGET\"."
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set builds path
|
# Display build path and file
|
||||||
#
|
#
|
||||||
|
|
||||||
if [ -z "$BUILDS_PATH" ]; then
|
echo "Using build path \"$BUILD_PATH\" to save file \"$BUILD_FILE\"."
|
||||||
BUILDS_PATH=build
|
BUILD_PATH_FULL="$GITHUB_WORKSPACE/$BUILD_PATH"
|
||||||
fi
|
CUSTOM_BUILD_PATH="$BUILD_PATH_FULL/$BUILD_FILE"
|
||||||
BUILDS_FULL_PATH=$GITHUB_WORKSPACE/$BUILDS_PATH
|
|
||||||
|
|
||||||
# TODO - Cleanup
|
|
||||||
BUILD_FOLDER=$BUILD_TARGET-$UNITY_VERSION
|
|
||||||
CURRENT_BUILD_PATH=$BUILDS_PATH/$BUILD_FOLDER
|
|
||||||
CURRENT_BUILD_FULL_PATH=$BUILDS_FULL_PATH/$BUILD_FOLDER
|
|
||||||
|
|
||||||
# TODO - Determine the file or folder based on BUILD_TARGET
|
|
||||||
CUSTOM_BUILD_PATH=$BUILDS_FULL_PATH/$BUILD_FOLDER/$BUILD_TARGET
|
|
||||||
|
|
||||||
echo "Using build path \"$CURRENT_BUILD_PATH\"."
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set the build method, must reference one of:
|
# Set the build method, must reference one of:
|
||||||
@@ -71,25 +46,36 @@ if [ -z "$BUILD_METHOD" ]; then
|
|||||||
#
|
#
|
||||||
echo "Using built-in build method."
|
echo "Using built-in build method."
|
||||||
# Create Editor directory if it does not exist
|
# Create Editor directory if it does not exist
|
||||||
mkdir -p $UNITY_PROJECT_PATH/Assets/Editor/
|
mkdir -p "$UNITY_PROJECT_PATH/Assets/Editor/"
|
||||||
# Copy the build script of Unity Builder action
|
# Copy the build script of Unity Builder action
|
||||||
cp -r /UnityBuilderAction/Assets/Editor $UNITY_PROJECT_PATH/Assets/Editor/
|
cp -R "/UnityBuilderAction/Assets/Editor/" "$UNITY_PROJECT_PATH/Assets/Editor/"
|
||||||
# Set the Build method to that of UnityBuilder Action
|
# Set the Build method to that of UnityBuilder Action
|
||||||
BUILD_METHOD="UnityBuilderAction.Builder.BuildProject"
|
BUILD_METHOD="UnityBuilderAction.Builder.BuildProject"
|
||||||
# Verify recursive paths
|
# Verify recursive paths
|
||||||
ls -Ralph $UNITY_PROJECT_PATH/Assets/Editor/
|
ls -Ralph "$UNITY_PROJECT_PATH/Assets/Editor/"
|
||||||
#
|
#
|
||||||
else
|
else
|
||||||
# User has provided their own build method.
|
# User has provided their own build method.
|
||||||
# Assume they also bring their own script.
|
# Assume they also bring their own script.
|
||||||
#
|
#
|
||||||
echo "User set build method to $BUILD_METHOD."
|
echo "Using build method \"$BUILD_METHOD\"."
|
||||||
#
|
#
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set build method to execute as flag + argument
|
#
|
||||||
EXECUTE_BUILD_METHOD="-executeMethod $BUILD_METHOD"
|
# Create Android keystore, if needed
|
||||||
|
#
|
||||||
|
if [[ -z $ANDROID_KEYSTORE_NAME || -z $ANDROID_KEYSTORE_BASE64 ]]; then
|
||||||
|
echo "Not creating Android keystore."
|
||||||
|
else
|
||||||
|
echo "$ANDROID_KEYSTORE_BASE64" | base64 --decode > "$ANDROID_KEYSTORE_NAME"
|
||||||
|
echo "Created Android keystore."
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Display custom parameters
|
||||||
|
#
|
||||||
|
echo "Using custom parameters $CUSTOM_PARAMETERS."
|
||||||
|
|
||||||
# The build specification below may require Unity 2019.2.11f1 or later (not tested below).
|
# The build specification below may require Unity 2019.2.11f1 or later (not tested below).
|
||||||
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
|
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
|
||||||
@@ -98,25 +84,15 @@ EXECUTE_BUILD_METHOD="-executeMethod $BUILD_METHOD"
|
|||||||
# Build info
|
# Build info
|
||||||
#
|
#
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "###########################"
|
|
||||||
echo "# All builds dir #"
|
|
||||||
echo "###########################"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Creating \"$BUILDS_FULL_PATH\" if it does not exist."
|
|
||||||
mkdir -p $BUILDS_FULL_PATH
|
|
||||||
ls -alh $BUILDS_FULL_PATH
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "###########################"
|
echo "###########################"
|
||||||
echo "# Current build dir #"
|
echo "# Current build dir #"
|
||||||
echo "###########################"
|
echo "###########################"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "Creating \"$CURRENT_BUILD_FULL_PATH\" if it does not exist."exist."
|
echo "Creating \"$BUILD_PATH_FULL\" if it does not exist."
|
||||||
mkdir -p $CURRENT_BUILD_FULL_PATH
|
mkdir -p "$BUILD_PATH_FULL"
|
||||||
ls -alh $CURRENT_BUILD_FULL_PATH
|
ls -alh "$BUILD_PATH_FULL"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "###########################"
|
echo "###########################"
|
||||||
@@ -135,6 +111,7 @@ echo ""
|
|||||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||||
/opt/Unity/Editor/Unity \
|
/opt/Unity/Editor/Unity \
|
||||||
-batchmode \
|
-batchmode \
|
||||||
|
-nographics \
|
||||||
-logfile /dev/stdout \
|
-logfile /dev/stdout \
|
||||||
-quit \
|
-quit \
|
||||||
-customBuildName "$BUILD_NAME" \
|
-customBuildName "$BUILD_NAME" \
|
||||||
@@ -142,7 +119,14 @@ xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
|||||||
-buildTarget "$BUILD_TARGET" \
|
-buildTarget "$BUILD_TARGET" \
|
||||||
-customBuildTarget "$BUILD_TARGET" \
|
-customBuildTarget "$BUILD_TARGET" \
|
||||||
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
-customBuildPath "$CUSTOM_BUILD_PATH" \
|
||||||
$EXECUTE_BUILD_METHOD
|
-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" \
|
||||||
|
$CUSTOM_PARAMETERS
|
||||||
|
|
||||||
# Catch exit code
|
# Catch exit code
|
||||||
BUILD_EXIT_CODE=$?
|
BUILD_EXIT_CODE=$?
|
||||||
@@ -154,6 +138,13 @@ else
|
|||||||
echo "Build failed, with exit code $BUILD_EXIT_CODE";
|
echo "Build failed, with exit code $BUILD_EXIT_CODE";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Add permissions to make app runnable
|
||||||
|
if [[ "$BUILD_TARGET" == "StandaloneOSX" ]]; then
|
||||||
|
ADD_PERMISSIONS_PATH=$BUILD_PATH_FULL/StandaloneOSX.app/Contents/MacOS/*
|
||||||
|
echo "Making the following path executable: $ADD_PERMISSIONS_PATH"
|
||||||
|
chmod +x $ADD_PERMISSIONS_PATH
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Results
|
# Results
|
||||||
#
|
#
|
||||||
@@ -164,4 +155,4 @@ echo "# Build directory #"
|
|||||||
echo "###########################"
|
echo "###########################"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
ls -alh $CURRENT_BUILD_FULL_PATH
|
ls -alh "$BUILD_PATH_FULL"
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEditor.Build.Reporting;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace UnityBuilderAction
|
|
||||||
{
|
|
||||||
static class Builder
|
|
||||||
{
|
|
||||||
private static string EOL = Environment.NewLine;
|
|
||||||
|
|
||||||
private static void ParseCommandLineArguments(out Dictionary<string, string> providedArguments)
|
|
||||||
{
|
|
||||||
providedArguments = new Dictionary<string, string>();
|
|
||||||
string[] args = Environment.GetCommandLineArgs();
|
|
||||||
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{EOL}" +
|
|
||||||
$"###########################{EOL}" +
|
|
||||||
$"# Parsing settings #{EOL}" +
|
|
||||||
$"###########################{EOL}" +
|
|
||||||
$"{EOL}"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Extract flags with optional values
|
|
||||||
for (int current = 0, next = 1; current < args.Length; current++, next++) {
|
|
||||||
// Parse flag
|
|
||||||
bool isFlag = args[current].StartsWith("-");
|
|
||||||
if (!isFlag) continue;
|
|
||||||
string flag = args[current].TrimStart('-');
|
|
||||||
|
|
||||||
// Parse optional value
|
|
||||||
bool flagHasValue = next < args.Length && !args[next].StartsWith("-");
|
|
||||||
string value = flagHasValue ? args[next].TrimStart('-') : "";
|
|
||||||
|
|
||||||
// Assign
|
|
||||||
Console.WriteLine($"Found flag \"{flag}\" with value \"{value}\".");
|
|
||||||
providedArguments.Add(flag, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, string> GetValidatedOptions()
|
|
||||||
{
|
|
||||||
ParseCommandLineArguments(out var validatedOptions);
|
|
||||||
|
|
||||||
if (!validatedOptions.TryGetValue("projectPath", out var projectPath)) {
|
|
||||||
Console.WriteLine("Missing argument -projectPath");
|
|
||||||
EditorApplication.Exit(110);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validatedOptions.TryGetValue("buildTarget", out var buildTarget)) {
|
|
||||||
Console.WriteLine("Missing argument -buildTarget");
|
|
||||||
EditorApplication.Exit(120);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
|
|
||||||
EditorApplication.Exit(121);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validatedOptions.TryGetValue("customBuildPath", out var customBuildPath)) {
|
|
||||||
Console.WriteLine("Missing argument -customBuildPath");
|
|
||||||
EditorApplication.Exit(130);
|
|
||||||
}
|
|
||||||
|
|
||||||
string defaultCustomBuildName = "TestBuild";
|
|
||||||
if (!validatedOptions.TryGetValue("customBuildName", out var customBuildName)) {
|
|
||||||
Console.WriteLine($"Missing argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
|
||||||
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
|
||||||
}
|
|
||||||
else if (customBuildName == "") {
|
|
||||||
Console.WriteLine($"Invalid argument -customBuildName, defaulting to {defaultCustomBuildName}.");
|
|
||||||
validatedOptions.Add("customBuildName", defaultCustomBuildName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return validatedOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BuildProject()
|
|
||||||
{
|
|
||||||
// Gather values from args
|
|
||||||
var options = GetValidatedOptions();
|
|
||||||
|
|
||||||
// Gather values from project
|
|
||||||
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
|
|
||||||
|
|
||||||
// Define BuildPlayer Options
|
|
||||||
var buildOptions = new BuildPlayerOptions {
|
|
||||||
scenes = scenes,
|
|
||||||
locationPathName = options["customBuildPath"],
|
|
||||||
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Perform build
|
|
||||||
BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions);
|
|
||||||
|
|
||||||
// Summary
|
|
||||||
BuildSummary summary = buildReport.summary;
|
|
||||||
ReportSummary(summary);
|
|
||||||
|
|
||||||
// Result
|
|
||||||
BuildResult result = summary.result;
|
|
||||||
ExitWithResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReportSummary(BuildSummary summary)
|
|
||||||
{
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{EOL}" +
|
|
||||||
$"###########################{EOL}" +
|
|
||||||
$"# Build results #{EOL}" +
|
|
||||||
$"###########################{EOL}" +
|
|
||||||
$"{EOL}" +
|
|
||||||
$"Duration: {summary.totalTime.ToString()}{EOL}" +
|
|
||||||
$"Warnings: {summary.totalWarnings.ToString()}{EOL}" +
|
|
||||||
$"Errors: {summary.totalErrors.ToString()}{EOL}" +
|
|
||||||
$"Size: {summary.totalSize.ToString()} bytes{EOL}" +
|
|
||||||
$"{EOL}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ExitWithResult(BuildResult result)
|
|
||||||
{
|
|
||||||
if (result == BuildResult.Succeeded) {
|
|
||||||
Console.WriteLine("Build succeeded!");
|
|
||||||
EditorApplication.Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == BuildResult.Failed) {
|
|
||||||
Console.WriteLine("Build failed!");
|
|
||||||
EditorApplication.Exit(101);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == BuildResult.Cancelled) {
|
|
||||||
Console.WriteLine("Build cancelled!");
|
|
||||||
EditorApplication.Exit(102);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == BuildResult.Unknown) {
|
|
||||||
Console.WriteLine("Build result is unknown!");
|
|
||||||
EditorApplication.Exit(103);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
#
|
|
||||||
# Run steps
|
|
||||||
#
|
|
||||||
|
|
||||||
source /steps/activate.sh
|
|
||||||
source /steps/build.sh
|
|
||||||
source /steps/return_license.sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Exit with code from the build step.
|
|
||||||
#
|
|
||||||
|
|
||||||
exit $BUILD_EXIT_CODE
|
|
||||||
File diff suppressed because one or more lines are too long
39
codecov.yml
Normal file
39
codecov.yml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
codecov:
|
||||||
|
require_ci_to_pass: yes
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
precision: 2
|
||||||
|
round: down
|
||||||
|
range: '70...100'
|
||||||
|
|
||||||
|
status:
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
# basic
|
||||||
|
target: auto
|
||||||
|
threshold: 100% # don't require patch to have coverage per se
|
||||||
|
base: auto
|
||||||
|
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
# basic
|
||||||
|
target: auto
|
||||||
|
threshold: 5%
|
||||||
|
base: auto
|
||||||
|
flags:
|
||||||
|
- unit
|
||||||
|
paths:
|
||||||
|
- 'src'
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: yes
|
||||||
|
loop: yes
|
||||||
|
method: no
|
||||||
|
macro: no
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: 'reach,diff,flags,tree'
|
||||||
|
behavior: default
|
||||||
|
require_changes: no
|
||||||
@@ -5,4 +5,5 @@ module.exports = {
|
|||||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||||
transform: { '^.+\\.(js|jsx)?$': 'babel-jest' },
|
transform: { '^.+\\.(js|jsx)?$': 'babel-jest' },
|
||||||
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
|
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
|
||||||
|
setupFilesAfterEnv: ['./src/jest.setup.js'],
|
||||||
};
|
};
|
||||||
|
|||||||
1
media/Discord-Logo.svg
Normal file
1
media/Discord-Logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 272.1"><style>.st0{fill:#7289DA;}</style><path class="st0" d="M142.8 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11s-4.6-11-10.2-11zM106.3 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11 .1-6.1-4.5-11-10.2-11z"/><path class="st0" d="M191.4 36.9h-134c-11.3 0-20.5 9.2-20.5 20.5v134c0 11.3 9.2 20.5 20.5 20.5h113.4l-5.3-18.3 12.8 11.8 12.1 11.1 21.6 18.7V57.4c-.1-11.3-9.3-20.5-20.6-20.5zm-38.6 129.5s-3.6-4.3-6.6-8c13.1-3.7 18.1-11.8 18.1-11.8-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.4-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.6-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.2-1.8-1-2.8-1.7-2.8-1.7s4.8 7.9 17.5 11.7c-3 3.8-6.7 8.2-6.7 8.2-22.1-.7-30.5-15.1-30.5-15.1 0-31.9 14.4-57.8 14.4-57.8 14.4-10.7 28-10.4 28-10.4l1 1.2c-18 5.1-26.2 13-26.2 13s2.2-1.2 5.9-2.8c10.7-4.7 19.2-5.9 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.5 0 0-7.9-7.5-24.9-12.6l1.4-1.6s13.7-.3 28 10.4c0 0 14.4 25.9 14.4 57.8 0-.1-8.4 14.3-30.5 15zM303.8 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1h33.2c17.8.1 34.5-8.8 34.5-29.2v-29.8c.1-20.8-16.6-29.9-34.4-29.9zm174 59.7v-30.6c0-11 19.8-13.5 25.8-2.5l18.3-7.4c-7.2-15.8-20.3-20.4-31.2-20.4-17.8 0-35.4 10.3-35.4 30.3v30.6c0 20.2 17.6 30.3 35 30.3 11.2 0 24.6-5.5 32-19.9l-19.6-9c-4.8 12.3-24.9 9.3-24.9-1.4zM417.3 113c-6.9-1.5-11.5-4-11.8-8.3.4-10.3 16.3-10.7 25.6-.8l14.7-11.3c-9.2-11.2-19.6-14.2-30.3-14.2-16.3 0-32.1 9.2-32.1 26.6 0 16.9 13 26 27.3 28.2 7.3 1 15.4 3.9 15.2 8.9-.6 9.5-20.2 9-29.1-1.8l-14.2 13.3c8.3 10.7 19.6 16.1 30.2 16.1 16.3 0 34.4-9.4 35.1-26.6 1-21.7-14.8-27.2-30.6-30.1zm-67 55.5h22.4V79.7h-22.4v88.8zM728 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1H728c17.8.1 34.5-8.8 34.5-29.2v-29.8c0-20.8-16.7-29.9-34.5-29.9zm-162.9-1.2c-18.4 0-36.7 10-36.7 30.5v30.3c0 20.3 18.4 30.5 36.9 30.5 18.4 0 36.7-10.2 36.7-30.5V109c0-20.4-18.5-30.5-36.9-30.5zm14.4 60.8c0 6.4-7.2 9.7-14.3 9.7-7.2 0-14.4-3.1-14.4-9.7V109c0-6.5 7-10 14-10 7.3 0 14.7 3.1 14.7 10v30.3zM682.4 109c-.5-20.8-14.7-29.2-33-29.2h-35.5v88.8h22.7v-28.2h4l20.6 28.2h28L665 138.1c10.7-3.4 17.4-12.7 17.4-29.1zm-32.6 12h-13.2v-20.3h13.2c14.1 0 14.1 20.3 0 20.3z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
BIN
media/UnityActions-ReferenceLogo.png
Normal file
BIN
media/UnityActions-ReferenceLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
media/UnityBuilder-Logo.png
Normal file
BIN
media/UnityBuilder-Logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
media/UnityCI-ReferenceLogo.png
Normal file
BIN
media/UnityCI-ReferenceLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
54
package.json
54
package.json
@@ -2,44 +2,49 @@
|
|||||||
"name": "unity-builder",
|
"name": "unity-builder",
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
"description": "Build Unity projects for different platforms.",
|
"description": "Build Unity projects for different platforms.",
|
||||||
"main": "builder/index.js",
|
"main": "action/index.js",
|
||||||
"repository": "git@github.com:webbertakken/unity-builder.git",
|
"repository": "git@github.com:webbertakken/unity-builder.git",
|
||||||
"author": "Webber <webber@takken.io>",
|
"author": "Webber <webber@takken.io>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ncc build src --out builder --minify",
|
"prebuild": "yarn",
|
||||||
|
"build": "ncc build src --out action --minify",
|
||||||
"lint": "prettier --check \"src/**/*.js\" && eslint src",
|
"lint": "prettier --check \"src/**/*.js\" && eslint src",
|
||||||
|
"format": "prettier --write \"src/**/*.js\"",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.2.0",
|
"@actions/core": "^1.2.6",
|
||||||
"@actions/exec": "1.0.2",
|
"@actions/exec": "1.0.4",
|
||||||
"@actions/github": "^2.0.0"
|
"@actions/github": "^2.1.1",
|
||||||
|
"base-64": "^0.1.0",
|
||||||
|
"kubernetes-client": "^9.0.0",
|
||||||
|
"semver": "^7.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "7.7.5",
|
"@babel/cli": "7.8.4",
|
||||||
"@babel/core": "7.7.5",
|
"@babel/core": "7.9.6",
|
||||||
"@babel/preset-env": "7.7.7",
|
"@babel/preset-env": "7.9.6",
|
||||||
"@zeit/ncc": "0.20.5",
|
"@zeit/ncc": "0.22.1",
|
||||||
"babel-eslint": "10.0.3",
|
"babel-eslint": "10.1.0",
|
||||||
"eslint": "6.7.2",
|
"eslint": "6.8.0",
|
||||||
"eslint-config-airbnb": "18.0.1",
|
"eslint-config-airbnb": "18.1.0",
|
||||||
"eslint-config-prettier": "6.7.0",
|
"eslint-config-prettier": "6.11.0",
|
||||||
"eslint-plugin-flowtype": "4.5.2",
|
"eslint-plugin-flowtype": "4.7.0",
|
||||||
"eslint-plugin-import": "2.19.1",
|
"eslint-plugin-import": "2.20.2",
|
||||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
"eslint-plugin-jsx-a11y": "6.2.3",
|
||||||
"eslint-plugin-prettier": "3.1.2",
|
"eslint-plugin-prettier": "3.1.3",
|
||||||
"eslint-plugin-react": "7.17.0",
|
"eslint-plugin-react": "7.19.0",
|
||||||
"eslint-plugin-unicorn": "14.0.1",
|
"eslint-plugin-unicorn": "19.0.1",
|
||||||
"husky": "4.0.0-beta.5",
|
"husky": "4.2.5",
|
||||||
"jest": "24.9.0",
|
"jest": "25.5.3",
|
||||||
"lint-staged": "9.5.0",
|
"lint-staged": "10.2.2",
|
||||||
"lodash-es": "4.17.15",
|
"lodash-es": "4.17.15",
|
||||||
"prettier": "1.19.1"
|
"prettier": "2.0.5"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged && yarn build && git add builder/index.js"
|
"pre-commit": "lint-staged && yarn build && git add action/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
@@ -52,6 +57,9 @@
|
|||||||
"*.{json,md,yaml,yml}": [
|
"*.{json,md,yaml,yml}": [
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"git add"
|
"git add"
|
||||||
|
],
|
||||||
|
"*.sh": [
|
||||||
|
"git update-index --chmod=+x"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/index.js
27
src/index.js
@@ -1,22 +1,29 @@
|
|||||||
import Action from './model/action';
|
import { Action, BuildParameters, Cache, Docker, ImageTag, Kubernetes, Output } from './model';
|
||||||
import Docker from './model/docker';
|
|
||||||
import ImageTag from './model/image-tag';
|
|
||||||
import Input from './model/input';
|
|
||||||
|
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
|
|
||||||
async function action() {
|
async function action() {
|
||||||
Action.checkCompatibility();
|
Action.checkCompatibility();
|
||||||
|
Cache.verify();
|
||||||
|
|
||||||
const { dockerfile, workspace, builderFolder } = Action;
|
const { dockerfile, workspace, actionFolder } = Action;
|
||||||
const { version, platform, projectPath, buildName, buildsPath, method } = Input.getFromUser();
|
|
||||||
|
|
||||||
const baseImage = new ImageTag({ version, platform });
|
const buildParameters = await BuildParameters.create();
|
||||||
const builtImage = await Docker.build({ path: builderFolder, dockerfile, baseImage });
|
const baseImage = new ImageTag(buildParameters);
|
||||||
|
if (buildParameters.kubeConfig) {
|
||||||
|
core.info('Building with Kubernetes');
|
||||||
|
await Kubernetes.runBuildJob(buildParameters, baseImage);
|
||||||
|
} else {
|
||||||
|
// Build docker image
|
||||||
|
// TODO: No image required (instead use a version published to dockerhub for the action, supply credentials for github cloning)
|
||||||
|
const builtImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
|
||||||
|
await Docker.run(builtImage, { workspace, ...buildParameters });
|
||||||
|
}
|
||||||
|
|
||||||
await Docker.run(builtImage, { workspace, platform, projectPath, buildName, buildsPath, method });
|
// Set output
|
||||||
|
await Output.setBuildVersion(buildParameters.buildVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
action().catch(error => {
|
action().catch((error) => {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
});
|
});
|
||||||
|
|||||||
49
src/jest.setup.js
Normal file
49
src/jest.setup.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
expect.extend({
|
||||||
|
toBeOfType(received, expectedType) {
|
||||||
|
const type = typeof received;
|
||||||
|
|
||||||
|
const pass = type === expectedType;
|
||||||
|
const message = () => `
|
||||||
|
Expected value to be of type ${this.utils.printExpected(expectedType)},
|
||||||
|
but received ${this.utils.printReceived(type)}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
pass,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
toBeEitherAFunctionOrAnObject(received) {
|
||||||
|
const type = typeof received;
|
||||||
|
|
||||||
|
const pass = ['object', 'function'].includes(type);
|
||||||
|
const message = () => `Expected a ${this.utils.printExpected('function')}
|
||||||
|
or an ${this.utils.printExpected('object')},
|
||||||
|
but received ${type}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
pass,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
toBeParsableToANumber(received) {
|
||||||
|
let pass = false;
|
||||||
|
let errorMessage = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
Number.parseInt(received, 10);
|
||||||
|
pass = true;
|
||||||
|
} catch (error) {
|
||||||
|
errorMessage = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = () => `Expected ${this.utils.printExpected(received)} to be parsable as a number
|
||||||
|
, but received error: ${this.utils.printReceived(errorMessage)}.`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
message,
|
||||||
|
pass,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
17
src/model/__mocks__/input.js
Normal file
17
src/model/__mocks__/input.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Import this named export into your test file:
|
||||||
|
import Platform from '../platform';
|
||||||
|
|
||||||
|
export const mockGetFromUser = jest.fn().mockResolvedValue({
|
||||||
|
version: '',
|
||||||
|
targetPlatform: Platform.types.Test,
|
||||||
|
projectPath: '.',
|
||||||
|
buildName: Platform.types.Test,
|
||||||
|
buildsPath: 'build',
|
||||||
|
buildMethod: undefined,
|
||||||
|
buildVersion: '1.3.37',
|
||||||
|
customParameters: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getFromUser: mockGetFromUser,
|
||||||
|
};
|
||||||
38
src/model/__mocks__/versioning.js
Normal file
38
src/model/__mocks__/versioning.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* eslint-disable unicorn/prevent-abbreviations */
|
||||||
|
|
||||||
|
// Import these named export into your test file:
|
||||||
|
export const mockProjectPath = jest.fn().mockResolvedValue('mockProjectPath');
|
||||||
|
export const mockIsDirtyAllowed = jest.fn().mockResolvedValue(false);
|
||||||
|
export const mockBranch = jest.fn().mockResolvedValue('mockBranch');
|
||||||
|
export const mockHeadRef = jest.fn().mockResolvedValue('mockHeadRef');
|
||||||
|
export const mockRef = jest.fn().mockResolvedValue('mockRef');
|
||||||
|
export const mockDetermineVersion = jest.fn().mockResolvedValue('1.2.3');
|
||||||
|
export const mockGenerateSemanticVersion = jest.fn().mockResolvedValue('2.3.4');
|
||||||
|
export const mockGenerateTagVersion = jest.fn().mockResolvedValue('1.0');
|
||||||
|
export const mockParseSemanticVersion = jest.fn().mockResolvedValue({});
|
||||||
|
export const mockFetch = jest.fn().mockImplementation(() => {});
|
||||||
|
export const mockGetVersionDescription = jest.fn().mockResolvedValue('1.2-3-g12345678-dirty');
|
||||||
|
export const mockIsDirty = jest.fn().mockResolvedValue(false);
|
||||||
|
export const mockGetTag = jest.fn().mockResolvedValue('v1.0');
|
||||||
|
export const mockHasAnyVersionTags = jest.fn().mockResolvedValue(true);
|
||||||
|
export const mockGetTotalNumberOfCommits = jest.fn().mockResolvedValue(3);
|
||||||
|
export const mockGit = jest.fn().mockImplementation(() => {});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
projectPath: mockProjectPath,
|
||||||
|
isDirtyAllowed: mockIsDirtyAllowed,
|
||||||
|
branch: mockBranch,
|
||||||
|
headRef: mockHeadRef,
|
||||||
|
ref: mockRef,
|
||||||
|
determineVersion: mockDetermineVersion,
|
||||||
|
generateSemanticVersion: mockGenerateSemanticVersion,
|
||||||
|
generateTagVersion: mockGenerateTagVersion,
|
||||||
|
parseSemanticVersion: mockParseSemanticVersion,
|
||||||
|
fetch: mockFetch,
|
||||||
|
getVersionDescription: mockGetVersionDescription,
|
||||||
|
isDirty: mockIsDirty,
|
||||||
|
getTag: mockGetTag,
|
||||||
|
hasAnyVersionTags: mockHasAnyVersionTags,
|
||||||
|
getTotalNumberOfCommits: mockGetTotalNumberOfCommits,
|
||||||
|
git: mockGit,
|
||||||
|
};
|
||||||
7
src/model/__snapshots__/versioning.test.js.snap
Normal file
7
src/model/__snapshots__/versioning.test.js.snap
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Versioning determineVersion throws for invalid strategy 0 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
||||||
|
|
||||||
|
exports[`Versioning determineVersion throws for invalid strategy somethingRandom 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
||||||
|
|
||||||
|
exports[`Versioning determineVersion throws for invalid strategy undefined 1`] = `"Versioning strategy should be one of None, Semantic, Tag, Custom."`;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
export default class Action {
|
class Action {
|
||||||
static get supportedPlatforms() {
|
static get supportedPlatforms() {
|
||||||
return ['linux'];
|
return ['linux'];
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,12 @@ export default class Action {
|
|||||||
return path.dirname(path.dirname(__filename));
|
return path.dirname(path.dirname(__filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
static get builderFolder() {
|
static get actionFolder() {
|
||||||
return `${Action.rootFolder}/builder`;
|
return `${Action.rootFolder}/action`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get dockerfile() {
|
static get dockerfile() {
|
||||||
return `${Action.builderFolder}/Dockerfile`;
|
return `${Action.actionFolder}/Dockerfile`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get workspace() {
|
static get workspace() {
|
||||||
@@ -44,3 +44,5 @@ export default class Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Action;
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ describe('Action', () => {
|
|||||||
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
|
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the builder folder', () => {
|
it('returns the action folder', () => {
|
||||||
const { builderFolder } = Action;
|
const { actionFolder } = Action;
|
||||||
|
|
||||||
expect(path.basename(builderFolder)).toStrictEqual('builder');
|
expect(path.basename(actionFolder)).toStrictEqual('action');
|
||||||
expect(fs.existsSync(builderFolder)).toStrictEqual(true);
|
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the docker file', () => {
|
it('returns the docker file', () => {
|
||||||
|
|||||||
33
src/model/android-versioning.js
Normal file
33
src/model/android-versioning.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as semver from 'semver';
|
||||||
|
|
||||||
|
export default class AndroidVersioning {
|
||||||
|
static determineVersionCode(version, inputVersionCode) {
|
||||||
|
if (!inputVersionCode) {
|
||||||
|
return AndroidVersioning.versionToVersionCode(version);
|
||||||
|
}
|
||||||
|
return inputVersionCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static versionToVersionCode(version) {
|
||||||
|
const parsedVersion = semver.parse(version);
|
||||||
|
|
||||||
|
if (!parsedVersion) {
|
||||||
|
core.warning(`Could not parse "${version}" to semver, defaulting android version code to 1`);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The greatest value Google Plays allows is 2100000000.
|
||||||
|
// 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) {
|
||||||
|
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.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
core.info(`Using android versionCode ${versionCode}`);
|
||||||
|
return versionCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/model/android-versioning.test.js
Normal file
27
src/model/android-versioning.test.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import AndroidVersioning from './android-versioning';
|
||||||
|
|
||||||
|
describe('Android Versioning', () => {
|
||||||
|
describe('versionToVersionCode', () => {
|
||||||
|
it('defaults to 1 when version is not a valid semver', () => {
|
||||||
|
expect(AndroidVersioning.versionToVersionCode('abcd')).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns a number', () => {
|
||||||
|
expect(AndroidVersioning.versionToVersionCode('123.456.789')).toBe(123456789);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throw when generated version code is too large', () => {
|
||||||
|
expect(() => AndroidVersioning.versionToVersionCode('1234.0.0')).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('determineVersionCode', () => {
|
||||||
|
it('defaults to parsed version', () => {
|
||||||
|
expect(AndroidVersioning.determineVersionCode('1.2.3', '')).toBe(1002003);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('use specified code', () => {
|
||||||
|
expect(AndroidVersioning.determineVersionCode('1.2.3', 2)).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
64
src/model/build-parameters.js
Normal file
64
src/model/build-parameters.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import AndroidVersioning from './android-versioning';
|
||||||
|
import Input from './input';
|
||||||
|
import Platform from './platform';
|
||||||
|
import Versioning from './versioning';
|
||||||
|
|
||||||
|
class BuildParameters {
|
||||||
|
static async create() {
|
||||||
|
const buildFile = this.parseBuildFile(
|
||||||
|
Input.buildName,
|
||||||
|
Input.targetPlatform,
|
||||||
|
Input.androidAppBundle,
|
||||||
|
);
|
||||||
|
const buildVersion = await Versioning.determineVersion(
|
||||||
|
Input.versioningStrategy,
|
||||||
|
Input.specifiedVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
const androidVersionCode = AndroidVersioning.determineVersionCode(
|
||||||
|
buildVersion,
|
||||||
|
Input.androidVersionCode,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: Input.unityVersion,
|
||||||
|
customImage: Input.customImage,
|
||||||
|
|
||||||
|
runnerTempPath: process.env.RUNNER_TEMP,
|
||||||
|
platform: Input.targetPlatform,
|
||||||
|
projectPath: Input.projectPath,
|
||||||
|
buildName: Input.buildName,
|
||||||
|
buildPath: `${Input.buildsPath}/${Input.targetPlatform}`,
|
||||||
|
buildFile,
|
||||||
|
buildMethod: Input.buildMethod,
|
||||||
|
buildVersion,
|
||||||
|
androidVersionCode,
|
||||||
|
androidKeystoreName: Input.androidKeystoreName,
|
||||||
|
androidKeystoreBase64: Input.androidKeystoreBase64,
|
||||||
|
androidKeystorePass: Input.androidKeystorePass,
|
||||||
|
androidKeyaliasName: Input.androidKeyaliasName,
|
||||||
|
androidKeyaliasPass: Input.androidKeyaliasPass,
|
||||||
|
customParameters: Input.customParameters,
|
||||||
|
kubeConfig: Input.kubeConfig,
|
||||||
|
githubToken: Input.githubToken,
|
||||||
|
kubeContainerMemory: Input.kubeContainerMemory,
|
||||||
|
kubeContainerCPU: Input.kubeContainerCPU,
|
||||||
|
kubeVolumeSize: Input.kubeVolumeSize,
|
||||||
|
kubeVolume: Input.kubeVolume,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseBuildFile(filename, platform, androidAppBundle) {
|
||||||
|
if (Platform.isWindows(platform)) {
|
||||||
|
return `${filename}.exe`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform.isAndroid(platform)) {
|
||||||
|
return androidAppBundle ? `${filename}.aab` : `${filename}.apk`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BuildParameters;
|
||||||
177
src/model/build-parameters.test.js
Normal file
177
src/model/build-parameters.test.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import Versioning from './versioning';
|
||||||
|
import BuildParameters from './build-parameters';
|
||||||
|
import Input from './input';
|
||||||
|
import Platform from './platform';
|
||||||
|
|
||||||
|
const determineVersion = jest
|
||||||
|
.spyOn(Versioning, 'determineVersion')
|
||||||
|
.mockImplementation(() => '1.3.37');
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('BuildParameters', () => {
|
||||||
|
describe('create', () => {
|
||||||
|
it('does not throw', async () => {
|
||||||
|
await expect(BuildParameters.create()).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('determines the version only once', async () => {
|
||||||
|
await BuildParameters.create();
|
||||||
|
expect(determineVersion).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the version', async () => {
|
||||||
|
const mockValue = 'someVersion';
|
||||||
|
jest.spyOn(Input, 'unityVersion', 'get').mockReturnValue(mockValue);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ version: mockValue }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the platform', async () => {
|
||||||
|
const mockValue = 'somePlatform';
|
||||||
|
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(mockValue);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ platform: 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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the build path', async () => {
|
||||||
|
const mockPath = 'somePath';
|
||||||
|
const mockPlatform = 'somePlatform';
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
|
||||||
|
'appends exe for %s',
|
||||||
|
async (targetPlatform) => {
|
||||||
|
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||||
|
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildFile: `${targetPlatform}.exe` }),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each([Platform.types.Android])('appends apk for %s', async (targetPlatform) => {
|
||||||
|
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.objectContaining({ buildFile: `${targetPlatform}.apk` }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([Platform.types.Android])('appends aab for %s', async (targetPlatform) => {
|
||||||
|
jest.spyOn(Input, 'targetPlatform', 'get').mockReturnValue(targetPlatform);
|
||||||
|
jest.spyOn(Input, 'buildName', 'get').mockReturnValue(targetPlatform);
|
||||||
|
jest.spyOn(Input, 'androidAppBundle', 'get').mockReturnValue(true);
|
||||||
|
await expect(BuildParameters.create()).resolves.toEqual(
|
||||||
|
expect.objectContaining({ buildFile: `${targetPlatform}.aab` }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the build method', async () => {
|
||||||
|
const mockValue = 'Namespace.ClassName.BuildMethod';
|
||||||
|
jest.spyOn(Input, 'buildMethod', 'get').mockReturnValue(mockValue);
|
||||||
|
await 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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
26
src/model/cache.js
Normal file
26
src/model/cache.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import * as core from '@actions/core';
|
||||||
|
import fs from 'fs';
|
||||||
|
import Action from './action';
|
||||||
|
import Project from './project';
|
||||||
|
|
||||||
|
class Cache {
|
||||||
|
static verify() {
|
||||||
|
if (!fs.existsSync(Project.libraryFolder)) {
|
||||||
|
this.notifyAboutCachingPossibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static notifyAboutCachingPossibility() {
|
||||||
|
if (Action.isRunningLocally) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.warning(`
|
||||||
|
Library folder does not exist.
|
||||||
|
Consider setting up caching to speed up your workflow,
|
||||||
|
if this is not your first build.
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cache;
|
||||||
11
src/model/cache.test.js
Normal file
11
src/model/cache.test.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import Cache from './cache';
|
||||||
|
|
||||||
|
jest.mock('./input');
|
||||||
|
|
||||||
|
describe('Cache', () => {
|
||||||
|
describe('Verification', () => {
|
||||||
|
it('does not throw', () => {
|
||||||
|
expect(() => Cache.verify()).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { exec } from '@actions/exec';
|
import { exec } from '@actions/exec';
|
||||||
import ImageTag from './image-tag';
|
import ImageTag from './image-tag';
|
||||||
|
|
||||||
export default class Docker {
|
class Docker {
|
||||||
static async build(buildParameters, silent = false) {
|
static async build(buildParameters, silent = false) {
|
||||||
const { path, dockerfile, baseImage } = buildParameters;
|
const { path, dockerfile, baseImage } = buildParameters;
|
||||||
const { version, platform } = baseImage;
|
const { version, platform } = baseImage;
|
||||||
@@ -12,28 +12,55 @@ export default class Docker {
|
|||||||
--build-arg IMAGE=${baseImage} \
|
--build-arg IMAGE=${baseImage} \
|
||||||
--tag ${tag}`;
|
--tag ${tag}`;
|
||||||
|
|
||||||
await exec(command, null, { silent });
|
await exec(command, undefined, { silent });
|
||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async run(image, parameters, silent = false) {
|
static async run(image, parameters, silent = false) {
|
||||||
const { workspace, platform, projectPath, buildName, buildsPath, method } = parameters;
|
const {
|
||||||
const { version } = image;
|
version,
|
||||||
|
workspace,
|
||||||
|
runnerTempPath,
|
||||||
|
platform,
|
||||||
|
projectPath,
|
||||||
|
buildName,
|
||||||
|
buildPath,
|
||||||
|
buildFile,
|
||||||
|
buildMethod,
|
||||||
|
buildVersion,
|
||||||
|
androidVersionCode,
|
||||||
|
androidKeystoreName,
|
||||||
|
androidKeystoreBase64,
|
||||||
|
androidKeystorePass,
|
||||||
|
androidKeyaliasName,
|
||||||
|
androidKeyaliasPass,
|
||||||
|
customParameters,
|
||||||
|
} = parameters;
|
||||||
|
|
||||||
const command = `docker run \
|
const command = `docker run \
|
||||||
--workdir /github/workspace \
|
--workdir /github/workspace \
|
||||||
--rm \
|
--rm \
|
||||||
--env UNITY_LICENSE \
|
--env UNITY_LICENSE \
|
||||||
|
--env UNITY_LICENSE_FILE \
|
||||||
--env UNITY_EMAIL \
|
--env UNITY_EMAIL \
|
||||||
--env UNITY_PASSWORD \
|
--env UNITY_PASSWORD \
|
||||||
--env UNITY_SERIAL \
|
--env UNITY_SERIAL \
|
||||||
--env UNITY_VERSION=${version} \
|
--env UNITY_VERSION="${version}" \
|
||||||
--env PROJECT_PATH=${projectPath} \
|
--env PROJECT_PATH="${projectPath}" \
|
||||||
--env BUILD_TARGET=${platform} \
|
--env BUILD_TARGET="${platform}" \
|
||||||
--env BUILD_NAME=${buildName} \
|
--env BUILD_NAME="${buildName}" \
|
||||||
--env BUILDS_PATH=${buildsPath} \
|
--env BUILD_PATH="${buildPath}" \
|
||||||
--env BUILD_METHOD=${method} \
|
--env BUILD_FILE="${buildFile}" \
|
||||||
|
--env BUILD_METHOD="${buildMethod}" \
|
||||||
|
--env VERSION="${buildVersion}" \
|
||||||
|
--env ANDROID_VERSION_CODE="${androidVersionCode}" \
|
||||||
|
--env ANDROID_KEYSTORE_NAME="${androidKeystoreName}" \
|
||||||
|
--env ANDROID_KEYSTORE_BASE64="${androidKeystoreBase64}" \
|
||||||
|
--env ANDROID_KEYSTORE_PASS="${androidKeystorePass}" \
|
||||||
|
--env ANDROID_KEYALIAS_NAME="${androidKeyaliasName}" \
|
||||||
|
--env ANDROID_KEYALIAS_PASS="${androidKeyaliasPass}" \
|
||||||
|
--env CUSTOM_PARAMETERS="${customParameters}" \
|
||||||
--env HOME=/github/home \
|
--env HOME=/github/home \
|
||||||
--env GITHUB_REF \
|
--env GITHUB_REF \
|
||||||
--env GITHUB_SHA \
|
--env GITHUB_SHA \
|
||||||
@@ -51,11 +78,13 @@ export default class Docker {
|
|||||||
--env RUNNER_TEMP \
|
--env RUNNER_TEMP \
|
||||||
--env RUNNER_WORKSPACE \
|
--env RUNNER_WORKSPACE \
|
||||||
--volume "/var/run/docker.sock":"/var/run/docker.sock" \
|
--volume "/var/run/docker.sock":"/var/run/docker.sock" \
|
||||||
--volume "/home/runner/work/_temp/_github_home":"/github/home" \
|
--volume "${runnerTempPath}/_github_home":"/github/home" \
|
||||||
--volume "/home/runner/work/_temp/_github_workflow":"/github/workflow" \
|
--volume "${runnerTempPath}/_github_workflow":"/github/workflow" \
|
||||||
--volume "${workspace}":"/github/workspace" \
|
--volume "${workspace}":"/github/workspace" \
|
||||||
${image}`;
|
${image}`;
|
||||||
|
|
||||||
await exec(command, null, { silent });
|
await exec(command, undefined, { silent });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Docker;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import Docker from './docker';
|
|||||||
import ImageTag from './image-tag';
|
import ImageTag from './image-tag';
|
||||||
|
|
||||||
describe('Docker', () => {
|
describe('Docker', () => {
|
||||||
it('builds', async () => {
|
it.skip('builds', async () => {
|
||||||
const path = Action.builderFolder;
|
const path = Action.actionFolder;
|
||||||
const dockerfile = `${path}/Dockerfile`;
|
const dockerfile = `${path}/Dockerfile`;
|
||||||
const baseImage = new ImageTag({
|
const baseImage = new ImageTag({
|
||||||
repository: '',
|
repository: '',
|
||||||
@@ -12,24 +12,19 @@ describe('Docker', () => {
|
|||||||
version: '3',
|
version: '3',
|
||||||
platform: 'Test',
|
platform: 'Test',
|
||||||
});
|
});
|
||||||
|
|
||||||
const tag = await Docker.build({ path, dockerfile, baseImage }, true);
|
const tag = await Docker.build({ path, dockerfile, baseImage }, true);
|
||||||
|
|
||||||
expect(tag).toBeInstanceOf(ImageTag);
|
expect(tag).toBeInstanceOf(ImageTag);
|
||||||
expect(tag.toString()).toStrictEqual('unity-builder:3');
|
expect(tag.toString()).toStrictEqual('unity-builder:3');
|
||||||
}, 240000);
|
}, 240000);
|
||||||
|
|
||||||
it.skip('runs', async () => {
|
it.skip('runs', async () => {
|
||||||
const image = 'unity-builder:2019.2.11f1-webgl';
|
const image = 'unity-builder:2019.2.11f1-webgl';
|
||||||
|
|
||||||
const parameters = {
|
const parameters = {
|
||||||
workspace: Action.rootFolder,
|
workspace: Action.rootFolder,
|
||||||
projectPath: `${Action.rootFolder}/test-project`,
|
projectPath: `${Action.rootFolder}/test-project`,
|
||||||
buildName: 'someBulidName',
|
buildName: 'someBuildName',
|
||||||
buildsPath: 'build',
|
buildsPath: 'build',
|
||||||
method: '',
|
method: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
await Docker.run(image, parameters);
|
await Docker.run(image, parameters);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
8
src/model/error/command-execution-error.js
Normal file
8
src/model/error/command-execution-error.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
class CommandExecutionError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'CommandExecutionError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CommandExecutionError;
|
||||||
14
src/model/error/command-execution-error.test.js
Normal file
14
src/model/error/command-execution-error.test.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import CommandExecutionError from './command-execution-error';
|
||||||
|
|
||||||
|
describe('CommandExecutionError', () => {
|
||||||
|
it('instantiates', () => {
|
||||||
|
expect(() => new CommandExecutionError()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
|
||||||
|
const error = new CommandExecutionError(message);
|
||||||
|
|
||||||
|
expect(error.name).toStrictEqual('CommandExecutionError');
|
||||||
|
expect(error.message).toStrictEqual(message.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
8
src/model/error/not-implemented-exception.js
Normal file
8
src/model/error/not-implemented-exception.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
class NotImplementedException extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'NotImplementedException';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NotImplementedException;
|
||||||
14
src/model/error/not-implemented-exception.test.js
Normal file
14
src/model/error/not-implemented-exception.test.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import NotImplementedException from './not-implemented-exception';
|
||||||
|
|
||||||
|
describe('NotImplementedException', () => {
|
||||||
|
it('instantiates', () => {
|
||||||
|
expect(() => new NotImplementedException()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
|
||||||
|
const error = new NotImplementedException(message);
|
||||||
|
|
||||||
|
expect(error.name).toStrictEqual('NotImplementedException');
|
||||||
|
expect(error.message).toStrictEqual(message.toString());
|
||||||
|
});
|
||||||
|
});
|
||||||
8
src/model/error/validation-error.js
Normal file
8
src/model/error/validation-error.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
class ValidationError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'ValidationError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ValidationError;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user