mirror of
https://github.com/game-ci/unity-test-runner.git
synced 2026-01-29 06:20:07 +08:00
Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fe2feb3c9 | ||
|
|
68d1df1d1b | ||
|
|
698c08cf4e | ||
|
|
5263cf0ab1 | ||
|
|
3bffd88e03 | ||
|
|
45ec546c43 | ||
|
|
26c9b7abe1 | ||
|
|
811160c5b3 | ||
|
|
3d5d2f5834 | ||
|
|
e8774f3837 | ||
|
|
d95f760d49 | ||
|
|
96562463cf | ||
|
|
ec4f39253f | ||
|
|
67402dce6f | ||
|
|
50a3bd4138 | ||
|
|
f87ed30c30 | ||
|
|
29ad0eb103 | ||
|
|
8324e03548 | ||
|
|
33bc4be9fa | ||
|
|
538792b218 | ||
|
|
79715c7e78 | ||
|
|
174e562151 | ||
|
|
2a6814ff04 | ||
|
|
905eb66d7f | ||
|
|
aa7a119f32 | ||
|
|
6b2660eabd | ||
|
|
cb6c63f07a | ||
|
|
cdfccd0aad | ||
|
|
87b202c6d9 | ||
|
|
8a69fc6be3 | ||
|
|
f61055d56f | ||
|
|
79e50e3e4f | ||
|
|
576ef39bb6 | ||
|
|
a2b1ed6631 | ||
|
|
3e969f16b2 | ||
|
|
20387ae1e0 | ||
|
|
e13aeebe33 | ||
|
|
02c0e7b60c | ||
|
|
7563db4160 | ||
|
|
19201393f1 | ||
|
|
9488ba6d77 | ||
|
|
dfd8e1e91f | ||
|
|
c56b66a41b | ||
|
|
4d6a166cb7 | ||
|
|
6838fda7a4 | ||
|
|
cf55f1c921 | ||
|
|
ad11a10dc8 | ||
|
|
5aaa7eff53 | ||
|
|
19661e2da7 | ||
|
|
5eca106c01 | ||
|
|
0674feac28 | ||
|
|
6ec7057a28 | ||
|
|
f95bef8f16 | ||
|
|
4a3465923a | ||
|
|
1fcc491cbe | ||
|
|
73c6b8aa34 | ||
|
|
694c315276 | ||
|
|
fffbf11b2a | ||
|
|
a195213baa | ||
|
|
8033066291 | ||
|
|
215f660c06 | ||
|
|
43d90c252f | ||
|
|
345f4c64bd | ||
|
|
d45ca4403f | ||
|
|
7dd059111b | ||
|
|
5edc17bb8a | ||
|
|
23b6b8f5f3 | ||
|
|
6e30d4827d | ||
|
|
50e6471ee4 | ||
|
|
6a039cc828 | ||
|
|
2656f4e108 | ||
|
|
e1be8325cd | ||
|
|
26807aaf05 | ||
|
|
a9d07b742d | ||
|
|
0c3e710069 | ||
|
|
a067c3d5ab | ||
|
|
3fca186a7b | ||
|
|
a8b9742ecd | ||
|
|
31cd755121 | ||
|
|
679222c549 | ||
|
|
29899d84e8 | ||
|
|
7d26e264b9 | ||
|
|
bac0f97d2f | ||
|
|
c4e44617e2 | ||
|
|
25e14f52b8 | ||
|
|
3a40ffcf5f | ||
|
|
3277792c11 | ||
|
|
ac2e8a74d0 | ||
|
|
8107d46ab7 | ||
|
|
a4e8475a2f | ||
|
|
f02586c1c9 | ||
|
|
31ae95179d | ||
|
|
cd86c7302b | ||
|
|
21831e61ad | ||
|
|
7c1cba9a39 | ||
|
|
29e179f50b | ||
|
|
2fa69494ad | ||
|
|
4e717f6c82 | ||
|
|
173716a8a9 | ||
|
|
3c915726f4 | ||
|
|
5cfdb7ee17 | ||
|
|
51648a5093 | ||
|
|
2297daa673 | ||
|
|
7711f454ba | ||
|
|
b518514f36 | ||
|
|
7e50ed34dd | ||
|
|
c85e37ca1f | ||
|
|
58f580c801 | ||
|
|
4ba71aefa9 | ||
|
|
bed834cb73 | ||
|
|
eb51009c09 | ||
|
|
da74d9ff8c | ||
|
|
c8a0e2865a | ||
|
|
627cf8f914 | ||
|
|
e9b4db003e | ||
|
|
45a1728dfb | ||
|
|
f854b54cb0 | ||
|
|
6948da8f6a | ||
|
|
922dcd8b1a | ||
|
|
c8909e4d5e | ||
|
|
060d1856e7 | ||
|
|
6bacc4484e | ||
|
|
892b3b8279 | ||
|
|
00afc45f14 | ||
|
|
868c383d7f | ||
|
|
54d8d414ea | ||
|
|
057deedeb0 | ||
|
|
d64e5a8b19 | ||
|
|
711a3ee644 | ||
|
|
39da97ffa3 | ||
|
|
1473c8f431 | ||
|
|
c210544758 | ||
|
|
f863c717a4 | ||
|
|
5423e61ad7 | ||
|
|
377244a880 | ||
|
|
6f1c3ded0c | ||
|
|
b181c9cdbe | ||
|
|
d5a5335100 | ||
|
|
c937b9ed6c | ||
|
|
56b8c04f36 | ||
|
|
a18b837919 | ||
|
|
033a0990cb | ||
|
|
24fe88806a | ||
|
|
e2f2badc29 | ||
|
|
3ccd77fd44 | ||
|
|
686f633329 | ||
|
|
28154ea36e | ||
|
|
2ca91788af | ||
|
|
2d11601618 | ||
|
|
545600f75b | ||
|
|
d6c937fe37 | ||
|
|
d105f8c891 | ||
|
|
048c75a66e | ||
|
|
a08a398026 | ||
|
|
311b685893 | ||
|
|
3d7f5a853b | ||
|
|
b846d206bc | ||
|
|
2bcc487a09 | ||
|
|
ae2ae7470f | ||
|
|
02ff2d03e1 | ||
|
|
f8bd2b7266 | ||
|
|
d1b98bf91e | ||
|
|
fd4bc863ba | ||
|
|
98f19717b4 | ||
|
|
8f88c85bbf | ||
|
|
7a50426e16 | ||
|
|
503c7cb617 |
@@ -2,5 +2,4 @@
|
||||
*
|
||||
|
||||
# Files required for the action
|
||||
!entrypoint.sh
|
||||
!action.yml
|
||||
!dist/
|
||||
|
||||
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
||||
tab_width = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
max_line_length = off
|
||||
|
||||
[COMMIT_EDITMSG]
|
||||
max_line_length = off
|
||||
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
jest.config.js
|
||||
25
.eslintrc.json
Normal file
25
.eslintrc.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"plugins": ["jest", "@typescript-eslint", "prettier", "unicorn"],
|
||||
"extends": ["plugin:unicorn/recommended", "plugin:github/recommended", "prettier"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"import/no-namespace": "off",
|
||||
"filenames/match-regex": "off",
|
||||
"unicorn/prefer-node-protocol": "off",
|
||||
"unicorn/prefer-module": "off",
|
||||
"i18n-text/no-en": "off", // for results-check
|
||||
"camelcase": "off", // for results-check
|
||||
"import/no-unresolved": "off" // for results-check
|
||||
}
|
||||
}
|
||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
dist/index* -diff linguist-generated=true
|
||||
dist/licenses* -diff linguist-generated=true
|
||||
dist/sourcemap* -diff linguist-generated=true
|
||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: game-ci
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # replace with a single OpenCollective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
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.-->
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discuss on Discord
|
||||
url: https://game.ci/discord
|
||||
about: Join our Discord community
|
||||
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 a new 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: ''
|
||||
---
|
||||
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
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)
|
||||
16
.github/workflows/cats.yml
vendored
Normal file
16
.github/workflows/cats.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Cats 😺
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
aCatForCreatingThePullRequest:
|
||||
name: A cat for your effort!
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: ruairidhwm/action-cats@1.0.2
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
265
.github/workflows/main.yml
vendored
265
.github/workflows/main.yml
vendored
@@ -1,111 +1,290 @@
|
||||
name: Actions 😎
|
||||
on: [push]
|
||||
on:
|
||||
push: { branches: [main] }
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
|
||||
env:
|
||||
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"576562626572264761624c65526f7578\"/>\n <Binding Key=\"2\" Value=\"576562626572264761624c65526f7578\"/>\n </MachineBindings>\n <MachineID Value=\"D7nTUnjNAmtsUMcnoyrqkgIbYdM=\"/>\n <SerialHash Value=\"2033b8ac3e6faa3742ca9f0bfae44d18f2a96b80\"/>\n <Features>\n <Feature Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature Value=\"62\"/>\n </Features>\n <DeveloperData Value=\"AQAAAEY0LUJHUlgtWEQ0RS1aQ1dWLUM1SlctR0RIQg==\"/>\n <SerialMasked Value=\"F4-BGRX-XD4E-ZCWV-C5JW-XXXX\"/>\n <StartDate Value=\"2021-02-08T00:00:00\"/>\n <UpdateDate Value=\"2021-02-09T00:34:57\"/>\n <InitialActivationDate Value=\"2021-02-08T00:34:56\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2018.4.30f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n <Entitlement Ns=\"unity_editor\" Tag=\"DarkSkin\" Type=\"EDITOR_FEATURE\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>m0Db8UK+ktnOLJBtHybkfetpcKo=</DigestValue></Reference></SignedInfo><SignatureValue>o/pUbSQAukz7+ZYAWhnA0AJbIlyyCPL7bKVEM2lVqbrXt7cyey+umkCXamuOgsWPVUKBMkXtMH8L\n5etLmD0getWIhTGhzOnDCk+gtIPfL4jMo9tkEuOCROQAXCci23VFscKcrkB+3X6h4wEOtA2APhOY\nB+wvC794o8/82ffjP79aVAi57rp3Wmzx+9pe9yMwoJuljAy2sc2tIMgdQGWVmOGBpQm3JqsidyzI\nJWG2kjnc7pDXK9pwYzXoKiqUqqrut90d+kQqRyv7MSZXR50HFqD/LI69h68b7P8Bjo3bPXOhNXGR\n9YCoemH6EkfCJxp2gIjzjWW+l2Hj2EsFQi8YXw==</SignatureValue></Signature></root>"
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
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 action || { echo "ERROR - index.js is different from repository version. Forgot to run `yarn build`?" ; exit 62; }
|
||||
|
||||
testAllModesLikeInTheReadme:
|
||||
name: Test in ${{ matrix.testMode }} on version ${{ matrix.unityVersion }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- unity-project-with-correct-tests
|
||||
unityVersion:
|
||||
- 2019.2.11f1
|
||||
testMode:
|
||||
- playmode
|
||||
- editmode
|
||||
steps:
|
||||
###########################
|
||||
# Checkout #
|
||||
###########################
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
###########################
|
||||
# Cache #
|
||||
###########################
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}
|
||||
restore-keys: |
|
||||
Library-
|
||||
- uses: ./
|
||||
id: tests
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: ${{ matrix.testMode }}
|
||||
artifactsPath: ${{ matrix.testMode }}-artifacts
|
||||
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test results for ${{ matrix.testMode }}
|
||||
path: ${{ steps.tests.outputs.artifactsPath }}
|
||||
retention-days: 14
|
||||
|
||||
testRunnerInAllModes:
|
||||
name: Test all modes ✨
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- unity-project-with-correct-tests
|
||||
unityVersion:
|
||||
- 2019.2.11f1
|
||||
steps:
|
||||
# Checkout repository (required to test local actions)
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
###########################
|
||||
# Checkout #
|
||||
###########################
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
###########################
|
||||
# Cache #
|
||||
###########################
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
|
||||
restore-keys: |
|
||||
Library-${{ matrix.projectPath }}-
|
||||
Library-
|
||||
|
||||
# Configure test runner
|
||||
- name: Run tests
|
||||
id: allTests
|
||||
uses: ./
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
TEST_MODE: all
|
||||
UNITY_PROJECT_PATH: unity-project-with-correct-tests
|
||||
# Test implicit ARTIFACTS_PATH, by not setting it
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: all
|
||||
coverageOptions: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:+MyScripts'
|
||||
# Test implicit artifactsPath, by not setting it
|
||||
|
||||
# Upload artifacts
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test results (all)
|
||||
path: ${{ steps.allTests.outputs.artifactsPath }}
|
||||
retention-days: 14
|
||||
|
||||
# Upload coverage
|
||||
- name: Upload coverage results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Coverage results (all)
|
||||
path: ${{ steps.allTests.outputs.coveragePath }}
|
||||
retention-days: 14
|
||||
|
||||
testRunnerInEditMode:
|
||||
name: Test edit mode 📝
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
unityVersion:
|
||||
- 2019.2.11f1
|
||||
projectPath:
|
||||
- unity-project-with-correct-tests
|
||||
steps:
|
||||
# Checkout repository (required to test local actions)
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
###########################
|
||||
# Checkout #
|
||||
###########################
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
###########################
|
||||
# Cache #
|
||||
###########################
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
|
||||
restore-keys: |
|
||||
Library-${{ matrix.projectPath }}-
|
||||
Library-
|
||||
|
||||
# Configure test runner
|
||||
- name: Run tests
|
||||
id: editMode
|
||||
uses: ./
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
TEST_MODE: editmode
|
||||
UNITY_PROJECT_PATH: unity-project-with-correct-tests
|
||||
ARTIFACTS_PATH: artifacts/editmode
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: editmode
|
||||
artifactsPath: artifacts/editmode
|
||||
|
||||
# Upload artifacts
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test results (edit mode)
|
||||
path: ${{ steps.editMode.outputs.artifactsPath }}
|
||||
retention-days: 14
|
||||
|
||||
# Upload coverage
|
||||
- name: Upload coverage results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Coverage results (edit mode)
|
||||
path: ${{ steps.editMode.outputs.coveragePath }}
|
||||
retention-days: 14
|
||||
|
||||
testRunnerInPlayMode:
|
||||
name: Test play mode 📺
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
projectPath:
|
||||
- unity-project-with-correct-tests
|
||||
unityVersion:
|
||||
- 2019.2.11f1
|
||||
steps:
|
||||
# Checkout repository (required to test local actions)
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
###########################
|
||||
# Checkout #
|
||||
###########################
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
###########################
|
||||
# Cache #
|
||||
###########################
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
|
||||
restore-keys: |
|
||||
Library-${{ matrix.projectPath }}-
|
||||
Library-
|
||||
|
||||
# Configure test runner
|
||||
- name: Run tests
|
||||
id: playMode
|
||||
uses: ./
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
TEST_MODE: playmode
|
||||
UNITY_PROJECT_PATH: unity-project-with-correct-tests
|
||||
ARTIFACTS_PATH: artifacts/editmode
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: playmode
|
||||
artifactsPath: artifacts/playmode
|
||||
|
||||
# Upload artifacts
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test results (play mode)
|
||||
path: ${{ steps.playMode.outputs.artifactsPath }}
|
||||
retention-days: 14
|
||||
|
||||
testRunnerInEachModeSeparately:
|
||||
# Upload coverage
|
||||
- name: Upload coverage results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Coverage results (play mode)
|
||||
path: ${{ steps.playMode.outputs.coveragePath }}
|
||||
retention-days: 14
|
||||
|
||||
testEachModeSequentially:
|
||||
name: Test each mode sequentially 👩👩👧👦 # don't try this at home (it's much slower)
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
unityVersion:
|
||||
- 2019.2.11f1
|
||||
projectPath:
|
||||
- unity-project-with-correct-tests
|
||||
steps:
|
||||
# Checkout repository (required to test local actions)
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
###########################
|
||||
# Checkout #
|
||||
###########################
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
###########################
|
||||
# Cache #
|
||||
###########################
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
|
||||
restore-keys: |
|
||||
Library-${{ matrix.projectPath }}-
|
||||
Library-
|
||||
|
||||
# Configure first test runner
|
||||
- name: Tests in editmode 📝
|
||||
uses: ./
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
TEST_MODE: editmode
|
||||
UNITY_PROJECT_PATH: unity-project-with-correct-tests
|
||||
ARTIFACTS_PATH: artifacts/editmode
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: editmode
|
||||
artifactsPath: artifacts/editmode
|
||||
|
||||
# Configure second test runner
|
||||
- name: Tests in playmode 📺
|
||||
uses: ./
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
TEST_MODE: playmode
|
||||
UNITY_PROJECT_PATH: unity-project-with-correct-tests
|
||||
ARTIFACTS_PATH: artifacts/playmode
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
testMode: playmode
|
||||
artifactsPath: artifacts/playmode
|
||||
|
||||
# Upload combined artifacts
|
||||
- name: Upload combined test results
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test results (combined)
|
||||
path: artifacts/
|
||||
retention-days: 14
|
||||
|
||||
12
.github/workflows/versioning.yml
vendored
Normal file
12
.github/workflows/versioning.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: Versioning
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published, edited]
|
||||
|
||||
jobs:
|
||||
updateMajorTag:
|
||||
name: Update major tag
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Actions-R-Us/actions-tagger@v2
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
.idea
|
||||
node_modules
|
||||
coverage/
|
||||
lib/
|
||||
|
||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
||||
13
.husky/pre-commit
Normal file
13
.husky/pre-commit
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
if [ -t 1 ]; then
|
||||
exec < /dev/tty
|
||||
fi
|
||||
|
||||
yarn lint-staged
|
||||
yarn lint
|
||||
yarn test
|
||||
|
||||
yarn build
|
||||
git add dist
|
||||
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
**/node_modules/**
|
||||
**/dist/**
|
||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
3
.yarnrc
Normal file
3
.yarnrc
Normal file
@@ -0,0 +1,3 @@
|
||||
save-prefix "^"
|
||||
--install.audit true
|
||||
--add.audit true
|
||||
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at webber@takken.io. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
39
CONTRIBUTING.md
Normal file
39
CONTRIBUTING.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Contributing
|
||||
|
||||
## How to Contribute
|
||||
|
||||
#### Code of Conduct
|
||||
|
||||
This repository has adopted the Contributor Covenant as it's
|
||||
Code of Conduct. It is expected that participants adhere to it.
|
||||
|
||||
#### Proposing a Change
|
||||
|
||||
If you are unsure about whether or not a change is desired,
|
||||
you can create an issue. This is useful because it creates
|
||||
the possibility for a discussion that's visible to everyone.
|
||||
|
||||
When fixing a bug it is fine to submit a pull request right away.
|
||||
|
||||
#### Sending a Pull Request
|
||||
|
||||
Steps to be performed to submit a pull request:
|
||||
|
||||
1. Fork the repository and create your branch from `main`.
|
||||
2. Run `yarn` in the repository root.
|
||||
3. If you've fixed a bug or added code that should be tested, add tests!
|
||||
4. Fill out the description, link any related issues and submit your pull request.
|
||||
|
||||
#### Pull Request Prerequisites
|
||||
|
||||
You have [Node](https://nodejs.org/) installed at v12.2.0+ and [Yarn](https://yarnpkg.com/) at v1.18.0+.
|
||||
|
||||
Please note that commit hooks will run automatically to perform some tasks;
|
||||
|
||||
- format your code
|
||||
- run tests & lint - `yarn lint && yarn test`
|
||||
- build distributable files - `yarn build`
|
||||
|
||||
#### License
|
||||
|
||||
By contributing to this repository, you agree that your contributions will be licensed under its MIT license.
|
||||
14
Dockerfile
14
Dockerfile
@@ -1,14 +0,0 @@
|
||||
FROM gableroux/unity3d:2019.2.11f1
|
||||
|
||||
LABEL "com.github.actions.name"="Unity - Test runner"
|
||||
LABEL "com.github.actions.description"="Run tests for any Unity project."
|
||||
LABEL "com.github.actions.icon"="box"
|
||||
LABEL "com.github.actions.color"="gray-dark"
|
||||
|
||||
LABEL "repository"="http://github.com/webbertakken/unity-actions"
|
||||
LABEL "homepage"="http://github.com/webbertakken/unity-actions"
|
||||
LABEL "maintainer"="Webber Takken <webber@takken.io>"
|
||||
|
||||
ADD entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
86
README.md
86
README.md
@@ -1,66 +1,52 @@
|
||||
# Unity - Test runner
|
||||
[](https://github.com/WebberTakken/unity-test-runner/workflows/Actions%20%F0%9F%98%8E/badge.svg)
|
||||
|
||||
[Github Action](https://github.com/features/actions)
|
||||
to run tests for any Unity project.
|
||||
(Not affiliated with Unity Technologies)
|
||||
|
||||
This is a recommended step to prepare your pipeline for using the
|
||||
[Build](https://github.com/webbertakken/unity-actions#build)
|
||||
action from the
|
||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
||||
collection.
|
||||
GitHub Action to
|
||||
[run tests](https://github.com/marketplace/actions/unity-test-runner)
|
||||
for any Unity project.
|
||||
|
||||
Requires the [activation](https://github.com/marketplace/actions/unity-activate) step.
|
||||
Part of the <a href="https://game.ci">GameCI</a> open source project.
|
||||
<br />
|
||||
<br />
|
||||
|
||||
## Usage
|
||||
[](https://github.com/game-ci/unity-test-runner/actions?query=workflow%3A%22Actions+%F0%9F%98%8E%22)
|
||||
<br />
|
||||
<br />
|
||||
|
||||
Create or edit the file called `.github/workflows/activation.yml` and add a job to it.
|
||||
## How to use
|
||||
|
||||
```yaml
|
||||
name: Test project
|
||||
on: [push]
|
||||
jobs:
|
||||
testRunnerInAllModes:
|
||||
name: Test all modes ✨
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
```
|
||||
Find the
|
||||
[docs](https://game.ci/docs/github/test-runner)
|
||||
on the GameCI
|
||||
[documentation website](https://game.ci/docs).
|
||||
|
||||
Configure the test runner as follows:
|
||||
## Related actions
|
||||
|
||||
```yaml
|
||||
# Configure test runner
|
||||
- name: Run tests
|
||||
id: myTestStep
|
||||
uses: webbertakken/unity-test-runner@v1
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
Visit the
|
||||
GameCI <a href="https://github.com/game-ci/unity-actions">Unity Actions</a>
|
||||
status repository for related Actions.
|
||||
|
||||
# Choose: "all", "playmode", "editmode"
|
||||
TEST_MODE: all
|
||||
|
||||
# Optional: Path to your project, leave blank for "./"
|
||||
UNITY_PROJECT_PATH: relative/path/to/your/project
|
||||
## Community
|
||||
|
||||
# Optional: Artifacts path, leave blank for "artifacts"
|
||||
ARTIFACTS_PATH: store/artifacts/here
|
||||
```
|
||||
Feel free to join us on
|
||||
<a href="http://game.ci/discord"><img height="30" src="media/Discord-Logo.svg" alt="Discord" /></a>
|
||||
and engage with the community.
|
||||
|
||||
You use the id to **upload the artifacts** like so:
|
||||
## Contributing
|
||||
|
||||
```yaml
|
||||
# Upload artifacts
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: Test results
|
||||
path: ${{ steps.myTestStep.outputs.artifactsPath }}
|
||||
```
|
||||
To help improve the documentation, please find the docs [repository](https://github.com/game-ci/documentation).
|
||||
|
||||
Commit and push your workflow definition.
|
||||
To contribute to this project, kindly read the [contribution guide](./CONTRIBUTING.md).
|
||||
|
||||
## More actions
|
||||
## Support us
|
||||
|
||||
Visit
|
||||
[Unity Actions](https://github.com/webbertakken/unity-actions)
|
||||
to find related actions for Unity.
|
||||
GameCI is free for everyone forever.
|
||||
|
||||
You can support us at [OpenCollective](https://opencollective.com/game-ci).
|
||||
|
||||
## Licence
|
||||
|
||||
This repository is [MIT](./LICENSE) licensed.
|
||||
|
||||
This includes all contributions from the community.
|
||||
|
||||
63
action.yml
63
action.yml
@@ -1,13 +1,66 @@
|
||||
name: 'Unity - Test runner'
|
||||
author: Webber Takken <webber@takken.io>
|
||||
description: 'Run tests for any Unity project.'
|
||||
inputs: {}
|
||||
inputs:
|
||||
unityVersion:
|
||||
required: false
|
||||
default: 'auto'
|
||||
description: 'Version of unity to use for testing the project. Use "auto" to get from your ProjectSettings/ProjectVersion.txt'
|
||||
customImage:
|
||||
required: false
|
||||
default: ''
|
||||
description: 'Specific docker image that should be used for testing the project'
|
||||
projectPath:
|
||||
required: false
|
||||
description: 'Path to the Unity project to be tested.'
|
||||
customParameters:
|
||||
required: false
|
||||
description: 'Extra parameters to configure the Unity editor run.'
|
||||
testMode:
|
||||
required: false
|
||||
default: 'all'
|
||||
description: 'The type of tests to be run by the test runner.'
|
||||
coverageOptions:
|
||||
required: false
|
||||
default: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport'
|
||||
description: 'Optional coverage parameters for the -coverageOptions argument.'
|
||||
artifactsPath:
|
||||
required: false
|
||||
default: 'artifacts'
|
||||
description: 'Path where test artifacts should be stored.'
|
||||
useHostNetwork:
|
||||
required: false
|
||||
default: false
|
||||
description: 'Initialises Docker using the host network.'
|
||||
sshAgent:
|
||||
required: false
|
||||
default: ''
|
||||
description: 'SSH Agent path to forward to the container.'
|
||||
gitPrivateToken:
|
||||
required: false
|
||||
default: ''
|
||||
description: 'GitHub Private Access Token (PAT) to pull from GitHub.'
|
||||
githubToken:
|
||||
required: false
|
||||
default: ''
|
||||
description: 'Token to authorize access to the GitHub REST API. If provided, a check run will be created with the test results.'
|
||||
checkName:
|
||||
required: false
|
||||
default: 'Test Results'
|
||||
description: 'Name for the check run that is created when a github token is provided.'
|
||||
chownFilesTo:
|
||||
required: false
|
||||
default: ''
|
||||
description: 'User and optionally group (user or user:group or uid:gid) to give ownership of the resulting build artifacts'
|
||||
outputs:
|
||||
artifactsPath:
|
||||
description: 'Path where the artifacts are stored'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
description: 'Path where the artifacts are stored.'
|
||||
coveragePath:
|
||||
description: 'Path where the code coverage results are stored.'
|
||||
branding:
|
||||
icon: 'box'
|
||||
color: 'gray-dark'
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/main.js'
|
||||
post: 'dist/post.js'
|
||||
|
||||
81
artifacts/editmode-results.xml
Normal file
81
artifacts/editmode-results.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<test-run id="2" testcasecount="6" result="Failed(Child)" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0" engine-version="3.5.0.0" clr-version="4.0.30319.42000" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.1168037">
|
||||
<test-suite type="TestSuite" id="1012" name="sample-project" fullname="sample-project" runstate="Runnable" testcasecount="6" result="Failed" site="Child" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.116804" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="Assembly" id="1020" name="Editor.dll" fullname="/github/workspace/unity-project/Library/ScriptAssemblies/Editor.dll" runstate="Runnable" testcasecount="6" result="Failed" site="Child" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.087946" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties>
|
||||
<property name="_PID" value="78" />
|
||||
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||
<property name="platform" value="EditMode" />
|
||||
</properties>
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="TestSuite" id="1021" name="Editor" fullname="Editor" runstate="Runnable" testcasecount="6" result="Failed" site="Child" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.086212" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="TestFixture" id="1013" name="EditorModeTest" fullname="Editor.EditorModeTest" classname="Editor.EditorModeTest" runstate="Runnable" testcasecount="6" result="Failed" site="Child" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.076416" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<output><![CDATA[You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
|
||||
]]></output>
|
||||
<test-case id="1016" name="FailedTest" fullname="Editor.EditorModeTest.FailedTest" methodname="FailedTest" classname="Editor.EditorModeTest" runstate="Runnable" seed="330279882" result="Failed" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.023093" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[ Expected: True
|
||||
But was: False
|
||||
]]></message>
|
||||
<stack-trace><![CDATA[at Editor.EditorModeTest.FailedTest () [0x00000] in /github/workspace/unity-project/Assets/Editor/EditorModeTest.cs:21
|
||||
]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
<test-case id="1019" name="FailedUnityTest" fullname="Editor.EditorModeTest.FailedUnityTest" methodname="FailedUnityTest" classname="Editor.EditorModeTest" runstate="Runnable" seed="347277877" result="Failed" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.014203" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
</properties>
|
||||
<failure>
|
||||
<message><![CDATA[ Expected: True
|
||||
But was: False
|
||||
]]></message>
|
||||
<stack-trace><![CDATA[at Editor.EditorModeTest+<FailedUnityTest>d__5.MoveNext () [0x0002e] in /github/workspace/unity-project/Assets/Editor/EditorModeTest.cs:40
|
||||
at UnityEngine.TestTools.TestEnumerator+<Execute>d__6.MoveNext () [0x00038] in /github/workspace/unity-project/Library/PackageCache/com.unity.test-framework@1.1.19/UnityEngine.TestRunner/NUnitExtensions/Attributes/TestEnumerator.cs:36
|
||||
]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
<test-case id="1015" name="IgnoredTest" fullname="Editor.EditorModeTest.IgnoredTest" methodname="IgnoredTest" classname="Editor.EditorModeTest" runstate="Ignored" seed="1319288303" result="Skipped" label="Ignored" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.000218" asserts="0">
|
||||
<properties>
|
||||
<property name="_SKIPREASON" value="ignore" />
|
||||
</properties>
|
||||
<reason>
|
||||
<message><![CDATA[ignore]]></message>
|
||||
</reason>
|
||||
</test-case>
|
||||
<test-case id="1018" name="IgnoredUnityTest" fullname="Editor.EditorModeTest.IgnoredUnityTest" methodname="IgnoredUnityTest" classname="Editor.EditorModeTest" runstate="Ignored" seed="2034877647" result="Skipped" label="Ignored" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.000004" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
<property name="_SKIPREASON" value="ignore" />
|
||||
</properties>
|
||||
<reason>
|
||||
<message><![CDATA[ignore]]></message>
|
||||
</reason>
|
||||
</test-case>
|
||||
<test-case id="1014" name="PassedTest" fullname="Editor.EditorModeTest.PassedTest" methodname="PassedTest" classname="Editor.EditorModeTest" runstate="Runnable" seed="387558551" result="Passed" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.000366" asserts="0">
|
||||
<properties />
|
||||
</test-case>
|
||||
<test-case id="1017" name="PassedUnityTest" fullname="Editor.EditorModeTest.PassedUnityTest" methodname="PassedUnityTest" classname="Editor.EditorModeTest" runstate="Runnable" seed="1069930397" result="Passed" start-time="2021-01-19 20:51:34Z" end-time="2021-01-19 20:51:34Z" duration="0.007903" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
</properties>
|
||||
</test-case>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-run>
|
||||
111
artifacts/playmode-results.xml
Normal file
111
artifacts/playmode-results.xml
Normal file
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<test-run id="2" testcasecount="8" result="Failed(Child)" total="8" passed="2" failed="4" inconclusive="0" skipped="2" asserts="0" engine-version="3.5.0.0" clr-version="4.0.30319.42000" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.1055695">
|
||||
<test-suite type="TestSuite" id="1000" name="sample-project" fullname="sample-project" runstate="Runnable" testcasecount="8" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.105570" total="8" passed="2" failed="4" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="Assembly" id="1012" name="Assembly-CSharp.dll" fullname="/github/workspace/unity-project/Library/ScriptAssemblies/Assembly-CSharp.dll" runstate="Runnable" testcasecount="8" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.088008" total="8" passed="2" failed="4" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties>
|
||||
<property name="_PID" value="474" />
|
||||
<property name="_APPDOMAIN" value="Unity Child Domain" />
|
||||
<property name="platform" value="PlayMode" />
|
||||
</properties>
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="TestSuite" id="1013" name="Tests" fullname="Tests" runstate="Runnable" testcasecount="8" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.084864" total="8" passed="2" failed="4" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-suite type="TestFixture" id="1001" name="PlayModeTest" fullname="Tests.PlayModeTest" classname="Tests.PlayModeTest" runstate="Runnable" testcasecount="6" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.074407" total="6" passed="2" failed="2" inconclusive="0" skipped="2" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-case id="1004" name="FailedTest" fullname="Tests.PlayModeTest.FailedTest" methodname="FailedTest" classname="Tests.PlayModeTest" runstate="Runnable" seed="1067965392" result="Failed" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.034377" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[ Expected: True
|
||||
But was: False
|
||||
]]></message>
|
||||
<stack-trace><![CDATA[at Tests.PlayModeTest.FailedTest () [0x00000] in /github/workspace/unity-project/Assets/Tests/PlayModeTest.cs:20
|
||||
]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
<test-case id="1007" name="FailedUnityTest" fullname="Tests.PlayModeTest.FailedUnityTest" methodname="FailedUnityTest" classname="Tests.PlayModeTest" runstate="Runnable" seed="318345342" result="Failed" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.009524" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
</properties>
|
||||
<failure>
|
||||
<message><![CDATA[ Expected: True
|
||||
But was: False
|
||||
]]></message>
|
||||
<stack-trace><![CDATA[at Tests.PlayModeTest+<FailedUnityTest>d__5.MoveNext () [0x0002e] in /github/workspace/unity-project/Assets/Tests/PlayModeTest.cs:39
|
||||
at UnityEngine.TestTools.TestEnumerator+<Execute>d__6.MoveNext () [0x00038] in /github/workspace/unity-project/Library/PackageCache/com.unity.test-framework@1.1.19/UnityEngine.TestRunner/NUnitExtensions/Attributes/TestEnumerator.cs:36
|
||||
]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
<test-case id="1003" name="IgnoredTest" fullname="Tests.PlayModeTest.IgnoredTest" methodname="IgnoredTest" classname="Tests.PlayModeTest" runstate="Ignored" seed="1914466070" result="Skipped" label="Ignored" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.000211" asserts="0">
|
||||
<properties>
|
||||
<property name="_SKIPREASON" value="ignore" />
|
||||
</properties>
|
||||
<reason>
|
||||
<message><![CDATA[ignore]]></message>
|
||||
</reason>
|
||||
</test-case>
|
||||
<test-case id="1006" name="IgnoredUnityTest" fullname="Tests.PlayModeTest.IgnoredUnityTest" methodname="IgnoredUnityTest" classname="Tests.PlayModeTest" runstate="Ignored" seed="475291067" result="Skipped" label="Ignored" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.000004" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
<property name="_SKIPREASON" value="ignore" />
|
||||
</properties>
|
||||
<reason>
|
||||
<message><![CDATA[ignore]]></message>
|
||||
</reason>
|
||||
</test-case>
|
||||
<test-case id="1002" name="PassedTest" fullname="Tests.PlayModeTest.PassedTest" methodname="PassedTest" classname="Tests.PlayModeTest" runstate="Runnable" seed="635988114" result="Passed" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.000400" asserts="0">
|
||||
<properties />
|
||||
</test-case>
|
||||
<test-case id="1005" name="PassedUnityTest" fullname="Tests.PlayModeTest.PassedUnityTest" methodname="PassedUnityTest" classname="Tests.PlayModeTest" runstate="Runnable" seed="881217608" result="Passed" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.000736" asserts="0">
|
||||
<properties>
|
||||
<property name="_JOINTYPE" value="UnityCombinatorial" />
|
||||
</properties>
|
||||
</test-case>
|
||||
</test-suite>
|
||||
<test-suite type="TestFixture" id="1008" name="SetupFailedTest" fullname="Tests.SetupFailedTest" classname="Tests.SetupFailedTest" runstate="Runnable" testcasecount="1" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.004318" total="1" passed="0" failed="1" inconclusive="0" skipped="0" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-case id="1009" name="PassedTest" fullname="Tests.SetupFailedTest.PassedTest" methodname="PassedTest" classname="Tests.SetupFailedTest" runstate="Runnable" seed="1423699315" result="Failed" label="Error" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.003206" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[SetUp : System.NullReferenceException : Object reference not set to an instance of an object]]></message>
|
||||
<stack-trace><![CDATA[--SetUp
|
||||
at Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10
|
||||
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
|
||||
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <9577ac7a62ef43179789031239ba8798>:0 ]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
</test-suite>
|
||||
<test-suite type="TestFixture" id="1010" name="TearDownFailedTest" fullname="Tests.TearDownFailedTest" classname="Tests.TearDownFailedTest" runstate="Runnable" testcasecount="1" result="Failed" site="Child" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.001857" total="1" passed="0" failed="1" inconclusive="0" skipped="0" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[One or more child tests had errors]]></message>
|
||||
</failure>
|
||||
<test-case id="1011" name="PassedTest" fullname="Tests.TearDownFailedTest.PassedTest" methodname="PassedTest" classname="Tests.TearDownFailedTest" runstate="Runnable" seed="1384928637" result="Failed" label="Error" start-time="2021-01-19 20:51:44Z" end-time="2021-01-19 20:51:44Z" duration="0.000755" asserts="0">
|
||||
<properties />
|
||||
<failure>
|
||||
<message><![CDATA[TearDown : System.NullReferenceException : Object reference not set to an instance of an object]]></message>
|
||||
<stack-trace><![CDATA[--TearDown
|
||||
at Tests.TearDownFailedTest.TearDown () [0x00000] in /github/workspace/unity-project/Assets/Tests/TearDownFailedTest.cs:10
|
||||
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[],System.Exception&)
|
||||
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in <9577ac7a62ef43179789031239ba8798>:0 ]]></stack-trace>
|
||||
</failure>
|
||||
</test-case>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-suite>
|
||||
</test-run>
|
||||
48
dist/entrypoint.ps1
vendored
Normal file
48
dist/entrypoint.ps1
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# Create directory for license activation
|
||||
#
|
||||
|
||||
$ACTIVATE_LICENSE_PATH = "${env:GITHUB_WORKSPACE}/_activate-license"
|
||||
New-Item -Path "$ACTIVATE_LICENSE_PATH" -ItemType Directory
|
||||
|
||||
#
|
||||
# Run steps
|
||||
#
|
||||
|
||||
& $PSScriptRoot\steps\activate.ps1
|
||||
& $PSScriptRoot\steps\set_gitcredential.ps1
|
||||
& $PSScriptRoot\steps\run_tests.ps1
|
||||
& $PSScriptRoot\steps\return_license.ps1
|
||||
|
||||
#
|
||||
# Remove license activation directory
|
||||
#
|
||||
|
||||
Remove-Item "$ACTIVATE_LICENSE_PATH" -Recurse -Force
|
||||
|
||||
#
|
||||
# Instructions for debugging
|
||||
#
|
||||
|
||||
if ($TEST_RUNNER_EXIT_CODE -gt 0)
|
||||
{
|
||||
Write-Output ""
|
||||
Write-Output "###########################"
|
||||
Write-Output "# Failure #"
|
||||
Write-Output "###########################"
|
||||
Write-Output ""
|
||||
Write-Output "Please note that the exit code is not very descriptive."
|
||||
Write-Output "Most likely it will not help you solve the issue."
|
||||
Write-Output ""
|
||||
Write-Output "To find the reason for failure: please search for errors in the log above."
|
||||
Write-Output ""
|
||||
}
|
||||
|
||||
#
|
||||
# Exit with code from the build step.
|
||||
#
|
||||
|
||||
if ( ($USE_EXIT_CODE -eq "true") -and ($TEST_RUNNER_EXIT_CODE -ne 2) )
|
||||
{
|
||||
exit $TEST_RUNNER_EXIT_CODE
|
||||
}
|
||||
48
dist/entrypoint.sh
vendored
Executable file
48
dist/entrypoint.sh
vendored
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# Create directory for license activation
|
||||
#
|
||||
|
||||
ACTIVATE_LICENSE_PATH="$GITHUB_WORKSPACE/_activate-license"
|
||||
mkdir -p "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
#
|
||||
# Run steps
|
||||
#
|
||||
|
||||
source /steps/activate.sh
|
||||
source /steps/set_gitcredential.sh
|
||||
source /steps/run_tests.sh
|
||||
source /steps/return_license.sh
|
||||
|
||||
#
|
||||
# Remove license activation directory
|
||||
#
|
||||
|
||||
rm -r "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
#
|
||||
# Instructions for debugging
|
||||
#
|
||||
|
||||
if [[ $TEST_RUNNER_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.
|
||||
#
|
||||
|
||||
if [[ $USE_EXIT_CODE == true || $TEST_RUNNER_EXIT_CODE -ne 2 ]]; then
|
||||
exit $TEST_RUNNER_EXIT_CODE
|
||||
fi;
|
||||
23647
dist/index.js
generated
vendored
Normal file
23647
dist/index.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/index.js.map
generated
vendored
Normal file
1
dist/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
784
dist/licenses.txt
generated
vendored
Normal file
784
dist/licenses.txt
generated
vendored
Normal file
@@ -0,0 +1,784 @@
|
||||
@actions/core
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/exec
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/github
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@actions/http-client
|
||||
MIT
|
||||
Actions Http Client for Node.js
|
||||
|
||||
Copyright (c) GitHub, Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@actions/io
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2019 GitHub
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@octokit/auth-token
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/core
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/endpoint
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2018 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/graphql
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2018 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/plugin-paginate-rest
|
||||
MIT
|
||||
MIT License Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/plugin-rest-endpoint-methods
|
||||
MIT
|
||||
MIT License Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/request
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2018 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@octokit/request-error
|
||||
MIT
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 Octokit contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
@vercel/ncc
|
||||
MIT
|
||||
Copyright 2018 ZEIT, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
before-after-hook
|
||||
Apache-2.0
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 Gregor Martynus and other contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
deprecation
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Gregor Martynus and contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
handlebars
|
||||
MIT
|
||||
Copyright (C) 2011-2019 by Yehuda Katz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
is-plain-object
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017, Jon Schlinkert.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
node-fetch
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 David Frank
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
||||
once
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
sax
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
====
|
||||
|
||||
`String.fromCodePoint` by Mathias Bynens used according to terms of MIT
|
||||
License, as follows:
|
||||
|
||||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
source-map
|
||||
BSD-3-Clause
|
||||
|
||||
Copyright (c) 2009-2011, Mozilla Foundation and contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the Mozilla Foundation nor the names of project
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
tr46
|
||||
MIT
|
||||
|
||||
tunnel
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 Koichi Kobayashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
universal-user-agent
|
||||
ISC
|
||||
# [ISC License](https://spdx.org/licenses/ISC)
|
||||
|
||||
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
uuid
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
webidl-conversions
|
||||
BSD-2-Clause
|
||||
# The BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2014, Domenic Denicola
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
whatwg-url
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015–2016 Sebastian Mayr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
wrappy
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
xml-js
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2017 Yousuf Almarzooqi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1
dist/main.js
vendored
Symbolic link
1
dist/main.js
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
index.js
|
||||
1
dist/post.js
vendored
Symbolic link
1
dist/post.js
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
index.js
|
||||
22
dist/results-check-details.hbs
vendored
Normal file
22
dist/results-check-details.hbs
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{{#runs}}
|
||||
|
||||
<details><summary>{{summary}}</summary>
|
||||
|
||||
{{#suites}}
|
||||
* {{summary}}
|
||||
{{#tests}}
|
||||
* {{summary}}
|
||||
{{#if annotation}}
|
||||
{{#if annotation.message}}
|
||||
{{indent annotation.message}}
|
||||
{{/if}}
|
||||
{{#if annotation.raw_details}}
|
||||
{{indent annotation.raw_details}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/tests}}
|
||||
{{/suites}}
|
||||
|
||||
</details>
|
||||
|
||||
{{/runs}}
|
||||
3
dist/results-check-summary.hbs
vendored
Normal file
3
dist/results-check-summary.hbs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{{#runs}}
|
||||
### {{summary}}
|
||||
{{/runs}}
|
||||
1
dist/sourcemap-register.js
generated
vendored
Normal file
1
dist/sourcemap-register.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
110
dist/steps/activate.ps1
vendored
Normal file
110
dist/steps/activate.ps1
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# Run in ACTIVATE_LICENSE_PATH directory
|
||||
Write-Output "Changing to $ACTIVATE_LICENSE_PATH directory."
|
||||
Push-Location "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
if ( ($null -ne ${env:UNITY_LICENSE}) -or ($null -ne ${env:UNITY_LICENSE_FILE}) )
|
||||
{
|
||||
#
|
||||
# PERSONAL LICENSE MODE
|
||||
#
|
||||
# This will activate Unity, using a license file
|
||||
#
|
||||
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
|
||||
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
|
||||
#
|
||||
# The license file can be acquired using `game-ci/request-manual-activation-file` action.
|
||||
Write-Output "Requesting activation (personal license)"
|
||||
|
||||
# Set the license file path
|
||||
$FILE_PATH = "$ACTIVATE_LICENSE_PATH\UnityLicenseFile.ulf"
|
||||
|
||||
if ($null -ne ${env:UNITY_LICENSE})
|
||||
{
|
||||
# Copy license file from Github variables
|
||||
Add-Content -Path $FILE_PATH -Value ${env:UNITY_LICENSE}
|
||||
}
|
||||
elseif ($null -ne ${env:UNITY_LICENSE_FILE})
|
||||
{
|
||||
# Copy license file from file system
|
||||
Add-Content -Path $FILE_PATH -Value ${env:UNITY_LICENSE_FILE}
|
||||
}
|
||||
$convert = (Get-Content -Raw $FILE_PATH) -replace "`r`n","`n"
|
||||
[io.file]::WriteAllText($FILE_PATH, $convert)
|
||||
Get-ChildItem -Path $FILE_PATH
|
||||
|
||||
# Activate license
|
||||
$ACTIVATION_OUTPUT = Start-Process -NoNewWindow -Wait -PassThru "C:\Program Files\Unity\Hub\Editor\${env:UNITY_VERSION}\editor\Unity.exe" -ArgumentList "-batchmode -nographics -logFile $ACTIVATE_LICENSE_PATH\activate.log -quit -manualLicenseFile $FILE_PATH"
|
||||
|
||||
# Store the exit code from the verify command
|
||||
$UNITY_EXIT_CODE = $ACTIVATION_OUTPUT.ExitCode
|
||||
|
||||
# The exit code for personal activation is always 1;
|
||||
# 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 = (Get-Content $ACTIVATE_LICENSE_PATH\activate.log | Select-String 'Next license update check is after' | Measure-Object -line | Select-Object -Expand Lines)
|
||||
|
||||
# Set exit code to 0 if activation was successful
|
||||
if ($ACTIVATION_SUCCESSFUL -eq 1)
|
||||
{
|
||||
$UNITY_EXIT_CODE = 0
|
||||
}
|
||||
|
||||
# Remove license file
|
||||
Remove-Item -Force $FILE_PATH
|
||||
}
|
||||
elseif ( ($null -ne ${env:UNITY_SERIAL}) -and ($null -ne ${env:UNITY_EMAIL}) -and ($null -ne ${env:UNITY_PASSWORD}) )
|
||||
{
|
||||
#
|
||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
||||
#
|
||||
# This will activate unity, using the activating process.
|
||||
#
|
||||
# Note: This is the preferred way for PROFESSIONAL LICENSES.
|
||||
#
|
||||
Write-Output "Requesting activation (professional license)"
|
||||
|
||||
# Activate license
|
||||
$ACTIVATION_OUTPUT = Start-Process -NoNewWindow -Wait -PassThru "C:\Program Files\Unity\Hub\Editor\${env:UNITY_VERSION}\editor\Unity.exe" -ArgumentList "-batchmode -nographics -logFile $ACTIVATE_LICENSE_PATH\activate.log -quit -serial ${env:UNITY_SERIAL} -username ${env:UNITY_EMAIL} -password ${env:UNITY_PASSWORD}"
|
||||
|
||||
# Store the exit code from the verify command
|
||||
$UNITY_EXIT_CODE = $ACTIVATION_OUTPUT.ExitCode
|
||||
}
|
||||
else
|
||||
{
|
||||
#
|
||||
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||
#
|
||||
# This will exit since no activation strategies could be matched.
|
||||
#
|
||||
Write-Output "License activation strategy could not be determined."
|
||||
Write-Output ""
|
||||
Write-Output "Visit https://game.ci/docs/github/getting-started for more"
|
||||
Write-Output "details on how to set up one of the possible activation strategies."
|
||||
|
||||
# Immediately exit as no UNITY_EXIT_CODE can be derived.
|
||||
exit 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Display information about the result
|
||||
#
|
||||
Get-Content $ACTIVATE_LICENSE_PATH\activate.log
|
||||
if ($UNITY_EXIT_CODE -eq 0)
|
||||
{
|
||||
# Activation was a success
|
||||
Write-Output "Activation complete."
|
||||
}
|
||||
else
|
||||
{
|
||||
# Activation failed so exit with the code from the license verification step
|
||||
Write-Output "Unclassified error occured while trying to activate license."
|
||||
Write-Output "Exit code was: $UNITY_EXIT_CODE"
|
||||
exit $UNITY_EXIT_CODE
|
||||
}
|
||||
|
||||
# Return to previous working directory
|
||||
Pop-Location
|
||||
125
dist/steps/activate.sh
vendored
Executable file
125
dist/steps/activate.sh
vendored
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Run in ACTIVATE_LICENSE_PATH directory
|
||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||
pushd "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
if [[ -n "$UNITY_LICENSE" ]] || [[ -n "$UNITY_LICENSE_FILE" ]]; then
|
||||
#
|
||||
# PERSONAL LICENSE MODE
|
||||
#
|
||||
# This will activate Unity, using a license file
|
||||
#
|
||||
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
|
||||
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
|
||||
#
|
||||
# The license file can be acquired using `game-ci/request-manual-activation-file` action.
|
||||
echo "Requesting activation (personal license)"
|
||||
|
||||
# Set the license file path
|
||||
FILE_PATH=UnityLicenseFile.ulf
|
||||
|
||||
if [[ -n "$UNITY_LICENSE" ]]; then
|
||||
# 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
|
||||
ACTIVATION_OUTPUT=$(unity-editor \
|
||||
-batchmode \
|
||||
-nographics \
|
||||
-logFile /dev/stdout \
|
||||
-quit \
|
||||
-manualLicenseFile $FILE_PATH)
|
||||
|
||||
# Store the exit code from the verify command
|
||||
UNITY_EXIT_CODE=$?
|
||||
|
||||
# The exit code for personal activation is always 1;
|
||||
# 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
|
||||
rm -f $FILE_PATH
|
||||
|
||||
elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
|
||||
#
|
||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
||||
#
|
||||
# This will activate unity, using the activating process.
|
||||
#
|
||||
# Note: This is the preferred way for PROFESSIONAL LICENSES.
|
||||
#
|
||||
echo "Requesting activation (professional license)"
|
||||
|
||||
# Activate license
|
||||
unity-editor \
|
||||
-batchmode \
|
||||
-nographics \
|
||||
-logFile /dev/stdout \
|
||||
-quit \
|
||||
-serial "$UNITY_SERIAL" \
|
||||
-username "$UNITY_EMAIL" \
|
||||
-password "$UNITY_PASSWORD"
|
||||
|
||||
# Store the exit code from the verify command
|
||||
UNITY_EXIT_CODE=$?
|
||||
elif [[ -n "$UNITY_LICENSING_SERVER" ]]; then
|
||||
#
|
||||
# Custom Unity License Server
|
||||
#
|
||||
echo "Adding licensing server config"
|
||||
|
||||
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --acquire-floating > license.txt #is this accessible in a env variable?
|
||||
UNITY_EXIT_CODE=$?
|
||||
PARSEDFILE=$(grep -oP '\".*?\"' < license.txt | tr -d '"')
|
||||
export FLOATING_LICENSE
|
||||
FLOATING_LICENSE=$(sed -n 2p <<< "$PARSEDFILE")
|
||||
FLOATING_LICENSE_TIMEOUT=$(sed -n 4p <<< "$PARSEDFILE")
|
||||
|
||||
echo "Acquired floating license: \"$FLOATING_LICENSE\" with timeout $FLOATING_LICENSE_TIMEOUT"
|
||||
# Store the exit code from the verify command
|
||||
else
|
||||
#
|
||||
# NO LICENSE ACTIVATION STRATEGY MATCHED
|
||||
#
|
||||
# This will exit since no activation strategies could be matched.
|
||||
#
|
||||
echo "License activation strategy could not be determined."
|
||||
echo ""
|
||||
echo "Visit https://game.ci/docs/github/getting-started for more"
|
||||
echo "details on how to set up one of the possible activation strategies."
|
||||
|
||||
# Immediately exit as no UNITY_EXIT_CODE can be derived.
|
||||
exit 1;
|
||||
|
||||
fi
|
||||
|
||||
#
|
||||
# Display information about the result
|
||||
#
|
||||
if [ $UNITY_EXIT_CODE -eq 0 ]; then
|
||||
# Activation was a success
|
||||
echo "Activation complete."
|
||||
else
|
||||
# Activation failed so exit with the code from the license verification step
|
||||
echo "Unclassified error occured while trying to activate license."
|
||||
echo "Exit code was: $UNITY_EXIT_CODE"
|
||||
exit $UNITY_EXIT_CODE
|
||||
fi
|
||||
|
||||
# Return to previous working directory
|
||||
popd
|
||||
18
dist/steps/return_license.ps1
vendored
Normal file
18
dist/steps/return_license.ps1
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Run in ACTIVATE_LICENSE_PATH directory
|
||||
Write-Output "Changing to $ACTIVATE_LICENSE_PATH directory."
|
||||
Push-Location "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
if ($null -ne ${env:UNITY_SERIAL})
|
||||
{
|
||||
#
|
||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
||||
#
|
||||
# This will return the license that is currently in use.
|
||||
#
|
||||
$RETURN_OUTPUT = Start-Process -NoNewWindow -Wait -PassThru "C:\Program Files\Unity\Hub\Editor\${env:UNITY_VERSION}\editor\Unity.exe" -ArgumentList "-batchmode -nographics -logFile $FULL_ARTIFACTS_PATH\deactivate.log -quit -returnlicense"
|
||||
|
||||
Get-Content $FULL_ARTIFACTS_PATH\deactivate.log
|
||||
}
|
||||
|
||||
# Return to previous working directory
|
||||
Pop-Location
|
||||
27
dist/steps/return_license.sh
vendored
Executable file
27
dist/steps/return_license.sh
vendored
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Run in ACTIVATE_LICENSE_PATH directory
|
||||
echo "Changing to \"$ACTIVATE_LICENSE_PATH\" directory."
|
||||
pushd "$ACTIVATE_LICENSE_PATH"
|
||||
|
||||
if [[ -n "$UNITY_LICENSING_SERVER" ]]; then #
|
||||
#
|
||||
# Return any floating license used.
|
||||
#
|
||||
echo "Returning floating license: \"$FLOATING_LICENSE\""
|
||||
/opt/unity/Editor/Data/Resources/Licensing/Client/Unity.Licensing.Client --return-floating "$FLOATING_LICENSE"
|
||||
elif [[ -n "$UNITY_SERIAL" ]]; then
|
||||
#
|
||||
# PROFESSIONAL (SERIAL) LICENSE MODE
|
||||
#
|
||||
# This will return the license that is currently in use.
|
||||
#
|
||||
unity-editor \
|
||||
-batchmode \
|
||||
-nographics \
|
||||
-logFile /dev/stdout \
|
||||
-quit \
|
||||
-returnlicense
|
||||
fi
|
||||
# Return to previous working directory
|
||||
popd
|
||||
118
dist/steps/run_tests.ps1
vendored
Normal file
118
dist/steps/run_tests.ps1
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
#
|
||||
# Set and display project path
|
||||
#
|
||||
|
||||
$UNITY_PROJECT_PATH = "${env:GITHUB_WORKSPACE}/${env:PROJECT_PATH}"
|
||||
Write-Output "Using project path $UNITY_PROJECT_PATH"
|
||||
|
||||
#
|
||||
# Set and display the artifacts path
|
||||
#
|
||||
|
||||
Write-Output "Using artifacts path ${env:ARTIFACTS_PATH} to save test results."
|
||||
$FULL_ARTIFACTS_PATH = "${env:GITHUB_WORKSPACE}\${env:ARTIFACTS_PATH}"
|
||||
|
||||
#
|
||||
# Set and display the coverage results path
|
||||
#
|
||||
|
||||
Write-Output "Using coverage results path ${env:COVERAGE_RESULTS_PATH} to save test coverage results."
|
||||
$FULL_COVERAGE_RESULTS_PATH = "${env:GITHUB_WORKSPACE}\${env:COVERAGE_RESULTS_PATH}"
|
||||
|
||||
#
|
||||
# Display custom parameters
|
||||
#
|
||||
|
||||
Write-Output "Using custom parameters ${env:CUSTOM_PARAMETERS}"
|
||||
|
||||
# The following tests are 2019 mode (requires Unity 2019.2.11f1 or later)
|
||||
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
|
||||
|
||||
#
|
||||
# Display the unity version
|
||||
#
|
||||
|
||||
Write-Output "Using Unity version ${env:UNITY_VERSION} to test."
|
||||
|
||||
#
|
||||
# Overall info
|
||||
#
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "###########################"
|
||||
Write-Output "# Artifacts folder #"
|
||||
Write-Output "###########################"
|
||||
Write-Output ""
|
||||
Write-Output "Creating $FULL_ARTIFACTS_PATH if it does not exist."
|
||||
New-Item -Path "$FULL_ARTIFACTS_PATH" -ItemType Directory
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "###########################"
|
||||
Write-Output "# Project directory #"
|
||||
Write-Output "###########################"
|
||||
Write-Output ""
|
||||
Get-ChildItem -Hidden -Path $UNITY_PROJECT_PATH
|
||||
|
||||
#
|
||||
# Testing for each platform
|
||||
#
|
||||
foreach ( $platform in ${env:TEST_PLATFORMS}.Split(";") )
|
||||
{
|
||||
Write-Output ""
|
||||
Write-Output "###########################"
|
||||
Write-Output "# Testing in $platform #"
|
||||
Write-Output "###########################"
|
||||
Write-Output ""
|
||||
|
||||
if ( $platform -ne "COMBINE_RESULTS" )
|
||||
{
|
||||
$runTests = "-runTests -testPlatform $platform -testResults $FULL_ARTIFACTS_PATH/$platform-results.xml"
|
||||
}
|
||||
else
|
||||
{
|
||||
$runTests = "-quit"
|
||||
}
|
||||
|
||||
$TEST_OUTPUT = Start-Process -NoNewWindow -Wait -PassThru "C:\Program Files\Unity\Hub\Editor\${env:UNITY_VERSION}\editor\Unity.exe" -ArgumentList "-batchmode -logFile $FULL_ARTIFACTS_PATH\$platform.log -projectPath $UNITY_PROJECT_PATH -coverageResultsPath $FULL_COVERAGE_RESULTS_PATH $runTests -enableCodeCoverage -debugCodeOptimization -coverageOptions ${env:COVERAGE_OPTIONS} ${env:CUSTOM_PARAMETERS}"
|
||||
|
||||
# Catch exit code
|
||||
$TEST_EXIT_CODE = $TEST_OUTPUT.ExitCode
|
||||
|
||||
# Print unity log output
|
||||
Get-Content "$FULL_ARTIFACTS_PATH/$platform.log"
|
||||
|
||||
# Display results
|
||||
if ($TEST_EXIT_CODE -eq 0)
|
||||
{
|
||||
Write-Output "Run succeeded, no failures occurred";
|
||||
}
|
||||
elseif ($TEST_EXIT_CODE -eq 2)
|
||||
{
|
||||
Write-Output "Run succeeded, some tests failed";
|
||||
}
|
||||
elseif ($TEST_EXIT_CODE -eq 3)
|
||||
{
|
||||
Write-Output "Run failure (other failure)";
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "Unexpected exit code $TEST_EXIT_CODE";
|
||||
}
|
||||
|
||||
if ( $TEST_EXIT_CODE -ne 0)
|
||||
{
|
||||
$TEST_RUNNER_EXIT_CODE = $TEST_EXIT_CODE
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "###########################"
|
||||
Write-Output "# $platform Results #"
|
||||
Write-Output "###########################"
|
||||
Write-Output ""
|
||||
|
||||
if ($platform -ne "COMBINE_RESULTS")
|
||||
{
|
||||
Get-Content "$FULL_ARTIFACTS_PATH/$platform-results.xml"
|
||||
Get-Content "$FULL_ARTIFACTS_PATH/$platform-results.xml" | Select-String "test-run" | Select-String "Passed"
|
||||
}
|
||||
}
|
||||
132
dist/steps/run_tests.sh
vendored
Executable file
132
dist/steps/run_tests.sh
vendored
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#
|
||||
# Set and display project path
|
||||
#
|
||||
|
||||
UNITY_PROJECT_PATH="$GITHUB_WORKSPACE/$PROJECT_PATH"
|
||||
echo "Using project path \"$UNITY_PROJECT_PATH\"."
|
||||
|
||||
#
|
||||
# Set and display the artifacts path
|
||||
#
|
||||
|
||||
echo "Using artifacts path \"$ARTIFACTS_PATH\" to save test results."
|
||||
FULL_ARTIFACTS_PATH=$GITHUB_WORKSPACE/$ARTIFACTS_PATH
|
||||
|
||||
#
|
||||
# Set and display the coverage results path
|
||||
#
|
||||
|
||||
echo "Using coverage results path \"$COVERAGE_RESULTS_PATH\" to save test coverage results."
|
||||
FULL_COVERAGE_RESULTS_PATH=$GITHUB_WORKSPACE/$COVERAGE_RESULTS_PATH
|
||||
|
||||
#
|
||||
# Display custom parameters
|
||||
#
|
||||
|
||||
echo "Using custom parameters $CUSTOM_PARAMETERS."
|
||||
|
||||
# The following tests are 2019 mode (requires Unity 2019.2.11f1 or later)
|
||||
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
|
||||
|
||||
#
|
||||
# Display the unity version
|
||||
#
|
||||
|
||||
echo "Using Unity version \"$UNITY_VERSION\" to test."
|
||||
|
||||
#
|
||||
# Overall info
|
||||
#
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Artifacts folder #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
echo "Creating \"$FULL_ARTIFACTS_PATH\" if it does not exist."
|
||||
mkdir -p $FULL_ARTIFACTS_PATH
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Project directory #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
ls -alh $UNITY_PROJECT_PATH
|
||||
|
||||
#
|
||||
# Testing for each platform
|
||||
#
|
||||
for platform in ${TEST_PLATFORMS//;/ }; do
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Testing in $platform #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
|
||||
if [[ "$platform" != "COMBINE_RESULTS" ]]; then
|
||||
runTests="-runTests -testPlatform $platform -testResults $FULL_ARTIFACTS_PATH/$platform-results.xml"
|
||||
else
|
||||
runTests="-quit"
|
||||
fi
|
||||
|
||||
unity-editor \
|
||||
-batchmode \
|
||||
-logFile "$FULL_ARTIFACTS_PATH/$platform.log" \
|
||||
-projectPath "$UNITY_PROJECT_PATH" \
|
||||
-coverageResultsPath "$FULL_COVERAGE_RESULTS_PATH" \
|
||||
$runTests \
|
||||
-enableCodeCoverage \
|
||||
-debugCodeOptimization \
|
||||
-coverageOptions "$COVERAGE_OPTIONS" \
|
||||
$CUSTOM_PARAMETERS
|
||||
|
||||
# Catch exit code
|
||||
TEST_EXIT_CODE=$?
|
||||
|
||||
# Print unity log output
|
||||
cat "$FULL_ARTIFACTS_PATH/$platform.log"
|
||||
|
||||
# Display results
|
||||
if [ $TEST_EXIT_CODE -eq 0 ]; then
|
||||
echo "Run succeeded, no failures occurred";
|
||||
elif [ $TEST_EXIT_CODE -eq 2 ]; then
|
||||
echo "Run succeeded, some tests failed";
|
||||
elif [ $TEST_EXIT_CODE -eq 3 ]; then
|
||||
echo "Run failure (other failure)";
|
||||
else
|
||||
echo "Unexpected exit code $TEST_EXIT_CODE";
|
||||
fi
|
||||
|
||||
if [ $TEST_EXIT_CODE -ne 0 ]; then
|
||||
TEST_RUNNER_EXIT_CODE=$TEST_EXIT_CODE
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# $platform Results #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
|
||||
if [[ "$platform" != "COMBINE_RESULTS" ]]; then
|
||||
cat "$FULL_ARTIFACTS_PATH/$platform-results.xml"
|
||||
cat "$FULL_ARTIFACTS_PATH/$platform-results.xml" | grep test-run | grep Passed
|
||||
fi
|
||||
done
|
||||
|
||||
#
|
||||
# Permissions
|
||||
#
|
||||
|
||||
# Make a given user owner of all artifacts
|
||||
if [[ -n "$CHOWN_FILES_TO" ]]; then
|
||||
chown -R "$CHOWN_FILES_TO" "$UNITY_PROJECT_PATH"
|
||||
chown -R "$CHOWN_FILES_TO" "$FULL_ARTIFACTS_PATH"
|
||||
chown -R "$CHOWN_FILES_TO" "$FULL_COVERAGE_RESULTS_PATH"
|
||||
fi
|
||||
|
||||
# Add read permissions for everyone to all artifacts
|
||||
chmod -R a+r "$UNITY_PROJECT_PATH"
|
||||
chmod -R a+r "$FULL_ARTIFACTS_PATH"
|
||||
chmod -R a+r "$FULL_COVERAGE_RESULTS_PATH"
|
||||
22
dist/steps/set_gitcredential.ps1
vendored
Normal file
22
dist/steps/set_gitcredential.ps1
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
if ($null -eq ${env:GIT_PRIVATE_TOKEN})
|
||||
{
|
||||
Write-Output "GIT_PRIVATE_TOKEN unset skipping"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "GIT_PRIVATE_TOKEN is set configuring git credentials"
|
||||
|
||||
git config --global credential.helper store
|
||||
git config --global --replace-all url.https://github.com/.insteadOf ssh://git@github.com/
|
||||
git config --global --add url.https://github.com/.insteadOf git@github.com
|
||||
|
||||
git config --global url."https://token:${env:GIT_PRIVATE_TOKEN}@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."https://ssh:${env:GIT_PRIVATE_TOKEN}@github.com/".insteadOf "ssh://git@github.com/"
|
||||
git config --global url."https://git:${env:GIT_PRIVATE_TOKEN}@github.com/".insteadOf "git@github.com:"
|
||||
}
|
||||
|
||||
Write-Output "---------- git config --list -------------"
|
||||
git config --list
|
||||
|
||||
Write-Output "---------- git config --list --show-origin -------------"
|
||||
git config --list --show-origin
|
||||
23
dist/steps/set_gitcredential.sh
vendored
Executable file
23
dist/steps/set_gitcredential.sh
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "${GIT_PRIVATE_TOKEN}" ]
|
||||
then
|
||||
echo "GIT_PRIVATE_TOKEN unset skipping"
|
||||
else
|
||||
echo "GIT_PRIVATE_TOKEN is set configuring git credentials"
|
||||
|
||||
git config --global credential.helper store
|
||||
git config --global --replace-all url.https://github.com/.insteadOf ssh://git@github.com/
|
||||
git config --global --add url.https://github.com/.insteadOf git@github.com
|
||||
|
||||
git config --global url."https://token:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "https://github.com/"
|
||||
git config --global url."https://ssh:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "ssh://git@github.com/"
|
||||
git config --global url."https://git:$GIT_PRIVATE_TOKEN@github.com/".insteadOf "git@github.com:"
|
||||
|
||||
fi
|
||||
|
||||
echo "---------- git config --list -------------"
|
||||
git config --list
|
||||
|
||||
echo "---------- git config --list --show-origin -------------"
|
||||
git config --list --show-origin
|
||||
7
dist/unity-config/services-config.json.template
vendored
Normal file
7
dist/unity-config/services-config.json.template
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"licensingServiceBaseUrl": "%URL%",
|
||||
"enableEntitlementLicensing": true,
|
||||
"enableFloatingApi": true,
|
||||
"clientConnectTimeoutSec": 5,
|
||||
"clientHandshakeTimeoutSec": 10
|
||||
}
|
||||
191
entrypoint.sh
191
entrypoint.sh
@@ -1,191 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set the license file path
|
||||
LICENSE_FILE_PATH=UnityLicenseFile.ulf
|
||||
UNITY_PROJECT_PATH=$GITHUB_WORKSPACE/$UNITY_PROJECT_PATH
|
||||
|
||||
# Set the artifacts path
|
||||
if [ -z "$ARTIFACTS_PATH" ]; then
|
||||
ARTIFACTS_PATH=artifacts
|
||||
fi
|
||||
FULL_ARTIFACTS_PATH=$GITHUB_WORKSPACE/$ARTIFACTS_PATH
|
||||
|
||||
# Set the modes for testing
|
||||
case $TEST_MODE in
|
||||
editmode)
|
||||
echo "Edit mode selected for testing."
|
||||
EDIT_MODE=true
|
||||
;;
|
||||
playmode)
|
||||
echo "Play mode selected for testing."
|
||||
PLAY_MODE=true
|
||||
;;
|
||||
*)
|
||||
echo "All modes selected for testing."
|
||||
EDIT_MODE=true
|
||||
PLAY_MODE=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Copy license file from Github variables
|
||||
echo "$UNITY_LICENSE" | tr -d '\r' > $LICENSE_FILE_PATH
|
||||
echo "$UNITY_LICENSE" | tr -d '\r' > /root/.local/share/unity3d/Unity/Unity_lic.ulf
|
||||
# TODO - test if this line has any effect
|
||||
echo "$UNITY_LICENSE" | tr -d '\r' > /root/.local/share/unity3d/Unity/Unity_v2019.x.ulf
|
||||
|
||||
##
|
||||
## Activate license
|
||||
##
|
||||
echo "Requesting activation"
|
||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||
/opt/Unity/Editor/Unity \
|
||||
-batchmode \
|
||||
-nographics \
|
||||
-logFile /dev/stdout \
|
||||
-quit \
|
||||
-manualLicenseFile $LICENSE_FILE_PATH
|
||||
# This is expected to always exit with code 1 (both success and failure).
|
||||
# Convert to exit code 0 by echoing the current exit code.
|
||||
echo $?
|
||||
# Exit code is now 0
|
||||
|
||||
|
||||
# The following tests are 2019 mode (requires Unity 2019.2.11f1 or later)
|
||||
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
|
||||
|
||||
#
|
||||
# Overall info
|
||||
#
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Artifacts folder #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
echo "Creating \"$FULL_ARTIFACTS_PATH\" if it does not exist."
|
||||
mkdir -p $FULL_ARTIFACTS_PATH
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Project directory #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
ls -alh $UNITY_PROJECT_PATH
|
||||
|
||||
#
|
||||
# Testing in EditMode
|
||||
#
|
||||
|
||||
if [ $EDIT_MODE = true ]; then
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Testing in EditMode #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||
/opt/Unity/Editor/Unity \
|
||||
-batchmode \
|
||||
-logfile /dev/stdout \
|
||||
-projectPath "$UNITY_PROJECT_PATH" \
|
||||
-runTests \
|
||||
-testPlatform editmode \
|
||||
-testResults "$FULL_ARTIFACTS_PATH/editmode-results.xml"
|
||||
|
||||
# Catch exit code
|
||||
EDIT_MODE_EXIT_CODE=$?
|
||||
|
||||
# Display results
|
||||
if [ $EDIT_MODE_EXIT_CODE -eq 0 ]; then
|
||||
echo "Run succeeded, no failures occurred";
|
||||
elif [ $EDIT_MODE_EXIT_CODE -eq 2 ]; then
|
||||
echo "Run succeeded, some tests failed";
|
||||
elif [ $EDIT_MODE_EXIT_CODE -eq 3 ]; then
|
||||
echo "Run failure (other failure)";
|
||||
else
|
||||
echo "Unexpected exit code $EDIT_MODE_EXIT_CODE";
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Testing in PlayMode
|
||||
#
|
||||
|
||||
if [ $PLAY_MODE = true ]; then
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Testing in PlayMode #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
|
||||
/opt/Unity/Editor/Unity \
|
||||
-batchmode \
|
||||
-logfile /dev/stdout \
|
||||
-projectPath "$UNITY_PROJECT_PATH" \
|
||||
-runTests \
|
||||
-testPlatform playmode \
|
||||
-testResults "$FULL_ARTIFACTS_PATH/playmode-results.xml"
|
||||
|
||||
# Catch exit code
|
||||
PLAY_MODE_EXIT_CODE=$?
|
||||
|
||||
# Display results
|
||||
if [ $PLAY_MODE_EXIT_CODE -eq 0 ]; then
|
||||
echo "Run succeeded, no failures occurred";
|
||||
elif [ $PLAY_MODE_EXIT_CODE -eq 2 ]; then
|
||||
echo "Run succeeded, some tests failed";
|
||||
elif [ $PLAY_MODE_EXIT_CODE -eq 3 ]; then
|
||||
echo "Run failure (other failure)";
|
||||
else
|
||||
echo "Unexpected exit code $PLAY_MODE_EXIT_CODE";
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Results
|
||||
#
|
||||
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Project directory #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
ls -alh $UNITY_PROJECT_PATH
|
||||
|
||||
if [ $EDIT_MODE = true ]; then
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Edit Mode Results #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
cat "$FULL_ARTIFACTS_PATH/editmode-results.xml"
|
||||
cat "$FULL_ARTIFACTS_PATH/editmode-results.xml" | grep test-run | grep Passed
|
||||
fi
|
||||
|
||||
if [ $PLAY_MODE = true ]; then
|
||||
echo ""
|
||||
echo "###########################"
|
||||
echo "# Edit Mode Results #"
|
||||
echo "###########################"
|
||||
echo ""
|
||||
cat "$FULL_ARTIFACTS_PATH/playmode-results.xml"
|
||||
cat "$FULL_ARTIFACTS_PATH/playmode-results.xml" | grep test-run | grep Passed
|
||||
fi
|
||||
|
||||
#
|
||||
# Output variables
|
||||
#
|
||||
|
||||
# Set resulting name as output variable
|
||||
echo ::set-output name=artifactsPath::$ARTIFACTS_PATH
|
||||
|
||||
#
|
||||
# Exit
|
||||
#
|
||||
|
||||
if [ $EDIT_MODE_EXIT_CODE -gt 0 ]; then
|
||||
exit $EDIT_MODE_EXIT_CODE
|
||||
fi
|
||||
|
||||
if [ $PLAY_MODE_EXIT_CODE -gt 0 ]; then
|
||||
exit $PLAY_MODE_EXIT_CODE
|
||||
fi
|
||||
11
jest.config.js
Normal file
11
jest.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest',
|
||||
},
|
||||
verbose: true,
|
||||
};
|
||||
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 |
56
package.json
Normal file
56
package.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "unity-test-runner",
|
||||
"version": "2.0.0",
|
||||
"description": "Run tests for any Unity project.",
|
||||
"main": "dist/index.js",
|
||||
"repository": "git@github.com:game-ci/unity-test-runner.git",
|
||||
"author": "Webber <webber@takken.io>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prebuild": "yarn",
|
||||
"build": "tsc && ncc build lib/index.js --source-map --license licenses.txt",
|
||||
"lint": "prettier --check \"src/**/*.{js,ts}\" && eslint src --ext .js,.ts --max-warnings=0",
|
||||
"format": "prettier --write \"src/**/*.{js,ts}\"",
|
||||
"test": "jest",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/github": "^5.0.0",
|
||||
"@octokit/openapi-types": "^11.2.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/node": "^14.14.9",
|
||||
"@types/semver": "^7.3.5",
|
||||
"@typescript-eslint/parser": "^5.9.0",
|
||||
"@vercel/ncc": "^0.33.1",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-github": "^4.3.5",
|
||||
"eslint-plugin-jest": "^25.3.4",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-unicorn": "^40.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^26.6.3",
|
||||
"js-yaml": "^3.14.0",
|
||||
"lint-staged": "^12.1.2",
|
||||
"prettier": "^2.2.1",
|
||||
"ts-jest": "^26.4.4",
|
||||
"typescript": "^4.1.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"prettier --write",
|
||||
"eslint",
|
||||
"jest --findRelatedTests"
|
||||
],
|
||||
"*.{json,md,yaml,yml}": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
30
src/index.ts
Normal file
30
src/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { run as main } from './main';
|
||||
import path from 'path';
|
||||
import { run as post } from './post';
|
||||
|
||||
/*
|
||||
* GitHub Action can provide multiple executable entrypoints (pre, main, post),
|
||||
* but it is complicated process to generate multiple `.js` files with `ncc`.
|
||||
* So we rather generate just one entrypoint, that is symlinked to multiple locations (main.js and post.js).
|
||||
* Then when GitHub Action Runner executes it as `node path/to/main.js` and `node path/to/post.js`,
|
||||
* it can read arguments it was executed with and decide which file to execute.
|
||||
* The argv[0] is going to be a full path to `node` executable and
|
||||
* the argv[1] is going to be the full path to the script.
|
||||
* In case index.js would be marked executable and executed directly without the argv[1] it defaults to "main.js".
|
||||
*/
|
||||
async function run([, name = 'main.js']: string[]) {
|
||||
const script = path.basename(name);
|
||||
|
||||
switch (script) {
|
||||
case 'main.js':
|
||||
await main();
|
||||
break;
|
||||
case 'post.js':
|
||||
await post();
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown script argument: '${script}'`);
|
||||
}
|
||||
}
|
||||
|
||||
run(process.argv);
|
||||
60
src/main.ts
Normal file
60
src/main.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import * as core from '@actions/core';
|
||||
import { Action, Docker, ImageTag, Input, Output, ResultsCheck } from './model';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
Action.checkCompatibility();
|
||||
|
||||
const { workspace, actionFolder } = Action;
|
||||
const {
|
||||
editorVersion,
|
||||
customImage,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
checkName,
|
||||
chownFilesTo,
|
||||
unityLicensingServer,
|
||||
} = Input.getFromUser();
|
||||
const baseImage = new ImageTag({ editorVersion, customImage });
|
||||
const runnerContext = Action.runnerContext();
|
||||
|
||||
try {
|
||||
await Docker.run(baseImage, {
|
||||
actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
chownFilesTo,
|
||||
unityLicensingServer,
|
||||
...runnerContext,
|
||||
});
|
||||
} finally {
|
||||
await Output.setArtifactsPath(artifactsPath);
|
||||
await Output.setCoveragePath('CodeCoverage');
|
||||
}
|
||||
|
||||
if (githubToken) {
|
||||
const failedTestCount = await ResultsCheck.createCheck(artifactsPath, githubToken, checkName);
|
||||
if (failedTestCount >= 1) {
|
||||
core.setFailed(`Test(s) Failed! Check '${checkName}' for details.`);
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
29
src/model/action.test.ts
Normal file
29
src/model/action.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import Action from './action';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
describe('Action', () => {
|
||||
describe('compatibility check', () => {
|
||||
it('throws for anything other than linux or windows', () => {
|
||||
if (process.platform !== 'linux' && process.platform !== 'win32') {
|
||||
expect(() => Action.checkCompatibility()).toThrow();
|
||||
} else {
|
||||
expect(() => Action.checkCompatibility()).not.toThrow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the root folder of the action', () => {
|
||||
const { rootFolder, canonicalName } = Action;
|
||||
|
||||
expect(path.basename(rootFolder)).toStrictEqual(canonicalName);
|
||||
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns the action folder', () => {
|
||||
const { actionFolder } = Action;
|
||||
|
||||
expect(path.basename(actionFolder)).toStrictEqual('dist');
|
||||
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
59
src/model/action.ts
Normal file
59
src/model/action.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import path from 'path';
|
||||
|
||||
export interface RunnerContext {
|
||||
runnerTemporaryPath: string;
|
||||
githubAction: string;
|
||||
}
|
||||
|
||||
const Action = {
|
||||
get supportedPlatforms() {
|
||||
return ['linux', 'win32'];
|
||||
},
|
||||
|
||||
get isRunningLocally() {
|
||||
return process.env.RUNNER_WORKSPACE === undefined;
|
||||
},
|
||||
|
||||
get isRunningFromSource() {
|
||||
return path.basename(__dirname) === 'model';
|
||||
},
|
||||
|
||||
get canonicalName() {
|
||||
return 'unity-test-runner';
|
||||
},
|
||||
|
||||
get rootFolder() {
|
||||
if (Action.isRunningFromSource) {
|
||||
return path.dirname(path.dirname(path.dirname(__filename)));
|
||||
}
|
||||
|
||||
return path.dirname(path.dirname(__filename));
|
||||
},
|
||||
|
||||
get actionFolder() {
|
||||
return `${Action.rootFolder}/dist`;
|
||||
},
|
||||
|
||||
get workspace() {
|
||||
return process.env.GITHUB_WORKSPACE;
|
||||
},
|
||||
|
||||
runnerContext(): RunnerContext {
|
||||
const runnerTemporaryPath = process.env.RUNNER_TEMP ?? process.cwd();
|
||||
const githubAction = process.env.GITHUB_ACTION ?? process.pid.toString();
|
||||
|
||||
return {
|
||||
runnerTemporaryPath,
|
||||
githubAction,
|
||||
};
|
||||
},
|
||||
|
||||
checkCompatibility() {
|
||||
const currentPlatform = process.platform;
|
||||
if (!Action.supportedPlatforms.includes(currentPlatform)) {
|
||||
throw new Error(`Currently ${currentPlatform}-platform is not supported`);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default Action;
|
||||
16
src/model/docker.test.ts
Normal file
16
src/model/docker.test.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import Action from './action';
|
||||
import Docker from './docker';
|
||||
|
||||
describe('Docker', () => {
|
||||
it.skip('runs', async () => {
|
||||
const image = 'unity-builder:2019.2.11f1-webgl';
|
||||
const parameters = {
|
||||
workspace: Action.rootFolder,
|
||||
projectPath: `${Action.rootFolder}/test-project`,
|
||||
buildName: 'someBuildName',
|
||||
buildsPath: 'build',
|
||||
method: '',
|
||||
};
|
||||
await Docker.run(image, parameters);
|
||||
});
|
||||
});
|
||||
213
src/model/docker.ts
Normal file
213
src/model/docker.ts
Normal file
@@ -0,0 +1,213 @@
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync } from 'fs';
|
||||
import LicensingServerSetup from './licensing-server-setup';
|
||||
import type { RunnerContext } from './action';
|
||||
import { exec } from '@actions/exec';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Build a path for a docker --cidfile parameter. Docker will store the the created container.
|
||||
* This path is stable for the whole execution of the action, so it can be executed with the same parameters
|
||||
* multiple times and get the same result.
|
||||
*/
|
||||
const containerIdFilePath = parameters => {
|
||||
const { runnerTemporaryPath, githubAction } = parameters;
|
||||
|
||||
return path.join(runnerTemporaryPath, `container_${githubAction}`);
|
||||
};
|
||||
|
||||
const Docker = {
|
||||
/**
|
||||
* Remove a possible leftover container created by `Docker.run`.
|
||||
*/
|
||||
async ensureContainerRemoval(parameters: RunnerContext) {
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
if (!existsSync(cidfile)) {
|
||||
return;
|
||||
}
|
||||
const container = readFileSync(cidfile, 'ascii').trim();
|
||||
await exec(`docker`, ['rm', '--force', '--volumes', container], { silent: true });
|
||||
rmSync(cidfile);
|
||||
},
|
||||
|
||||
async run(image, parameters, silent = false) {
|
||||
let runCommand = '';
|
||||
|
||||
if (parameters.unityLicensingServer !== '') {
|
||||
LicensingServerSetup.Setup(parameters.unityLicensingServer, parameters.actionFolder);
|
||||
}
|
||||
|
||||
switch (process.platform) {
|
||||
case 'linux':
|
||||
runCommand = this.getLinuxCommand(image, parameters);
|
||||
break;
|
||||
case 'win32':
|
||||
runCommand = this.getWindowsCommand(image, parameters);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Operation system, ${process.platform}, is not supported yet.`);
|
||||
}
|
||||
|
||||
await exec(runCommand, undefined, { silent });
|
||||
},
|
||||
|
||||
getLinuxCommand(image, parameters): string {
|
||||
const {
|
||||
actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
runnerTemporaryPath,
|
||||
chownFilesTo,
|
||||
unityLicensingServer,
|
||||
} = parameters;
|
||||
|
||||
const githubHome = path.join(runnerTemporaryPath, '_github_home');
|
||||
if (!existsSync(githubHome)) mkdirSync(githubHome);
|
||||
const githubWorkflow = path.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!existsSync(githubWorkflow)) mkdirSync(githubWorkflow);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const testPlatforms = (
|
||||
testMode === 'all' ? ['playmode', 'editmode', 'COMBINE_RESULTS'] : [testMode]
|
||||
).join(';');
|
||||
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
--env UNITY_EMAIL \
|
||||
--env UNITY_PASSWORD \
|
||||
--env UNITY_SERIAL \
|
||||
--env UNITY_LICENSING_SERVER="${unityLicensingServer}" \
|
||||
--env UNITY_VERSION="${editorVersion}" \
|
||||
--env PROJECT_PATH="${projectPath}" \
|
||||
--env CUSTOM_PARAMETERS="${customParameters}" \
|
||||
--env TEST_PLATFORMS="${testPlatforms}" \
|
||||
--env COVERAGE_OPTIONS="${coverageOptions}" \
|
||||
--env COVERAGE_RESULTS_PATH="CodeCoverage" \
|
||||
--env ARTIFACTS_PATH="${artifactsPath}" \
|
||||
--env GITHUB_REF \
|
||||
--env GITHUB_SHA \
|
||||
--env GITHUB_REPOSITORY \
|
||||
--env GITHUB_ACTOR \
|
||||
--env GITHUB_WORKFLOW \
|
||||
--env GITHUB_HEAD_REF \
|
||||
--env GITHUB_BASE_REF \
|
||||
--env GITHUB_EVENT_NAME \
|
||||
--env GITHUB_WORKSPACE="/github/workspace" \
|
||||
--env GITHUB_ACTION \
|
||||
--env GITHUB_EVENT_PATH \
|
||||
--env RUNNER_OS \
|
||||
--env RUNNER_TOOL_CACHE \
|
||||
--env RUNNER_TEMP \
|
||||
--env RUNNER_WORKSPACE \
|
||||
--env GIT_PRIVATE_TOKEN="${gitPrivateToken}" \
|
||||
--env CHOWN_FILES_TO="${chownFilesTo}" \
|
||||
${sshAgent ? '--env SSH_AUTH_SOCK=/ssh-agent' : ''} \
|
||||
--volume "${githubHome}:/root:z" \
|
||||
--volume "${githubWorkflow}:/github/workflow:z" \
|
||||
--volume "${workspace}:/github/workspace:z" \
|
||||
--volume "${actionFolder}/steps:/steps:z" \
|
||||
--volume "${actionFolder}/entrypoint.sh:/entrypoint.sh:z" \
|
||||
--volume "${actionFolder}/unity-config:/usr/share/unity3d/config/:z" \
|
||||
${sshAgent ? `--volume ${sshAgent}:/ssh-agent` : ''} \
|
||||
${
|
||||
sshAgent ? `--volume /home/runner/.ssh/known_hosts:/root/.ssh/known_hosts:ro` : ''
|
||||
} \
|
||||
${useHostNetwork ? '--net=host' : ''} \
|
||||
${githubToken ? '--env USE_EXIT_CODE=false' : '--env USE_EXIT_CODE=true'} \
|
||||
${image} \
|
||||
/bin/bash -c /entrypoint.sh`;
|
||||
},
|
||||
|
||||
getWindowsCommand(image, parameters): string {
|
||||
const {
|
||||
actionFolder,
|
||||
editorVersion,
|
||||
workspace,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
runnerTemporaryPath,
|
||||
chownFilesTo,
|
||||
unityLicensingServer,
|
||||
} = parameters;
|
||||
|
||||
const githubHome = path.join(runnerTemporaryPath, '_github_home');
|
||||
if (!existsSync(githubHome)) mkdirSync(githubHome);
|
||||
const cidfile = containerIdFilePath(parameters);
|
||||
const githubWorkflow = path.join(runnerTemporaryPath, '_github_workflow');
|
||||
if (!existsSync(githubWorkflow)) mkdirSync(githubWorkflow);
|
||||
const testPlatforms = (
|
||||
testMode === 'all' ? ['playmode', 'editmode', 'COMBINE_RESULTS'] : [testMode]
|
||||
).join(';');
|
||||
|
||||
return `docker run \
|
||||
--workdir /github/workspace \
|
||||
--cidfile "${cidfile}" \
|
||||
--rm \
|
||||
--env UNITY_LICENSE \
|
||||
--env UNITY_LICENSE_FILE \
|
||||
--env UNITY_EMAIL \
|
||||
--env UNITY_PASSWORD \
|
||||
--env UNITY_SERIAL \
|
||||
--env UNITY_LICENSING_SERVER="${unityLicensingServer}" \
|
||||
--env UNITY_VERSION="${editorVersion}" \
|
||||
--env PROJECT_PATH="${projectPath}" \
|
||||
--env CUSTOM_PARAMETERS="${customParameters}" \
|
||||
--env TEST_PLATFORMS="${testPlatforms}" \
|
||||
--env COVERAGE_OPTIONS="${coverageOptions}" \
|
||||
--env COVERAGE_RESULTS_PATH="CodeCoverage" \
|
||||
--env ARTIFACTS_PATH="${artifactsPath}" \
|
||||
--env GITHUB_REF \
|
||||
--env GITHUB_SHA \
|
||||
--env GITHUB_REPOSITORY \
|
||||
--env GITHUB_ACTOR \
|
||||
--env GITHUB_WORKFLOW \
|
||||
--env GITHUB_HEAD_REF \
|
||||
--env GITHUB_BASE_REF \
|
||||
--env GITHUB_EVENT_NAME \
|
||||
--env GITHUB_WORKSPACE="/github/workspace" \
|
||||
--env GITHUB_ACTION \
|
||||
--env GITHUB_EVENT_PATH \
|
||||
--env RUNNER_OS \
|
||||
--env RUNNER_TOOL_CACHE \
|
||||
--env RUNNER_TEMP \
|
||||
--env RUNNER_WORKSPACE \
|
||||
--env GIT_PRIVATE_TOKEN="${gitPrivateToken}" \
|
||||
--env CHOWN_FILES_TO="${chownFilesTo}" \
|
||||
${sshAgent ? '--env SSH_AUTH_SOCK=c:/ssh-agent' : ''} \
|
||||
--volume "${githubHome}":"c:/root" \
|
||||
--volume "${githubWorkflow}":"c:/github/workflow" \
|
||||
--volume "${workspace}":"c:/github/workspace" \
|
||||
--volume "${actionFolder}/steps":"c:/steps" \
|
||||
--volume "${actionFolder}":"c:/dist" \
|
||||
${sshAgent ? `--volume ${sshAgent}:c:/ssh-agent` : ''} \
|
||||
${
|
||||
sshAgent
|
||||
? `--volume c:/Users/Administrator/.ssh/known_hosts:c:/root/.ssh/known_hosts`
|
||||
: ''
|
||||
} \
|
||||
${useHostNetwork ? '--net=host' : ''} \
|
||||
${githubToken ? '--env USE_EXIT_CODE=false' : '--env USE_EXIT_CODE=true'} \
|
||||
${image} \
|
||||
powershell c:/dist/entrypoint.ps1`;
|
||||
},
|
||||
};
|
||||
|
||||
export default Docker;
|
||||
77
src/model/image-tag.test.ts
Normal file
77
src/model/image-tag.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import ImageTag from './image-tag';
|
||||
|
||||
jest.spyOn(ImageTag, 'getImagePlatformPrefix').mockReturnValue('ubuntu');
|
||||
|
||||
describe('ImageTag', () => {
|
||||
const some = {
|
||||
editorVersion: '2099.9.f9f9',
|
||||
targetPlatform: 'Test',
|
||||
builderPlatform: '',
|
||||
};
|
||||
|
||||
const defaults = {
|
||||
repository: 'unityci',
|
||||
name: 'editor',
|
||||
image: 'unityci/editor',
|
||||
};
|
||||
|
||||
describe('constructor', () => {
|
||||
it('can be called', () => {
|
||||
const { targetPlatform } = some;
|
||||
expect(() => new ImageTag({ platform: targetPlatform })).not.toThrow();
|
||||
});
|
||||
|
||||
it('accepts parameters and sets the right properties', () => {
|
||||
const image = new ImageTag(some);
|
||||
|
||||
expect(image.repository).toStrictEqual('unityci');
|
||||
expect(image.name).toStrictEqual('editor');
|
||||
expect(image.editorVersion).toStrictEqual(some.editorVersion);
|
||||
expect(image.targetPlatform).toStrictEqual(some.targetPlatform);
|
||||
expect(image.targetPlatformSuffix).toStrictEqual(some.builderPlatform);
|
||||
});
|
||||
|
||||
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', editorVersion => {
|
||||
expect(
|
||||
() => new ImageTag({ editorVersion, targetPlatform: some.targetPlatform }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
test.each(['some version', '', 1])('throws for incorrect versions %p', editorVersion => {
|
||||
const { targetPlatform } = some;
|
||||
expect(() => new ImageTag({ editorVersion, targetPlatform })).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
it('returns the correct version', () => {
|
||||
const image = new ImageTag({
|
||||
editorVersion: '2099.1.1111',
|
||||
targetPlatform: some.targetPlatform,
|
||||
});
|
||||
|
||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2099.1.1111-1`);
|
||||
});
|
||||
it('returns customImage if given', () => {
|
||||
const image = new ImageTag({
|
||||
editorVersion: '2099.1.1111',
|
||||
targetPlatform: some.targetPlatform,
|
||||
customImage: `${defaults.image}:2099.1.1111@347598437689743986`,
|
||||
});
|
||||
|
||||
expect(image.toString()).toStrictEqual(image.customImage);
|
||||
});
|
||||
|
||||
it('returns the specific build platform', () => {
|
||||
const image = new ImageTag({ editorVersion: '2019.2.11f1', targetPlatform: 'WebGL' });
|
||||
|
||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-webgl-1`);
|
||||
});
|
||||
|
||||
it('returns no specific build platform for generic targetPlatforms', () => {
|
||||
const image = new ImageTag({ targetPlatform: 'NoTarget' });
|
||||
|
||||
expect(image.toString()).toStrictEqual(`${defaults.image}:ubuntu-2019.2.11f1-1`);
|
||||
});
|
||||
});
|
||||
});
|
||||
161
src/model/image-tag.ts
Normal file
161
src/model/image-tag.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import Platform from './platform';
|
||||
|
||||
class ImageTag {
|
||||
public customImage?: string;
|
||||
public repository: string;
|
||||
public name: string;
|
||||
public editorVersion: string;
|
||||
public targetPlatform: string;
|
||||
public targetPlatformSuffix: string;
|
||||
public imagePlatformPrefix: string;
|
||||
public imageRollingVersion: number;
|
||||
|
||||
constructor(imageProperties) {
|
||||
const {
|
||||
editorVersion = '2019.2.11f1',
|
||||
targetPlatform = ImageTag.getImagePlatformType(process.platform),
|
||||
customImage,
|
||||
} = imageProperties;
|
||||
|
||||
if (!ImageTag.versionPattern.test(editorVersion)) {
|
||||
throw new Error(`Invalid version "${editorVersion}".`);
|
||||
}
|
||||
|
||||
// Either
|
||||
this.customImage = customImage;
|
||||
|
||||
// Or
|
||||
this.repository = 'unityci';
|
||||
this.name = 'editor';
|
||||
this.editorVersion = editorVersion;
|
||||
this.targetPlatform = targetPlatform;
|
||||
this.targetPlatformSuffix = ImageTag.getTargetPlatformSuffix(targetPlatform, editorVersion);
|
||||
this.imagePlatformPrefix = ImageTag.getImagePlatformPrefix(process.platform);
|
||||
this.imageRollingVersion = 1;
|
||||
}
|
||||
|
||||
static get versionPattern() {
|
||||
return /^20\d{2}\.\d\.\w{3,4}|3$/;
|
||||
}
|
||||
|
||||
static get targetPlatformSuffixes() {
|
||||
return {
|
||||
generic: '',
|
||||
webgl: 'webgl',
|
||||
mac: 'mac-mono',
|
||||
windows: 'windows-il2cpp',
|
||||
linux: 'base',
|
||||
linuxIl2cpp: 'linux-il2cpp',
|
||||
android: 'android',
|
||||
ios: 'ios',
|
||||
facebook: 'facebook',
|
||||
};
|
||||
}
|
||||
|
||||
static getImagePlatformPrefix(platform) {
|
||||
switch (platform) {
|
||||
case 'linux':
|
||||
return 'ubuntu';
|
||||
case 'win32':
|
||||
return 'windows';
|
||||
default:
|
||||
throw new Error(
|
||||
`The Operating System of this runner, "${platform}", is not yet supported.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static getImagePlatformType(platform) {
|
||||
switch (platform) {
|
||||
case 'linux':
|
||||
return Platform.types.StandaloneLinux64;
|
||||
case 'win32':
|
||||
return Platform.types.StandaloneWindows;
|
||||
default:
|
||||
throw new Error(
|
||||
`The Operating System of this runner, "${platform}", is not yet supported.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static getTargetPlatformSuffix(targetPlatform, editorVersion) {
|
||||
const { generic, webgl, mac, windows, linux, linuxIl2cpp, android, ios, facebook } =
|
||||
ImageTag.targetPlatformSuffixes;
|
||||
|
||||
const [major, minor] = editorVersion.split('.').map(digit => Number(digit));
|
||||
// @see: https://docs.unity3d.com/ScriptReference/BuildTarget.html
|
||||
switch (targetPlatform) {
|
||||
case Platform.types.StandaloneOSX:
|
||||
return mac;
|
||||
case Platform.types.StandaloneWindows:
|
||||
return windows;
|
||||
case Platform.types.StandaloneWindows64:
|
||||
return windows;
|
||||
case Platform.types.StandaloneLinux64: {
|
||||
// Unity versions before 2019.3 do not support il2cpp
|
||||
if (major >= 2020 || (major === 2019 && minor >= 3)) {
|
||||
return linuxIl2cpp;
|
||||
}
|
||||
return linux;
|
||||
}
|
||||
case Platform.types.iOS:
|
||||
return ios;
|
||||
case Platform.types.Android:
|
||||
return android;
|
||||
case Platform.types.WebGL:
|
||||
return webgl;
|
||||
case Platform.types.WSAPlayer:
|
||||
return windows;
|
||||
case Platform.types.PS4:
|
||||
return windows;
|
||||
case Platform.types.XboxOne:
|
||||
return windows;
|
||||
case Platform.types.tvOS:
|
||||
return windows;
|
||||
case Platform.types.Switch:
|
||||
return windows;
|
||||
// Unsupported
|
||||
case Platform.types.Lumin:
|
||||
return windows;
|
||||
case Platform.types.BJM:
|
||||
return windows;
|
||||
case Platform.types.Stadia:
|
||||
return windows;
|
||||
case Platform.types.Facebook:
|
||||
return facebook;
|
||||
case Platform.types.NoTarget:
|
||||
return generic;
|
||||
|
||||
// Test specific
|
||||
case Platform.types.Test:
|
||||
return generic;
|
||||
default:
|
||||
throw new Error(`
|
||||
Platform must be one of the ones described in the documentation.
|
||||
"${targetPlatform}" is currently not supported.`);
|
||||
}
|
||||
}
|
||||
|
||||
get tag() {
|
||||
const versionAndTarget = `${this.editorVersion}-${this.targetPlatformSuffix}`.replace(
|
||||
/-+$/,
|
||||
'',
|
||||
);
|
||||
|
||||
return `${this.imagePlatformPrefix}-${versionAndTarget}-${this.imageRollingVersion}`;
|
||||
}
|
||||
|
||||
get image() {
|
||||
return `${this.repository}/${this.name}`.replace(/^\/+/, '');
|
||||
}
|
||||
|
||||
toString() {
|
||||
const { image, tag, customImage } = this;
|
||||
|
||||
if (customImage) return customImage;
|
||||
|
||||
return `${image}:${tag}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default ImageTag;
|
||||
10
src/model/index.test.ts
Normal file
10
src/model/index.test.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as Index from '.';
|
||||
|
||||
describe('Index', () => {
|
||||
test.each(['Action', 'Docker', 'ImageTag', 'Input', 'Output', 'ResultsCheck'])(
|
||||
'exports %s',
|
||||
exportedModule => {
|
||||
expect(Index[exportedModule]).toBeDefined();
|
||||
},
|
||||
);
|
||||
});
|
||||
6
src/model/index.ts
Normal file
6
src/model/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as Action } from './action';
|
||||
export { default as Docker } from './docker';
|
||||
export { default as ImageTag } from './image-tag';
|
||||
export { default as Input } from './input';
|
||||
export { default as Output } from './output';
|
||||
export { default as ResultsCheck } from './results-check';
|
||||
36
src/model/input.test.ts
Normal file
36
src/model/input.test.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import Input from './input';
|
||||
|
||||
jest.mock('./unity-version-parser');
|
||||
|
||||
describe('Input', () => {
|
||||
describe('getFromUser', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Input.getFromUser()).not.toThrow();
|
||||
});
|
||||
|
||||
it('returns an object', () => {
|
||||
expect(typeof Input.getFromUser()).toStrictEqual('object');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidFolderName', () => {
|
||||
test.each([
|
||||
'.',
|
||||
'./',
|
||||
'folder',
|
||||
'trailing/',
|
||||
'.hidden',
|
||||
'.hidden/sub',
|
||||
'.hidden/trailing/',
|
||||
'./.hidden-sub',
|
||||
'hyphen-folder',
|
||||
'under_score',
|
||||
])('returns true for %s', folderName => {
|
||||
expect(Input.isValidFolderName(folderName)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
test.each(['..', '../'])('returns false for %s', folderName => {
|
||||
expect(Input.isValidFolderName(folderName)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
76
src/model/input.ts
Normal file
76
src/model/input.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import UnityVersionParser from './unity-version-parser';
|
||||
import { getInput } from '@actions/core';
|
||||
|
||||
const Input = {
|
||||
get testModes() {
|
||||
return ['all', 'playmode', 'editmode'];
|
||||
},
|
||||
|
||||
isValidFolderName(folderName) {
|
||||
const validFolderName = new RegExp(/^(\.|\.\/)?(\.?[\w~]+([ _-]?[\w~]+)*\/?)*$/);
|
||||
|
||||
return validFolderName.test(folderName);
|
||||
},
|
||||
|
||||
getFromUser() {
|
||||
// Input variables specified in workflow using "with" prop.
|
||||
const unityVersion = getInput('unityVersion') || 'auto';
|
||||
const customImage = getInput('customImage') || '';
|
||||
const rawProjectPath = getInput('projectPath') || '.';
|
||||
const unityLicensingServer = getInput('unityLicensingServer') || '';
|
||||
const customParameters = getInput('customParameters') || '';
|
||||
const testMode = (getInput('testMode') || 'all').toLowerCase();
|
||||
const coverageOptions = getInput('coverageOptions') || '';
|
||||
const rawArtifactsPath = getInput('artifactsPath') || 'artifacts';
|
||||
const rawUseHostNetwork = getInput('useHostNetwork') || 'false';
|
||||
const sshAgent = getInput('sshAgent') || '';
|
||||
const gitPrivateToken = getInput('gitPrivateToken') || '';
|
||||
const githubToken = getInput('githubToken') || '';
|
||||
const checkName = getInput('checkName') || 'Test Results';
|
||||
const chownFilesTo = getInput('chownFilesTo') || '';
|
||||
|
||||
// Validate input
|
||||
if (!this.testModes.includes(testMode)) {
|
||||
throw new Error(`Invalid testMode ${testMode}`);
|
||||
}
|
||||
|
||||
if (!this.isValidFolderName(rawProjectPath)) {
|
||||
throw new Error(`Invalid projectPath "${rawProjectPath}"`);
|
||||
}
|
||||
|
||||
if (!this.isValidFolderName(rawArtifactsPath)) {
|
||||
throw new Error(`Invalid artifactsPath "${rawArtifactsPath}"`);
|
||||
}
|
||||
|
||||
if (rawUseHostNetwork !== 'true' && rawUseHostNetwork !== 'false') {
|
||||
throw new Error(`Invalid useHostNetwork "${rawUseHostNetwork}"`);
|
||||
}
|
||||
|
||||
// Sanitise input
|
||||
const projectPath = rawProjectPath.replace(/\/$/, '');
|
||||
const artifactsPath = rawArtifactsPath.replace(/\/$/, '');
|
||||
const useHostNetwork = rawUseHostNetwork === 'true';
|
||||
const editorVersion =
|
||||
unityVersion === 'auto' ? UnityVersionParser.read(projectPath) : unityVersion;
|
||||
|
||||
// Return sanitised input
|
||||
return {
|
||||
editorVersion,
|
||||
customImage,
|
||||
projectPath,
|
||||
customParameters,
|
||||
testMode,
|
||||
coverageOptions,
|
||||
artifactsPath,
|
||||
useHostNetwork,
|
||||
sshAgent,
|
||||
gitPrivateToken,
|
||||
githubToken,
|
||||
checkName,
|
||||
chownFilesTo,
|
||||
unityLicensingServer,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default Input;
|
||||
20
src/model/licensing-server-setup.ts
Normal file
20
src/model/licensing-server-setup.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as core from '@actions/core';
|
||||
import fs from 'fs';
|
||||
|
||||
class LicensingServerSetup {
|
||||
public static Setup(unityLicensingServer, actionFolder: string) {
|
||||
const servicesConfigPath = `${actionFolder}/unity-config/services-config.json`;
|
||||
const servicesConfigPathTemplate = `${servicesConfigPath}.template`;
|
||||
if (!fs.existsSync(servicesConfigPathTemplate)) {
|
||||
core.error(`Missing services config ${servicesConfigPathTemplate}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let servicesConfig = fs.readFileSync(servicesConfigPathTemplate).toString();
|
||||
servicesConfig = servicesConfig.replace('%URL%', unityLicensingServer);
|
||||
fs.writeFileSync(servicesConfigPath, servicesConfig);
|
||||
}
|
||||
}
|
||||
|
||||
export default LicensingServerSetup;
|
||||
24
src/model/output.test.ts
Normal file
24
src/model/output.test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import Output from './output';
|
||||
|
||||
describe('Output', () => {
|
||||
describe('setArtifactsPath', () => {
|
||||
it('does not throw', async () => {
|
||||
await expect(Output.setArtifactsPath('')).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
describe('setCoveragePath', () => {
|
||||
it('does not throw', async () => {
|
||||
await expect(Output.setCoveragePath('')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('artifacts')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('coverage')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('CodeCoverage')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./artifacts')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./coverage')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./CodeCoverage')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./artifacts/coverage')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./coverage/')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./CodeCoverage/')).resolves.not.toThrow();
|
||||
await expect(Output.setCoveragePath('./artifacts/coverage/')).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
12
src/model/output.ts
Normal file
12
src/model/output.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import * as core from '@actions/core';
|
||||
|
||||
const Output = {
|
||||
async setArtifactsPath(artifactsPath) {
|
||||
await core.setOutput('artifactsPath', artifactsPath);
|
||||
},
|
||||
async setCoveragePath(coveragePath) {
|
||||
await core.setOutput('coveragePath', coveragePath);
|
||||
},
|
||||
};
|
||||
|
||||
export default Output;
|
||||
37
src/model/platform.test.ts
Normal file
37
src/model/platform.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import Platform from './platform';
|
||||
|
||||
describe('Platform', () => {
|
||||
describe('default', () => {
|
||||
it('does not throw', () => {
|
||||
expect(() => Platform.default).not.toThrow();
|
||||
});
|
||||
|
||||
it('returns a string', () => {
|
||||
expect(typeof Platform.default).toStrictEqual('string');
|
||||
});
|
||||
|
||||
it('returns a platform', () => {
|
||||
expect(Object.values(Platform.types)).toContain(Platform.default);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isWindows', () => {
|
||||
it('returns true for windows', () => {
|
||||
expect(Platform.isWindows(Platform.types.StandaloneWindows64)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for MacOS', () => {
|
||||
expect(Platform.isWindows(Platform.types.StandaloneOSX)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAndroid', () => {
|
||||
it('returns true for Android', () => {
|
||||
expect(Platform.isAndroid(Platform.types.Android)).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('returns false for Windows', () => {
|
||||
expect(Platform.isAndroid(Platform.types.StandaloneWindows64)).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
51
src/model/platform.ts
Normal file
51
src/model/platform.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
const Platform = {
|
||||
get default() {
|
||||
return Platform.types.StandaloneWindows64;
|
||||
},
|
||||
|
||||
get types() {
|
||||
return {
|
||||
StandaloneOSX: 'StandaloneOSX',
|
||||
StandaloneWindows: 'StandaloneWindows',
|
||||
StandaloneWindows64: 'StandaloneWindows64',
|
||||
StandaloneLinux64: 'StandaloneLinux64',
|
||||
iOS: 'iOS',
|
||||
Android: 'Android',
|
||||
WebGL: 'WebGL',
|
||||
WSAPlayer: 'WSAPlayer',
|
||||
PS4: 'PS4',
|
||||
XboxOne: 'XboxOne',
|
||||
tvOS: 'tvOS',
|
||||
Switch: 'Switch',
|
||||
// Unsupported
|
||||
Lumin: 'Lumin',
|
||||
BJM: 'BJM',
|
||||
Stadia: 'Stadia',
|
||||
Facebook: 'Facebook',
|
||||
NoTarget: 'NoTarget',
|
||||
// Test specific
|
||||
Test: 'Test',
|
||||
};
|
||||
},
|
||||
|
||||
isWindows(platform) {
|
||||
switch (platform) {
|
||||
case Platform.types.StandaloneWindows:
|
||||
case Platform.types.StandaloneWindows64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
isAndroid(platform) {
|
||||
switch (platform) {
|
||||
case Platform.types.Android:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default Platform;
|
||||
9
src/model/results-check.test.ts
Normal file
9
src/model/results-check.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import ResultsCheck from './results-check';
|
||||
|
||||
describe('ResultsCheck', () => {
|
||||
describe('createCheck', () => {
|
||||
it('throws for missing input', () => {
|
||||
expect(() => ResultsCheck.createCheck('', '', '')).rejects;
|
||||
});
|
||||
});
|
||||
});
|
||||
120
src/model/results-check.ts
Normal file
120
src/model/results-check.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as fs from 'fs';
|
||||
import * as github from '@actions/github';
|
||||
import Handlebars from 'handlebars';
|
||||
import ResultsParser from './results-parser';
|
||||
import { RunMeta } from './results-meta';
|
||||
import path from 'path';
|
||||
|
||||
const ResultsCheck = {
|
||||
async createCheck(artifactsPath, githubToken, checkName) {
|
||||
// Validate input
|
||||
if (!fs.existsSync(artifactsPath) || !githubToken || !checkName) {
|
||||
throw new Error(
|
||||
`Missing input! {"artifactsPath": "${artifactsPath}", "githubToken": "${githubToken}, "checkName": "${checkName}"`,
|
||||
);
|
||||
}
|
||||
|
||||
// Parse all results files
|
||||
const runs: RunMeta[] = [];
|
||||
const files = fs.readdirSync(artifactsPath);
|
||||
await Promise.all(
|
||||
files.map(async filepath => {
|
||||
if (!filepath.endsWith('.xml')) return;
|
||||
core.info(`Processing file ${filepath}...`);
|
||||
const fileData = await ResultsParser.parseResults(path.join(artifactsPath, filepath));
|
||||
core.info(fileData.summary);
|
||||
runs.push(fileData);
|
||||
}),
|
||||
);
|
||||
|
||||
// Combine all results into a single run summary
|
||||
const runSummary = new RunMeta(checkName);
|
||||
for (const run of runs) {
|
||||
runSummary.total += run.total;
|
||||
runSummary.passed += run.passed;
|
||||
runSummary.skipped += run.skipped;
|
||||
runSummary.failed += run.failed;
|
||||
runSummary.duration += run.duration;
|
||||
for (const suite of run.suites) {
|
||||
runSummary.addTests(suite.tests);
|
||||
}
|
||||
}
|
||||
|
||||
// Log
|
||||
core.info('=================');
|
||||
core.info('Analyze result:');
|
||||
core.info(runSummary.summary);
|
||||
|
||||
// Format output
|
||||
const title = runSummary.summary;
|
||||
const summary = await ResultsCheck.renderSummary(runs);
|
||||
core.debug(`Summary view: ${summary}`);
|
||||
const details = await ResultsCheck.renderDetails(runs);
|
||||
core.debug(`Details view: ${details}`);
|
||||
const rawAnnotations = runSummary.extractAnnotations();
|
||||
core.debug(`Raw annotations: ${rawAnnotations}`);
|
||||
const annotations = rawAnnotations.map(rawAnnotation => {
|
||||
const annotation = rawAnnotation;
|
||||
annotation.path = rawAnnotation.path.replace('/github/workspace/', '');
|
||||
return annotation;
|
||||
});
|
||||
core.debug(`Annotations: ${annotations}`);
|
||||
const output = {
|
||||
title,
|
||||
summary,
|
||||
text: details,
|
||||
annotations: annotations.slice(0, 50),
|
||||
};
|
||||
|
||||
// Call GitHub API
|
||||
await ResultsCheck.requestGitHubCheck(githubToken, checkName, output);
|
||||
return runSummary.failed;
|
||||
},
|
||||
|
||||
async requestGitHubCheck(githubToken, checkName, output) {
|
||||
const pullRequest = github.context.payload.pull_request;
|
||||
const headSha = (pullRequest && pullRequest.head.sha) || github.context.sha;
|
||||
|
||||
core.info(`Posting results for ${headSha}`);
|
||||
const createCheckRequest = {
|
||||
...github.context.repo,
|
||||
name: checkName,
|
||||
head_sha: headSha,
|
||||
status: 'completed',
|
||||
conclusion: 'neutral',
|
||||
output,
|
||||
};
|
||||
|
||||
const octokit = github.getOctokit(githubToken);
|
||||
await octokit.rest.checks.create(createCheckRequest);
|
||||
},
|
||||
|
||||
async renderSummary(runMetas) {
|
||||
return ResultsCheck.render(`${__dirname}/results-check-summary.hbs`, runMetas);
|
||||
},
|
||||
|
||||
async renderDetails(runMetas) {
|
||||
return ResultsCheck.render(`${__dirname}/results-check-details.hbs`, runMetas);
|
||||
},
|
||||
|
||||
async render(viewPath, runMetas) {
|
||||
Handlebars.registerHelper('indent', toIndent =>
|
||||
toIndent
|
||||
.split('\n')
|
||||
.map(s => ` ${s.replace('/github/workspace/', '')}`)
|
||||
.join('\n'),
|
||||
);
|
||||
const source = await fs.promises.readFile(viewPath, 'utf8');
|
||||
const template = Handlebars.compile(source);
|
||||
return template(
|
||||
{ runs: runMetas },
|
||||
{
|
||||
allowProtoMethodsByDefault: true,
|
||||
allowProtoPropertiesByDefault: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default ResultsCheck;
|
||||
118
src/model/results-meta.ts
Normal file
118
src/model/results-meta.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { components } from '@octokit/openapi-types';
|
||||
|
||||
export function timeHelper(seconds: number): string {
|
||||
return `${seconds.toFixed(3)}s`;
|
||||
}
|
||||
|
||||
export abstract class Meta {
|
||||
title: string;
|
||||
duration = 0;
|
||||
|
||||
constructor(title: string) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
abstract get summary(): string;
|
||||
|
||||
abstract get mark(): string;
|
||||
}
|
||||
|
||||
export type Annotation = components['schemas']['check-annotation'];
|
||||
|
||||
export class RunMeta extends Meta {
|
||||
total = 0;
|
||||
passed = 0;
|
||||
skipped = 0;
|
||||
failed = 0;
|
||||
|
||||
tests: TestMeta[] = [];
|
||||
suites: RunMeta[] = [];
|
||||
|
||||
extractAnnotations(): Annotation[] {
|
||||
const result = [] as Annotation[];
|
||||
for (const suite of this.suites) {
|
||||
result.push(...suite.extractAnnotations());
|
||||
}
|
||||
for (const test of this.tests) {
|
||||
if (test.annotation !== undefined) {
|
||||
result.push(test.annotation);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
addTests(testSuite: TestMeta[]): void {
|
||||
for (const test of testSuite) {
|
||||
this.addTest(test);
|
||||
}
|
||||
}
|
||||
|
||||
addTest(test: TestMeta): void {
|
||||
if (test.suite === undefined) {
|
||||
return;
|
||||
}
|
||||
if (test.suite === this.title) {
|
||||
this.total++;
|
||||
this.duration += test.duration;
|
||||
this.tests.push(test);
|
||||
if (test.result === 'Passed') this.passed++;
|
||||
else if (test.result === 'Failed') this.failed++;
|
||||
else this.skipped++;
|
||||
return;
|
||||
}
|
||||
|
||||
let target = this.suites.find(s => s.title === test.suite);
|
||||
if (target === undefined) {
|
||||
target = new RunMeta(test.suite);
|
||||
this.suites.push(target);
|
||||
}
|
||||
|
||||
target.addTest(test);
|
||||
}
|
||||
|
||||
get summary(): string {
|
||||
const result = this.failed > 0 ? 'Failed' : 'Passed';
|
||||
const sPart = this.skipped > 0 ? `, skipped: ${this.skipped}` : '';
|
||||
const fPart = this.failed > 0 ? `, failed: ${this.failed}` : '';
|
||||
const dPart = ` in ${timeHelper(this.duration)}`;
|
||||
return `${this.mark} ${this.title} - ${this.passed}/${this.total}${sPart}${fPart} - ${result}${dPart}`;
|
||||
}
|
||||
|
||||
get mark(): string {
|
||||
if (this.failed > 0) return '❌️';
|
||||
else if (this.skipped === 0) return '✅';
|
||||
return '⚠️';
|
||||
}
|
||||
}
|
||||
|
||||
export class TestMeta extends Meta {
|
||||
suite: string;
|
||||
result: string | undefined;
|
||||
annotation: Annotation | undefined;
|
||||
|
||||
constructor(suite: string, title: string) {
|
||||
super(title);
|
||||
this.suite = suite;
|
||||
this.result = undefined;
|
||||
this.duration = Number.NaN;
|
||||
}
|
||||
|
||||
isSkipped(): boolean {
|
||||
return this.result === 'Skipped';
|
||||
}
|
||||
|
||||
isFailed(): boolean {
|
||||
return this.result === 'Failed';
|
||||
}
|
||||
|
||||
get summary(): string {
|
||||
const dPart = this.isSkipped() ? '' : ` in ${timeHelper(this.duration)}`;
|
||||
return `${this.mark} **${this.title}** - ${this.result}${dPart}`;
|
||||
}
|
||||
|
||||
get mark(): string {
|
||||
if (this.isFailed()) return '❌️';
|
||||
else if (this.isSkipped()) return '⚠️';
|
||||
return '✅';
|
||||
}
|
||||
}
|
||||
252
src/model/results-parser.test.ts
Normal file
252
src/model/results-parser.test.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import * as fs from 'fs';
|
||||
import * as xmljs from 'xml-js';
|
||||
import ResultsParser from './results-parser';
|
||||
import { TestMeta } from './results-meta';
|
||||
|
||||
describe('ResultsParser', () => {
|
||||
describe('parseResults', () => {
|
||||
it('throws for missing file', () => {
|
||||
expect(() => ResultsParser.parseResults('')).rejects;
|
||||
});
|
||||
|
||||
it('parses editmode-results.xml', () => {
|
||||
expect(() => ResultsParser.parseResults('./artifacts/editmode-results.xml')).not.toThrow();
|
||||
});
|
||||
|
||||
it('parses playmode-results.xml', () => {
|
||||
expect(() => ResultsParser.parseResults('./artifacts/playmode-results.xml')).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertResults', () => {
|
||||
it('converts editmode-results.xml', () => {
|
||||
const file = fs.readFileSync('./artifacts/editmode-results.xml', 'utf8');
|
||||
const filedata = xmljs.xml2js(file, { compact: true });
|
||||
const result = ResultsParser.convertResults('editmode-results.xml', filedata);
|
||||
expect(result.suites.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('converts playmode-results.xml', () => {
|
||||
const file = fs.readFileSync('./artifacts/playmode-results.xml', 'utf8');
|
||||
const filedata = xmljs.xml2js(file, { compact: true });
|
||||
const result = ResultsParser.convertResults('playmode-results.xml', filedata);
|
||||
expect(result.suites.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertSuite', () => {
|
||||
test('convert single', () => {
|
||||
const targetSuite = {
|
||||
_attributes: {
|
||||
fullname: 'Suite Full Name',
|
||||
},
|
||||
'test-case': [{ _attributes: { name: 'testA' } }, { _attributes: { name: 'testB' } }],
|
||||
'test-suite': [
|
||||
{
|
||||
_attributes: {
|
||||
fullname: 'Inner Suite Full Name',
|
||||
},
|
||||
'test-case': { _attributes: { name: 'testC' } },
|
||||
'test-suite': [],
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = ResultsParser.convertSuite(targetSuite);
|
||||
|
||||
expect(result).toMatchObject([
|
||||
new TestMeta('Inner Suite Full Name', 'testC'),
|
||||
new TestMeta('Suite Full Name', 'testA'),
|
||||
new TestMeta('Suite Full Name', 'testB'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertTests', () => {
|
||||
test('convert array', () => {
|
||||
const testA = { _attributes: { name: 'testA' } };
|
||||
const testB = { _attributes: { name: 'testB' } };
|
||||
const testResult = [testA, testB];
|
||||
const result = ResultsParser.convertTests('Test Suite', testResult);
|
||||
|
||||
expect(result).toMatchObject([
|
||||
{ suite: 'Test Suite', title: 'testA' },
|
||||
{ suite: 'Test Suite', title: 'testB' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('convert single', () => {
|
||||
const testA = { _attributes: { name: 'testA' } };
|
||||
const result = ResultsParser.convertTests('Test Suite', testA);
|
||||
|
||||
expect(result).toMatchObject([{ suite: 'Test Suite', title: 'testA' }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertTestCase', () => {
|
||||
test('not failed', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toBeUndefined();
|
||||
});
|
||||
|
||||
test('no stack trace', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
failure: {
|
||||
message: { _cdata: 'Message CDATA' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toBeUndefined();
|
||||
});
|
||||
|
||||
test('no cdata in stack trace', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
failure: {
|
||||
message: { _cdata: 'Message CDATA' },
|
||||
'stack-trace': {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toBeUndefined();
|
||||
});
|
||||
|
||||
test('no annotation path', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
failure: {
|
||||
message: { _cdata: 'Message CDATA' },
|
||||
'stack-trace': { _cdata: 'Test CDATA' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toBeUndefined();
|
||||
});
|
||||
|
||||
test('prepare annotation without console output', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
fullname: 'Test Full Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
failure: {
|
||||
message: { _cdata: 'Message CDATA' },
|
||||
'stack-trace': {
|
||||
_cdata:
|
||||
'at Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toMatchObject({
|
||||
annotation_level: 'failure',
|
||||
end_line: 10,
|
||||
message: 'Message CDATA',
|
||||
path: '/github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs',
|
||||
raw_details:
|
||||
'at Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10',
|
||||
start_line: 10,
|
||||
title: 'Test Full Name',
|
||||
});
|
||||
});
|
||||
|
||||
test('prepare annotation with console output', () => {
|
||||
const result = ResultsParser.convertTestCase('Test Suite', {
|
||||
_attributes: {
|
||||
name: 'Test Name',
|
||||
fullname: 'Test Full Name',
|
||||
duration: '3.14',
|
||||
},
|
||||
output: {
|
||||
_cdata: '[Warning] This is a warning',
|
||||
},
|
||||
failure: {
|
||||
message: { _cdata: 'Message CDATA' },
|
||||
'stack-trace': {
|
||||
_cdata:
|
||||
'at Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.suite).toBe('Test Suite');
|
||||
expect(result.title).toBe('Test Name');
|
||||
expect(result.duration).toBe(3.14);
|
||||
expect(result.annotation).toMatchObject({
|
||||
annotation_level: 'failure',
|
||||
end_line: 10,
|
||||
message: 'Message CDATA',
|
||||
path: '/github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs',
|
||||
raw_details:
|
||||
'[Warning] This is a warning\nat Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10',
|
||||
start_line: 10,
|
||||
title: 'Test Full Name',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAnnotationPoint', () => {
|
||||
test('keep working if not matching', () => {
|
||||
const result = ResultsParser.findAnnotationPoint('');
|
||||
expect(result.path).toBe('');
|
||||
expect(result.line).toBe(0);
|
||||
});
|
||||
|
||||
test('simple annotation point', () => {
|
||||
const result =
|
||||
ResultsParser.findAnnotationPoint(`at Tests.PlayModeTest+<FailedUnityTest>d__5.MoveNext () [0x0002e] in /github/workspace/unity-project/Assets/Tests/PlayModeTest.cs:39
|
||||
at UnityEngine.TestTools.TestEnumerator+<Execute>d__6.MoveNext () [0x00038] in /github/workspace/unity-project/Library/PackageCache/com.unity.test-framework@1.1.19/UnityEngine.TestRunner/NUnitExtensions/Attributes/TestEnumerator.cs:36`);
|
||||
expect(result.path).toBe('/github/workspace/unity-project/Assets/Tests/PlayModeTest.cs');
|
||||
expect(result.line).toBe(39);
|
||||
});
|
||||
|
||||
test('first entry with non-zero line number annotation point', () => {
|
||||
const result =
|
||||
ResultsParser.findAnnotationPoint(`at FluentAssertions.Execution.LateBoundTestFramework.Throw (System.String message) [0x00044] in <527a5493e59e45679b35c1e8d65350b3>:0
|
||||
at FluentAssertions.Execution.TestFrameworkProvider.Throw (System.String message) [0x00011] in <527a5493e59e45679b35c1e8d65350b3>:0
|
||||
at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure (System.String message) [0x00005] in <527a5493e59e45679b35c1e8d65350b3>:0
|
||||
at Tests.PlayModeTest+<FailedUnityTest>d__5.MoveNext () [0x0002e] in /github/workspace/unity-project/Assets/Tests/PlayModeTest.cs:39
|
||||
at UnityEngine.TestTools.TestEnumerator+<Execute>d__6.MoveNext () [0x00038] in /github/workspace/unity-project/Library/PackageCache/com.unity.test-framework@1.1.19/UnityEngine.TestRunner/NUnitExtensions/Attributes/TestEnumerator.cs:36`);
|
||||
expect(result.path).toBe('/github/workspace/unity-project/Assets/Tests/PlayModeTest.cs');
|
||||
expect(result.line).toBe(39);
|
||||
});
|
||||
|
||||
test('setup annotation point', () => {
|
||||
const result = ResultsParser.findAnnotationPoint(`SetUp
|
||||
at Tests.SetupFailedTest.SetUp () [0x00000] in /github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs:10`);
|
||||
expect(result.path).toBe('/github/workspace/unity-project/Assets/Tests/SetupFailedTest.cs');
|
||||
expect(result.line).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
157
src/model/results-parser.ts
Normal file
157
src/model/results-parser.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
import * as core from '@actions/core';
|
||||
import * as fs from 'fs';
|
||||
import * as xmljs from 'xml-js';
|
||||
import { RunMeta, TestMeta } from './results-meta';
|
||||
import path from 'path';
|
||||
|
||||
const ResultsParser = {
|
||||
async parseResults(filepath): Promise<RunMeta> {
|
||||
if (!fs.existsSync(filepath)) {
|
||||
throw new Error(`Missing file! {"filepath": "${filepath}"}`);
|
||||
}
|
||||
|
||||
core.info(`Trying to open ${filepath}`);
|
||||
const file = await fs.promises.readFile(filepath, 'utf8');
|
||||
const results = xmljs.xml2js(file, { compact: true });
|
||||
core.info(`File ${filepath} parsed...`);
|
||||
|
||||
return ResultsParser.convertResults(path.basename(filepath), results);
|
||||
},
|
||||
|
||||
convertResults(filename, filedata): RunMeta {
|
||||
core.info(`Start analyzing results: ${filename}`);
|
||||
|
||||
const run = filedata['test-run'];
|
||||
const runMeta = new RunMeta(filename);
|
||||
const tests = ResultsParser.convertSuite(run['test-suite']);
|
||||
core.debug(tests.toString());
|
||||
|
||||
runMeta.total = Number(run._attributes.total);
|
||||
runMeta.failed = Number(run._attributes.failed);
|
||||
runMeta.skipped = Number(run._attributes.skipped);
|
||||
runMeta.passed = Number(run._attributes.passed);
|
||||
runMeta.duration = Number(run._attributes.duration);
|
||||
runMeta.addTests(tests);
|
||||
|
||||
return runMeta;
|
||||
},
|
||||
|
||||
convertSuite(suites) {
|
||||
if (Array.isArray(suites)) {
|
||||
const innerResult: TestMeta[] = [];
|
||||
for (const suite of suites) {
|
||||
innerResult.push(...ResultsParser.convertSuite(suite));
|
||||
}
|
||||
return innerResult;
|
||||
}
|
||||
|
||||
const result: TestMeta[] = [];
|
||||
const innerSuite = suites['test-suite'];
|
||||
if (innerSuite) {
|
||||
result.push(...ResultsParser.convertSuite(innerSuite));
|
||||
}
|
||||
|
||||
const tests = suites['test-case'];
|
||||
if (tests) {
|
||||
result.push(...ResultsParser.convertTests(suites._attributes.fullname, tests));
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
convertTests(suite, tests): TestMeta[] {
|
||||
if (Array.isArray(tests)) {
|
||||
const result: TestMeta[] = [];
|
||||
for (const testCase of tests) {
|
||||
result.push(ResultsParser.convertTestCase(suite, testCase));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return [ResultsParser.convertTestCase(suite, tests)];
|
||||
},
|
||||
|
||||
convertTestCase(suite, testCase): TestMeta {
|
||||
const { _attributes, failure, output } = testCase;
|
||||
const { name, fullname, result, duration } = _attributes;
|
||||
const testMeta = new TestMeta(suite, name);
|
||||
testMeta.result = result;
|
||||
testMeta.duration = Number(duration);
|
||||
|
||||
if (!failure) {
|
||||
core.debug(`Skip test ${fullname} without failure data`);
|
||||
return testMeta;
|
||||
}
|
||||
|
||||
core.debug(`Convert data for test ${fullname}`);
|
||||
if (failure['stack-trace'] === undefined) {
|
||||
core.warning(`No stack trace for test case: ${fullname}`);
|
||||
return testMeta;
|
||||
}
|
||||
|
||||
const trace = failure['stack-trace']._cdata;
|
||||
if (trace === undefined) {
|
||||
core.warning(`No cdata in stack trace for test case: ${fullname}`);
|
||||
return testMeta;
|
||||
}
|
||||
const point = ResultsParser.findAnnotationPoint(trace);
|
||||
if (!point.path || !point.line) {
|
||||
core.warning(`Not able to find annotation point for failed test! Test trace: ${trace}`);
|
||||
return testMeta;
|
||||
}
|
||||
|
||||
const rawDetails = [trace];
|
||||
|
||||
if (output && output._cdata) {
|
||||
rawDetails.unshift(output._cdata);
|
||||
} else {
|
||||
core.debug(`No console output for test case: ${fullname}`);
|
||||
}
|
||||
|
||||
testMeta.annotation = {
|
||||
path: point.path,
|
||||
start_line: point.line,
|
||||
end_line: point.line,
|
||||
annotation_level: 'failure',
|
||||
title: fullname,
|
||||
message: failure.message._cdata ? failure.message._cdata : 'Test Failed!',
|
||||
raw_details: rawDetails.join('\n'),
|
||||
start_column: 0,
|
||||
end_column: 0,
|
||||
blob_href: '',
|
||||
};
|
||||
core.info(
|
||||
`- ${testMeta.annotation.path}:${testMeta.annotation.start_line} - ${testMeta.annotation.title}`,
|
||||
);
|
||||
return testMeta;
|
||||
},
|
||||
|
||||
findAnnotationPoint(trace) {
|
||||
// Find first entry with non-zero line number in stack trace
|
||||
const items = trace.match(/at .* in ((?<path>[^:]+):(?<line>\d+))/g);
|
||||
if (Array.isArray(items)) {
|
||||
const result: { path: any; line: number }[] = [];
|
||||
for (const item of items) {
|
||||
const match = item.match(/at .* in ((?<path>[^:]+):(?<line>\d+))/);
|
||||
const point = {
|
||||
path: match ? match.groups.path : '',
|
||||
line: match ? Number(match.groups.line) : 0,
|
||||
};
|
||||
if (point.line > 0) {
|
||||
result.push(point);
|
||||
}
|
||||
}
|
||||
if (result.length > 0) {
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
// If all entries have zero line number match fallback pattern
|
||||
const match = trace.match(/at .* in ((?<path>[^:]+):(?<line>\d+))/);
|
||||
return {
|
||||
path: match ? match.groups.path : '',
|
||||
line: match ? Number(match.groups.line) : 0,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default ResultsParser;
|
||||
58
src/model/results-report.ts
Normal file
58
src/model/results-report.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
interface CommonAttributes {
|
||||
id: string;
|
||||
result: string;
|
||||
asserts: string;
|
||||
|
||||
'start-time': string;
|
||||
'end-time': string;
|
||||
duration: string;
|
||||
}
|
||||
|
||||
interface CommonSuiteAttributes extends CommonAttributes {
|
||||
total: string;
|
||||
passed: string;
|
||||
failed: string;
|
||||
skipped: string;
|
||||
}
|
||||
|
||||
export interface TestRun {
|
||||
_attributes: TestRunAttributes;
|
||||
'test-suite': TestSuite | TestSuite[];
|
||||
}
|
||||
|
||||
export interface TestRunAttributes extends CommonSuiteAttributes {
|
||||
testcasecount: string;
|
||||
'engine-version': string;
|
||||
}
|
||||
|
||||
export interface TestSuite {
|
||||
_attributes: TestSuiteAttributes;
|
||||
'test-suite': TestSuite | TestSuite[];
|
||||
'test-case': TestCase | TestCase[];
|
||||
failure?: FailureMessage;
|
||||
}
|
||||
|
||||
export interface TestSuiteAttributes extends CommonSuiteAttributes {
|
||||
type: string;
|
||||
name: string;
|
||||
fullname: string;
|
||||
}
|
||||
|
||||
export interface TestCase {
|
||||
_attributes: TestCaseAttributes;
|
||||
failure?: FailureMessage;
|
||||
}
|
||||
|
||||
export interface TestCaseAttributes extends CommonAttributes {
|
||||
name: string;
|
||||
fullname: string;
|
||||
methodname: string;
|
||||
classname: string;
|
||||
runstate: string;
|
||||
seed: string;
|
||||
}
|
||||
|
||||
export interface FailureMessage {
|
||||
message: { _cdata: string };
|
||||
'stack-trace'?: { _cdata: string };
|
||||
}
|
||||
25
src/model/unity-version-parser.test.ts
Normal file
25
src/model/unity-version-parser.test.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import UnityVersionParser from './unity-version-parser';
|
||||
|
||||
describe('UnityVersionParser', () => {
|
||||
describe('parse', () => {
|
||||
it('throws for empty string', () => {
|
||||
expect(() => UnityVersionParser.parse('')).toThrow(Error);
|
||||
});
|
||||
|
||||
it('parses from ProjectVersion.txt', () => {
|
||||
const projectVersionContents = `m_EditorVersion: 2019.2.11f1
|
||||
m_EditorVersionWithRevision: 2019.2.11f1 (5f859a4cfee5)`;
|
||||
expect(UnityVersionParser.parse(projectVersionContents)).toBe('2019.2.11f1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
it('throws for invalid path', () => {
|
||||
expect(() => UnityVersionParser.read('')).toThrow(Error);
|
||||
});
|
||||
|
||||
it('reads from unity-project-with-correct-tests', () => {
|
||||
expect(UnityVersionParser.read('./unity-project-with-correct-tests')).toBe('2019.2.11f1');
|
||||
});
|
||||
});
|
||||
});
|
||||
28
src/model/unity-version-parser.ts
Normal file
28
src/model/unity-version-parser.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const UnityVersionParser = {
|
||||
get versionPattern() {
|
||||
return /20\d{2}\.\d\.\w{3,4}|3/;
|
||||
},
|
||||
|
||||
parse(projectVersionTxt) {
|
||||
const matches = projectVersionTxt.match(UnityVersionParser.versionPattern);
|
||||
if (!matches || matches.length === 0) {
|
||||
throw new Error(`Failed to parse version from "${projectVersionTxt}".`);
|
||||
}
|
||||
return matches[0];
|
||||
},
|
||||
|
||||
read(projectPath) {
|
||||
const filePath = path.join(projectPath, 'ProjectSettings', 'ProjectVersion.txt');
|
||||
if (!fs.existsSync(filePath)) {
|
||||
throw new Error(
|
||||
`Project settings file not found at "${filePath}". Have you correctly set the projectPath?`,
|
||||
);
|
||||
}
|
||||
return UnityVersionParser.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
},
|
||||
};
|
||||
|
||||
export default UnityVersionParser;
|
||||
12
src/post.ts
Normal file
12
src/post.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import * as core from '@actions/core';
|
||||
import Action from './model/action';
|
||||
import { Docker } from './model';
|
||||
|
||||
export async function run() {
|
||||
try {
|
||||
const parameters = Action.runnerContext();
|
||||
await Docker.ensureContainerRemoval(parameters);
|
||||
} catch (error: any) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
}
|
||||
24
src/views/results-check-details.hbs
Normal file
24
src/views/results-check-details.hbs
Normal file
@@ -0,0 +1,24 @@
|
||||
{{#runs}}
|
||||
|
||||
<details><summary>{{summary}}</summary>
|
||||
|
||||
{{#suites}}
|
||||
*
|
||||
{{summary}}
|
||||
{{#tests}}
|
||||
*
|
||||
{{summary}}
|
||||
{{#if annotation}}
|
||||
{{#if annotation.message}}
|
||||
{{indent annotation.message}}
|
||||
{{/if}}
|
||||
{{#if annotation.raw_details}}
|
||||
{{indent annotation.raw_details}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/tests}}
|
||||
{{/suites}}
|
||||
|
||||
</details>
|
||||
|
||||
{{/runs}}
|
||||
4
src/views/results-check-summary.hbs
Normal file
4
src/views/results-check-summary.hbs
Normal file
@@ -0,0 +1,4 @@
|
||||
{{#runs}}
|
||||
###
|
||||
{{summary}}
|
||||
{{/runs}}
|
||||
12
tsconfig.json
Normal file
12
tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */,
|
||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||
"outDir": "./lib" /* Redirect output structure to the directory. */,
|
||||
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
"noImplicitAny": false /* Re-enable after fixing compatibility */ /* Raise error on expressions and declarations with an implied 'any' type. */,
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class SampleComponent : MonoBehaviour
|
||||
{
|
||||
public BasicCounter Counter;
|
||||
|
||||
void Start()
|
||||
{
|
||||
Counter = new BasicCounter(5);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
Counter.Increment();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a5f63b9ea4b465194653c4d681faf42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class TimerComponent : MonoBehaviour
|
||||
{
|
||||
public BasicCounter Counter = new BasicCounter();
|
||||
public float Timer = 1f;
|
||||
|
||||
void Update()
|
||||
{
|
||||
Timer -= Time.deltaTime;
|
||||
|
||||
if (Timer > 0)
|
||||
return;
|
||||
|
||||
Counter.Increment();
|
||||
Timer = 1f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b668d68a45bb48108ccda73269e3da7b
|
||||
timeCreated: 1610056748
|
||||
@@ -2,7 +2,8 @@
|
||||
"name": "PlayModeTests",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner"
|
||||
"UnityEditor.TestRunner",
|
||||
"MyScripts"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
@@ -16,4 +17,4 @@
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
public class SampleComponentTest
|
||||
{
|
||||
private GameObject target;
|
||||
private SampleComponent component;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
target = GameObject.Instantiate(new GameObject());
|
||||
component = target.AddComponent<SampleComponent>();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestIncrementOnUpdateAfterNextFrame()
|
||||
{
|
||||
// Save the current value, since it was updated after component Start() method called
|
||||
var count = component.Counter.Count;
|
||||
|
||||
// Skip frame and assert the new value
|
||||
yield return null;
|
||||
Assert.AreEqual(count + 1, component.Counter.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c688799d17b14d35ad515bff9de8d12c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Tests
|
||||
@@ -12,8 +10,14 @@ namespace Tests
|
||||
[Test]
|
||||
public void NewTestScriptSimplePasses()
|
||||
{
|
||||
// Use the Assert class to test conditions
|
||||
Assert.True(true);
|
||||
// Given
|
||||
var counter = new BasicCounter(0);
|
||||
|
||||
// When
|
||||
counter.Increment();
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(1, counter.Count);
|
||||
}
|
||||
|
||||
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
|
||||
@@ -21,9 +25,18 @@ namespace Tests
|
||||
[UnityTest]
|
||||
public IEnumerator NewTestScriptWithEnumeratorPasses()
|
||||
{
|
||||
// Given
|
||||
var counter = new BasicCounter(3);
|
||||
|
||||
// Use the Assert class to test conditions.
|
||||
// Use yield to skip a frame.
|
||||
yield return null;
|
||||
|
||||
// When
|
||||
counter.Increment();
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(4, counter.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
public class TimerComponentTest
|
||||
{
|
||||
private GameObject target;
|
||||
private TimerComponent component;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
target = GameObject.Instantiate(new GameObject());
|
||||
component = target.AddComponent<TimerComponent>();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestIncrementAfterSomeTime()
|
||||
{
|
||||
// Save the current value, since it was updated after component Start() method called
|
||||
var count = component.Counter.Count;
|
||||
|
||||
// Skip frame and assert the new value
|
||||
yield return null;
|
||||
Assert.AreEqual(count, component.Counter.Count);
|
||||
|
||||
yield return new WaitForSeconds(1.1f);
|
||||
Assert.AreEqual(count + 1, component.Counter.Count);
|
||||
|
||||
yield return new WaitForSeconds(1.1f);
|
||||
Assert.AreEqual(count + 2, component.Counter.Count);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestTimeScaleIsAffectingIncrement()
|
||||
{
|
||||
// Save the current value, since it was updated after component Start() method called
|
||||
var count = component.Counter.Count;
|
||||
Time.timeScale = .5f;
|
||||
|
||||
// Skip frame and assert the new value
|
||||
yield return null;
|
||||
Assert.AreEqual(count, component.Counter.Count);
|
||||
|
||||
yield return WaitForRealSeconds(1.1f);
|
||||
Assert.AreEqual(count, component.Counter.Count);
|
||||
|
||||
yield return WaitForRealSeconds(1.1f);
|
||||
Assert.AreEqual(count + 1, component.Counter.Count);
|
||||
}
|
||||
|
||||
// Skipping time ignoring Time.scale
|
||||
// https://answers.unity.com/questions/301868/yield-waitforseconds-outside-of-timescale.html
|
||||
public static IEnumerator WaitForRealSeconds(float time)
|
||||
{
|
||||
float start = Time.realtimeSinceStartup;
|
||||
while (Time.realtimeSinceStartup < start + time)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 818b22370d404398b87b47a922a435c9
|
||||
timeCreated: 1610056889
|
||||
@@ -6,6 +6,7 @@
|
||||
"com.unity.ide.vscode": "1.1.2",
|
||||
"com.unity.package-manager-ui": "2.2.0",
|
||||
"com.unity.test-framework": "1.0.13",
|
||||
"com.unity.testtools.codecoverage": "1.1.1",
|
||||
"com.unity.textmeshpro": "2.0.1",
|
||||
"com.unity.timeline": "1.1.0",
|
||||
"com.unity.ugui": "1.0.0",
|
||||
|
||||
Reference in New Issue
Block a user