Compare commits

...

96 Commits
v0.8 ... v0.14

Author SHA1 Message Date
Webber
34e4b86924 Fix case where no tags does not trigger false 2020-05-01 20:32:41 +02:00
Webber
e9514b4e37 Stop hammering patches 🔨 2020-05-01 17:55:27 +02:00
Webber
d4d91e75c3 Configure codecov threshold 2020-05-01 17:55:27 +02:00
Webber
2085eff264 Add missing test for ref getters 2020-05-01 17:55:27 +02:00
Webber
98a1b078fc Update styles to latest unicorn 🦄 and prettier 🦋 2020-05-01 17:55:27 +02:00
Webber
afef854ea0 update packages to latest 2020-05-01 17:55:27 +02:00
Webber
a0a5de2a83 Cover all versioning paths 2020-05-01 16:15:56 +02:00
Webber
c146049b33 Mock all output methods from core 2020-05-01 16:15:56 +02:00
Webber
e46399169f Add tests for System model 2020-05-01 16:15:56 +02:00
Webber
b41026b36e Introduce smart fetching, based on type of local repo. 2020-05-01 16:15:56 +02:00
Webber
cd1d215dfa Remove unshallow fetch 2020-05-01 16:15:56 +02:00
Webber
d01e844eea Fix versioning for push event. 2020-05-01 16:15:56 +02:00
Webber
40564afbaf Fix failed test 2020-04-28 02:02:34 +02:00
Webber
b6f8040f4a Add tests for the versioning model 2020-04-28 02:02:34 +02:00
Webber
22c7d0e516 Improve versioning readme 📜 2020-04-26 21:45:10 +02:00
Webber
f85e50e499 Fix bug in hasAnyVersionTags 🐜 2020-04-26 21:45:10 +02:00
Webber
d75d7890d0 Implement versioning strategies in js 🧉 2020-04-26 21:45:10 +02:00
Webber
2e81e61af3 Add additional tests 🧪 2020-04-26 21:45:10 +02:00
Webber
ac76e9d562 Update readme with versioning examples 🧉 2020-04-26 21:45:10 +02:00
Webber
39a160b789 Allow versioning and version parameters. 2020-04-26 21:45:10 +02:00
Webber
e8a2eaad72 Cleanup default-build-script 2020-04-26 21:45:10 +02:00
Webber
6f1d03d8a8 Refactor Builder 2020-04-26 21:45:10 +02:00
Webber
5ee9c59113 Create VersionApplicator 2020-04-26 21:45:10 +02:00
Webber
03510d4a55 Abstract out the stdout reporter 2020-04-26 21:45:10 +02:00
Webber
ad65b0ece4 Abstract out the argument parser 2020-04-26 21:45:10 +02:00
Webber
a513e5b640 Add semantic versioning logic 2020-04-26 21:45:10 +02:00
Webber
328b0d8ac0 Add system extension for Process 2020-04-26 21:45:10 +02:00
Webber
e53dcf13e3 Add .editorconfig for the default-build-script project 2020-04-26 21:45:10 +02:00
dependabot-preview[bot]
3338b392a0 [Security] Bump acorn from 6.4.0 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.4.0 to 6.4.1. **This update includes a security fix.**
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.4.0...6.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-13 22:32:17 +00:00
dependabot-preview[bot]
7e115b5cc3 Bump eslint-plugin-unicorn from 17.0.1 to 17.1.0
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 17.0.1 to 17.1.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v17.0.1...v17.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-10 18:22:23 +00:00
dependabot-preview[bot]
758108295c Bump eslint-plugin-react from 7.18.3 to 7.19.0
Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.18.3 to 7.19.0.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.18.3...v7.19.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-10 09:00:11 +00:00
Webber
8684472273 install deps during build phase 2020-03-09 23:47:22 +01:00
Webber
38b6a42f5e fix dist file 2020-03-09 23:47:22 +01:00
litefeel
fbeaf77867 Apply merge request suggestions 2020-03-09 23:23:53 +01:00
litefeel
6f3a2bd992 Fixed compatibility 2020-03-09 23:23:53 +01:00
litefeel
e1eda1e876 Change UNITY_LICENSE_PATH to UNITY_LICENSE_FILE 2020-03-09 23:23:53 +01:00
litefeel
0088ca3094 Add UNITY_LICENSE_PATH 2020-03-09 23:23:53 +01:00
dependabot-preview[bot]
465f15a945 Bump eslint-plugin-unicorn from 16.1.1 to 17.0.1
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 16.1.1 to 17.0.1.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v16.1.1...v17.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-09 21:53:00 +00:00
dependabot-preview[bot]
ffe381e28a Bump @babel/core from 7.8.6 to 7.8.7
Bumps [@babel/core](https://github.com/babel/babel) from 7.8.6 to 7.8.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.6...v7.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-05 15:36:08 +00:00
dependabot-preview[bot]
085359d24f Bump @babel/preset-env from 7.8.6 to 7.8.7
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.8.6 to 7.8.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.6...v7.8.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-05 15:26:03 +00:00
dependabot-preview[bot]
b47dcdab84 Bump @babel/core from 7.8.4 to 7.8.6
Bumps [@babel/core](https://github.com/babel/babel) from 7.8.4 to 7.8.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.4...v7.8.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-28 09:18:56 +00:00
dependabot-preview[bot]
0c23c7d0a3 Bump @babel/preset-env from 7.8.4 to 7.8.6
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.8.4 to 7.8.6.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.8.4...v7.8.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-28 09:09:38 +00:00
dependabot-preview[bot]
f3099b6226 Bump lint-staged from 10.0.7 to 10.0.8
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 10.0.7 to 10.0.8.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v10.0.7...v10.0.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-28 09:00:06 +00:00
dependabot-preview[bot]
a969d3322f Bump babel-eslint from 10.0.3 to 10.1.0
Bumps [babel-eslint](https://github.com/babel/babel-eslint) from 10.0.3 to 10.1.0.
- [Release notes](https://github.com/babel/babel-eslint/releases)
- [Commits](https://github.com/babel/babel-eslint/compare/v10.0.3...v10.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-27 23:02:57 +00:00
dependabot-preview[bot]
8f63acf12b Bump @actions/github from 2.1.0 to 2.1.1
Bumps [@actions/github](https://github.com/actions/toolkit/tree/HEAD/packages/github) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/master/packages/github/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/github)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-21 08:40:38 +00:00
Webber
1813ee2895 add dist build 2020-02-15 18:02:01 +01:00
dependabot-preview[bot]
6e377601bf Bump @zeit/ncc from 0.21.0 to 0.21.1
Bumps [@zeit/ncc](https://github.com/zeit/ncc) from 0.21.0 to 0.21.1.
- [Release notes](https://github.com/zeit/ncc/releases)
- [Commits](https://github.com/zeit/ncc/compare/0.21.0...0.21.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-15 18:02:01 +01:00
dependabot-preview[bot]
f7321735d5 Bump husky from 4.2.2 to 4.2.3
Bumps [husky](https://github.com/typicode/husky) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/typicode/husky/releases)
- [Changelog](https://github.com/typicode/husky/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typicode/husky/compare/v4.2.2...v4.2.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-13 08:13:42 +00:00
dependabot-preview[bot]
19429bf324 Bump eslint-plugin-unicorn from 16.0.0 to 16.1.1
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 16.0.0 to 16.1.1.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v16.0.0...v16.1.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-12 11:37:51 +01:00
dependabot-preview[bot]
04eaffcd1f Bump husky from 4.2.1 to 4.2.2
Bumps [husky](https://github.com/typicode/husky) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/typicode/husky/releases)
- [Changelog](https://github.com/typicode/husky/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typicode/husky/compare/v4.2.1...v4.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-12 09:52:47 +01:00
Webber
2c1ef01beb Update readme to reflect v0.11 2020-02-11 20:59:27 +01:00
Webber
dfccf539d1 Add custom parameters to test workflow 2020-02-11 20:59:27 +01:00
Webber
c1a7c5f70b Separate custom parameters 2020-02-11 20:59:27 +01:00
dependabot-preview[bot]
7e4851cc3a Bump @zeit/ncc from 0.20.5 to 0.21.0
Bumps [@zeit/ncc](https://github.com/zeit/ncc) from 0.20.5 to 0.21.0.
- [Release notes](https://github.com/zeit/ncc/releases)
- [Commits](https://github.com/zeit/ncc/compare/0.20.5...0.21.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 13:55:58 +01:00
dependabot-preview[bot]
bbb5661b43 Bump husky from 4.0.0-beta.5 to 4.2.1
Bumps [husky](https://github.com/typicode/husky) from 4.0.0-beta.5 to 4.2.1.
- [Release notes](https://github.com/typicode/husky/releases)
- [Changelog](https://github.com/typicode/husky/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typicode/husky/compare/v4.0.0-beta.5...v4.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 13:04:47 +01:00
dependabot-preview[bot]
678fb210be Bump eslint-plugin-flowtype from 4.5.2 to 4.6.0
Bumps [eslint-plugin-flowtype](https://github.com/gajus/eslint-plugin-flowtype) from 4.5.2 to 4.6.0.
- [Release notes](https://github.com/gajus/eslint-plugin-flowtype/releases)
- [Commits](https://github.com/gajus/eslint-plugin-flowtype/compare/v4.5.2...v4.6.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 11:34:58 +01:00
dependabot-preview[bot]
90af9768a7 Bump eslint from 6.7.2 to 6.8.0
Bumps [eslint](https://github.com/eslint/eslint) from 6.7.2 to 6.8.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v6.7.2...v6.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 10:23:53 +01:00
dependabot-preview[bot]
6ab433b631 Bump @babel/core from 7.7.5 to 7.8.4
Bumps [@babel/core](https://github.com/babel/babel) from 7.7.5 to 7.8.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.7.5...v7.8.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 17:55:59 +01:00
dependabot-preview[bot]
d5c4c09fc4 Bump lint-staged from 9.5.0 to 10.0.7
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 9.5.0 to 10.0.7.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v9.5.0...v10.0.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 17:38:42 +01:00
dependabot-preview[bot]
3e69d63ec4 Bump eslint-config-prettier from 6.7.0 to 6.10.0
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 6.7.0 to 6.10.0.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/commits/v6.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 17:13:29 +01:00
dependabot-preview[bot]
c47d5a4d2e Bump eslint-plugin-react from 7.17.0 to 7.18.3
Bumps [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) from 7.17.0 to 7.18.3.
- [Release notes](https://github.com/yannickcr/eslint-plugin-react/releases)
- [Changelog](https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yannickcr/eslint-plugin-react/compare/v7.17.0...v7.18.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 16:49:56 +01:00
dependabot-preview[bot]
9dd75201b0 Bump eslint-plugin-import from 2.19.1 to 2.20.1
Bumps [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import) from 2.19.1 to 2.20.1.
- [Release notes](https://github.com/benmosher/eslint-plugin-import/releases)
- [Changelog](https://github.com/benmosher/eslint-plugin-import/blob/master/CHANGELOG.md)
- [Commits](https://github.com/benmosher/eslint-plugin-import/compare/v2.19.1...v2.20.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-10 14:16:53 +01:00
Webber
308a9e173d fix: upgrade @actions/github from 2.0.0 to 2.0.1 2020-02-09 16:04:51 +01:00
snyk-bot
f5a61eed4a fix: upgrade @actions/exec from 1.0.2 to 1.0.3
Snyk has created this PR to upgrade @actions/exec from 1.0.2 to 1.0.3.

See this package in NPM:
https://www.npmjs.com/package/@actions/exec

See this project in Snyk:
https://app.snyk.io/org/webbertakken/project/e69ca31d-f4f2-4223-ae93-0245ffac3626?utm_source=github&utm_medium=upgrade-pr
2020-02-09 10:28:35 +01:00
Webber
051513bf4a Sort badges by color ugliness 🦄 2020-02-09 01:53:32 +01:00
Webber
d9382df690 put badges on 1 line 2020-02-09 01:53:32 +01:00
Webber
0df7fa7855 Add badges for lgtm, codecov, snyk 2020-02-09 01:24:03 +01:00
Webber
d1c1d276e0 Add token as env, so PRs will trigger codecov 2020-02-09 01:24:03 +01:00
Webber
ad1f47dd3a Set token in runner env 2020-02-09 01:24:03 +01:00
Webber
a0d197e1fa Integrate codecov 2020-02-09 01:24:03 +01:00
Webber
cc244fa58b Add updated index.js 2020-02-08 19:25:58 +01:00
dependabot-preview[bot]
c70fdac383 Bump @actions/core from 1.2.0 to 1.2.2
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.0 to 1.2.2.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/master/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-08 19:25:58 +01:00
dependabot-preview[bot]
81487e2140 Bump @babel/preset-env from 7.7.7 to 7.8.4
Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.7.7 to 7.8.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.7.7...v7.8.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-08 19:09:38 +01:00
dependabot-preview[bot]
ef06de9255 Bump jest from 24.9.0 to 25.1.0
Bumps [jest](https://github.com/facebook/jest) from 24.9.0 to 25.1.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v24.9.0...v25.1.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-08 18:50:59 +01:00
dependabot-preview[bot]
64499d66cc Bump eslint-plugin-unicorn from 14.0.1 to 16.0.0
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 14.0.1 to 16.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v14.0.1...v16.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-08 17:34:17 +01:00
dependabot-preview[bot]
59ab903a78 Bump @babel/cli from 7.7.5 to 7.8.4
Bumps [@babel/cli](https://github.com/babel/babel) from 7.7.5 to 7.8.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/compare/v7.7.5...v7.8.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-08 15:12:50 +01:00
Webber Takken
2fa5b33111 Update README.md 2020-02-01 21:24:33 +01:00
Webber
0399609b07 Give more info about what is different 2020-02-01 21:02:56 +01:00
Webber
1c91a3bf31 Fix custom parameters 2020-02-01 21:02:56 +01:00
Webber
ae7f659e9f Remove unneeded trailing slash 2020-02-01 20:43:49 +01:00
Webber
b781b891ec Align diff test with rename 2020-02-01 20:43:49 +01:00
Webber
f3a984165e Rename builder folder to action folder (unity actions convention) 2020-02-01 20:43:49 +01:00
Webber
d8896dc4f5 Update references 2020-01-27 23:15:26 +01:00
Webber
4051832dc0 Add some more basic tests 🤷‍♂️ 2020-01-27 23:15:26 +01:00
Webber
fe2311ef4b Hint enabling cache if not already enabled. 2020-01-27 23:15:26 +01:00
Webber
37d5ce498f Add more complete steps to create workflow 2020-01-27 23:15:26 +01:00
Webber
6bff9d7c68 Update readme for 0.9 (custom parameters) 2020-01-27 20:42:52 +01:00
Webber
7d51d12262 Allow custom parameters 2020-01-27 20:42:52 +01:00
Webber
b382ae9023 Remove duplicate restore key 2020-01-26 01:34:34 +01:00
Webber
4c8f96d75c Add caching step in workflow 2020-01-26 01:34:34 +01:00
Webber
afddcfa5fd Move static tests to main workflow 2020-01-26 01:34:34 +01:00
Webber
ca2bcea3ad Minor cleanup 2020-01-26 01:34:34 +01:00
Webber
d5552eaa01 Further simplify activation and complete feedback to user 2020-01-21 21:59:49 +01:00
Webber
32081adc59 Remove debugging, switch -ne to -eq 2020-01-21 21:59:49 +01:00
Webber
ad034dd2a5 Simplify and fail faster for activation process 2020-01-21 21:59:49 +01:00
Webber
cad4a8a0e5 Simplify build-method implementation 2020-01-21 21:59:49 +01:00
98 changed files with 4289 additions and 2670 deletions

View File

@@ -2,4 +2,4 @@
*
# Files required for the action
!builder/
!action/

View File

@@ -14,5 +14,8 @@ trim_trailing_whitespace = true
max_line_length = off
trim_trailing_whitespace = false
[*.{yml,yaml}]
max_line_length = off
[COMMIT_EDITMSG]
max_line_length = 0
max_line_length = off

View File

@@ -1,2 +1,2 @@
**/node_modules/**
**/builder/**
**/action/**

View File

@@ -6,8 +6,24 @@ on:
env:
UNITY_LICENSE: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>\n <License id=\"Terms\">\n <MachineBindings>\n <Binding Key=\"1\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n <Binding Key=\"2\" Value=\"d39b8e2f4d364b2e98b06afa0c6e08c5\"/>\n </MachineBindings>\n <MachineID Value=\"Xxo1ZKbdPu/IATrc0mPBYANJFF0=\"/>\n <SerialHash Value=\"1efd68fa935192b6090ac03c77d289a9f588c55a\"/>\n <Features>\n <Feature Value=\"33\"/>\n <Feature Value=\"1\"/>\n <Feature Value=\"12\"/>\n <Feature Value=\"2\"/>\n <Feature Value=\"24\"/>\n <Feature Value=\"3\"/>\n <Feature Value=\"36\"/>\n <Feature Value=\"17\"/>\n <Feature Value=\"19\"/>\n <Feature Value=\"62\"/>\n </Features>\n <DeveloperData Value=\"AQAAAEY0LUg2WFMtUE00NS1SM0M4LUUyWlotWkdWOA==\"/>\n <SerialMasked Value=\"F4-H6XS-PM45-R3C8-E2ZZ-XXXX\"/>\n <StartDate Value=\"2018-05-02T00:00:00\"/>\n <UpdateDate Value=\"2019-11-25T18:23:38\"/>\n <InitialActivationDate Value=\"2018-05-02T14:21:28\"/>\n <LicenseVersion Value=\"6.x\"/>\n <ClientProvidedVersion Value=\"2019.2.11f1\"/>\n <AlwaysOnline Value=\"false\"/>\n <Entitlements>\n <Entitlement Ns=\"unity_editor\" Tag=\"UnityPersonal\" Type=\"EDITOR\" ValidTo=\"9999-12-31T00:00:00\"/>\n </Entitlements>\n </License>\n<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"/><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/><Reference URI=\"#Terms\"><Transforms><Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/></Transforms><DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/><DigestValue>JHdOBFmBNq2H8BrGFzir/StLoYo=</DigestValue></Reference></SignedInfo><SignatureValue>aENLHd37a51RtP2/g7YU0Pexf5mx0/ENXYGtrPzqwZ8NQt2AsSdxGnl0CUB45/GuNXfJVDt2HWot\ncNYZB2OylVBn1WHQbKZlPmm8gEAMz0MYbr4Isb5i5buryBrZlmbEOjnRI+pEg1CBwlgMo6xdtjjE\n/d7cC293QIUO91kdzRXftYou1dNaUyuPL9ZH65vdB2pDXGRNxgUVD+GnnqZA7b5L2HXqNQclcWAK\n5Yd1BeF3VzR1iLw9G/SmH5oOhnpXSmqbL4qk7LVP2/mgXpFk5kP4X8VC3z47obNhBIGq40dwWyEe\nUYk5/nRAOkZawDT+tcu96e06gPC9Cxk5PdbRbA==</SignatureValue></Signature></root>"
CODECOV_TOKEN: '2f2eb890-30e2-4724-83eb-7633832cf0de'
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12.x
- run: yarn
- run: yarn lint
- run: yarn test --coverage
- run: bash <(curl -s https://codecov.io/bash)
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
- run: yarn build --quiet && git diff --quiet action || { echo "action should be auto generated" ; git diff action ; exit 62; }
buildForAllPlatforms:
name: Build for ${{ matrix.targetPlatform }} on version ${{ matrix.unityVersion }}
runs-on: ubuntu-latest
@@ -34,12 +50,22 @@ jobs:
# - Switch # Build a Nintendo Switch player.
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
lfs: true
- uses: actions/cache@v1.1.0
with:
path: ${{ matrix.projectPath }}/Library
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
restore-keys: |
Library-${{ matrix.projectPath }}-
Library-
- uses: ./
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
targetPlatform: ${{ matrix.targetPlatform }}
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
- uses: actions/upload-artifact@v1
with:
name: Build

View File

@@ -1,19 +0,0 @@
name: Test Action
on:
pull_request: {}
push: { branches: [master] }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12.x
- run: yarn
- run: yarn lint
- run: yarn test
- run: yarn build || { echo "build command should always succeed" ; exit 61; }
- run: yarn build --quiet && git diff --quiet builder || { echo "builder should be auto generated" ; exit 62; }

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
.idea
node_modules
coverage/

View File

@@ -1,2 +1,2 @@
**/node_modules/**
**/dist/**
**/action/**

198
README.md
View File

@@ -1,6 +1,9 @@
# Unity - Builder
[![Actions status](https://github.com/webbertakken/unity-builder/workflows/Actions%20%F0%9F%98%8E/badge.svg?event=push&branch=master)](https://github.com/webbertakken/unity-builder/actions?query=branch%3Amaster+event%3Apush+workflow%3A%22Actions+%F0%9F%98%8E%22)
[![snyk - known vulnerabilities](https://snyk.io/test/github/webbertakken/unity-builder/badge.svg)](https://snyk.io/test/github/webbertakken/unity-builder)
[![lgtm - code quality](https://img.shields.io/lgtm/grade/javascript/g/webbertakken/unity-builder.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/webbertakken/unity-builder/context:javascript)
[![codecov - test coverage](https://codecov.io/gh/webbertakken/unity-builder/branch/master/graph/badge.svg)](https://codecov.io/gh/webbertakken/unity-builder)
---
@@ -31,10 +34,24 @@ collection repository for workflow documentation and reference implementation.
## Usage
#### Setup builder
By default the enabled scenes from the project's settings will be built.
Create or edit the file called `.github/workflows/main.yml` and add a job to it.
##### Personal License
Personal licenses require a one-time manual activation step (per unity version).
Make sure you
[acquire and activate](https://github.com/marketplace/actions/unity-request-activation-file)
your license file and add it as a secret.
Then, define the build step as follows:
```yaml
- uses: webbertakken/unity-builder@v0.5
- uses: webbertakken/unity-builder@v0.11
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
with:
@@ -43,6 +60,75 @@ Create or edit the file called `.github/workflows/main.yml` and add a job to it.
targetPlatform: WebGL
```
##### Professional license
Professional licenses do not need any manual steps.
Instead, three variables will need to be set.
- `UNITY_EMAIL` (should contain the email address for your Unity account)
- `UNITY_PASSWORD` (the password that you use to login to Unity)
- `UNITY_SERIAL` (the serial provided by Unity)
Define the build step as follows:
```yaml
- uses: webbertakken/unity-builder@v0.11
env:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
with:
projectPath: path/to/your/project
unityVersion: 2020.X.XXXX
targetPlatform: WebGL
```
That is all you need to build your project.
#### Storing the build
To be able to access your built files,
they need to be uploaded as artifacts.
To do this it is recommended to use Github Actions official
[upload artifact action](https://github.com/marketplace/actions/upload-artifact)
after any build action.
By default, Builder outputs it's builds to a folder named `build`.
Example:
```yaml
- uses: actions/upload-artifact@v1
with:
name: Build
path: build
```
Builds can now be downloaded as Artifacts in the Actions tab.
#### Caching
In order to make builds run faster, you can cache Library files from previous
builds. To do so simply add Github Actions official
[cache action](https://github.com/marketplace/actions/cache) before any unity steps.
Example:
```yaml
- uses: actions/cache@v1.1.0
with:
path: path/to/your/project/Library
key: Library-MyProjectName-TargetPlatform
restore-keys: |
Library-MyProjectName-
Library-
```
This simple addition could speed up your build by more than 50%.
## Complete example
A complete workflow that builds every available platform could look like this:
```yaml
@@ -81,8 +167,17 @@ jobs:
- tvOS # Build to Apple's tvOS platform.
- Switch # Build a Nintendo Switch player.
steps:
- uses: actions/checkout@v1
- uses: webbertakken/unity-builder@v0.5
- uses: actions/checkout@v2
with:
lfs: true
- uses: actions/cache@v1.1.0
with:
path: ${{ matrix.projectPath }}/Library
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}
restore-keys: |
Library-${{ matrix.projectPath }}-
Library-
- uses: webbertakken/unity-builder@v0.11
with:
projectPath: ${{ matrix.projectPath }}
unityVersion: ${{ matrix.unityVersion }}
@@ -93,10 +188,7 @@ jobs:
path: build
```
> **Notes:**
>
> - Don't forget to replace _&lt;test-project&gt;_ with your project name.
> - By default the enabled scenes from the project's settings will be built.
> **Note:** _Environment variables are set for all jobs in the workflow like this._
## Configuration options
@@ -153,7 +245,7 @@ There are two conditions for a custom buildCommand:
_**example:**_
```yaml
- uses: webbertakken/unity-builder@master
- uses: webbertakken/unity-builder@<version>
with:
buildMethod: EditorNamespace.BuilderClassName.StaticBulidMethod
```
@@ -161,6 +253,96 @@ _**example:**_
_**required:** `false`_
_**default:** Built-in script that will run a build out of the box._
#### versioning
The versioning strategy to use.
Strategies only work when no custom buildMethod is specified.
_**required:** `false`_
_**default:** `Auto`_
#### _These are the available strategies:_
##### None
No version will be set by Builder.
```yaml
- uses: webbertakken/unity-builder@<version>
with:
versioning: None
```
Note that the version set in the project will be used instead.
##### Semantic (default)
Builder automatically generates a version based on [semantic versioning](https://semver.org/) out of the box.
The version works as follows: `<major>.<minor>.<patch>` for example `0.1.2`.
The latest tag dictates `<major>.<minor>` and the number of commits since that tag is used in `<patch>`.
```yaml
- uses: webbertakken/unity-builder@<version>
with:
versioning: Semantic
```
This strategy works well for the following reasons:
- All builds have their unique version
- No version related commits are created
- No knowledge of git or versioning is required
- Developer keeps control over `major` and `minor` versions using tags.
- Zero configuration; It works out of the box
##### Tag
Uses the tag that points at `HEAD` as the version.
```yaml
- uses: webbertakken/unity-builder@<version>
with:
versioning: Tag
```
This strategy works well when using a pipeline that specifically runs for tags.
The tag must be a version tag.
##### Custom
Allows specifying a custom version in the `version` field.
```yaml
- uses: webbertakken/unity-builder@<version>
with:
versioning: Custom
version: <some_version>
```
If there is a use case missing from Builder, feel free to create a feature request.
#### customParameters
Custom parameters to configure the build.
Parameters must start with a hyphen (`-`) and may be followed by a value (without hyphen).
Parameters without a value will be considered booleans (with a value of true).
_**example:**_
```yaml
- uses: webbertakken/unity-builder@<version>
with:
customParameters: -profile SomeProfile -someBoolean -someValue exampleValue
```
_**required:** `false`_
_**default:** ""_
## More actions
Visit

View File

@@ -32,4 +32,4 @@ branding:
color: 'gray-dark'
runs:
using: 'node12'
main: 'builder/index.js'
main: 'action/index.js'

View File

@@ -0,0 +1,4 @@
root = true
[*.cs]
resharper_check_namespace_highlighting = do_not_show

View File

@@ -57,6 +57,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Assets\Editor\Builder.cs" />
<Compile Include="Assets\Editor\Input\ArgumentsParser.cs" />
<Compile Include="Assets\Editor\Reporting\StdOutReporter.cs" />
<Compile Include="Assets\Editor\System\ProcessExtensions.cs" />
<Compile Include="Assets\Editor\Versioning\VersionApplicator.cs" />
<Compile Include="Assets\Editor\Versioning\Git.cs" />
<Compile Include="Assets\Editor\Versioning\VersionGenerator.cs" />
<Compile Include="Assets\Editor\Versioning\GitException.cs" />
<Reference Include="UnityEditor.TestRunner">
<HintPath>C:/Repositories/unity-builder/builder/default-build-script/Library/ScriptAssemblies/UnityEditor.TestRunner.dll</HintPath>
</Reference>
@@ -688,6 +695,9 @@
<HintPath>C:/Program Files/Unity/2019.2.11f1/Editor/Data/MonoBleedingEdge/lib/mono/unityscript/Boo.Lang.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include=".editorconfig" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityBuilderAction.Input;
using UnityBuilderAction.Reporting;
using UnityBuilderAction.Versioning;
using UnityEditor;
using UnityEditor.Build.Reporting;
namespace UnityBuilderAction
{
static class Builder
{
public static void BuildProject()
{
// Gather values from args
var options = ArgumentsParser.GetValidatedOptions();
// Gather values from project
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
// Define BuildPlayer Options
var buildOptions = new BuildPlayerOptions {
scenes = scenes,
locationPathName = options["customBuildPath"],
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
};
// Set version for this build
VersionApplicator.SetVersion(options["version"]);
// Perform build
BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions);
// Summary
BuildSummary summary = buildReport.summary;
StdOutReporter.ReportSummary(summary);
// Result
BuildResult result = summary.result;
StdOutReporter.ExitWithResult(result);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b6e5ef18d769419d887b56665969442b
timeCreated: 1587503329

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using UnityEditor;
namespace UnityBuilderAction.Input
{
public class ArgumentsParser
{
static string EOL = Environment.NewLine;
public static Dictionary<string, string> GetValidatedOptions()
{
ParseCommandLineArguments(out var validatedOptions);
if (!validatedOptions.TryGetValue("projectPath", out var projectPath)) {
Console.WriteLine("Missing argument -projectPath");
EditorApplication.Exit(110);
}
if (!validatedOptions.TryGetValue("buildTarget", out var buildTarget)) {
Console.WriteLine("Missing argument -buildTarget");
EditorApplication.Exit(120);
}
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
EditorApplication.Exit(121);
}
if (!validatedOptions.TryGetValue("customBuildPath", out var customBuildPath)) {
Console.WriteLine("Missing argument -customBuildPath");
EditorApplication.Exit(130);
}
const string defaultCustomBuildName = "TestBuild";
if (!validatedOptions.TryGetValue("customBuildName", out var customBuildName)) {
Console.WriteLine($"Missing argument -customBuildName, defaulting to {defaultCustomBuildName}.");
validatedOptions.Add("customBuildName", defaultCustomBuildName);
} else if (customBuildName == "") {
Console.WriteLine($"Invalid argument -customBuildName, defaulting to {defaultCustomBuildName}.");
validatedOptions.Add("customBuildName", defaultCustomBuildName);
}
return validatedOptions;
}
static void ParseCommandLineArguments(out Dictionary<string, string> providedArguments)
{
providedArguments = new Dictionary<string, string>();
string[] args = Environment.GetCommandLineArgs();
Console.WriteLine(
$"{EOL}" +
$"###########################{EOL}" +
$"# Parsing settings #{EOL}" +
$"###########################{EOL}" +
$"{EOL}"
);
// Extract flags with optional values
for (int current = 0, next = 1; current < args.Length; current++, next++) {
// Parse flag
bool isFlag = args[current].StartsWith("-");
if (!isFlag) continue;
string flag = args[current].TrimStart('-');
// Parse optional value
bool flagHasValue = next < args.Length && !args[next].StartsWith("-");
string value = flagHasValue ? args[next].TrimStart('-') : "";
// Assign
Console.WriteLine($"Found flag \"{flag}\" with value \"{value}\".");
providedArguments.Add(flag, value);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 46d2ec4a86604575be2b2d02b0df7b74
timeCreated: 1587503354

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 166f919334c44e7a80ae916667974e7d
timeCreated: 1587503566

View File

@@ -0,0 +1,50 @@
using System;
using UnityEditor;
using UnityEditor.Build.Reporting;
namespace UnityBuilderAction.Reporting
{
public class StdOutReporter
{
static string EOL = Environment.NewLine;
public static void ReportSummary(BuildSummary summary)
{
Console.WriteLine(
$"{EOL}" +
$"###########################{EOL}" +
$"# Build results #{EOL}" +
$"###########################{EOL}" +
$"{EOL}" +
$"Duration: {summary.totalTime.ToString()}{EOL}" +
$"Warnings: {summary.totalWarnings.ToString()}{EOL}" +
$"Errors: {summary.totalErrors.ToString()}{EOL}" +
$"Size: {summary.totalSize.ToString()} bytes{EOL}" +
$"{EOL}"
);
}
public static void ExitWithResult(BuildResult result)
{
if (result == BuildResult.Succeeded) {
Console.WriteLine("Build succeeded!");
EditorApplication.Exit(0);
}
if (result == BuildResult.Failed) {
Console.WriteLine("Build failed!");
EditorApplication.Exit(101);
}
if (result == BuildResult.Cancelled) {
Console.WriteLine("Build cancelled!");
EditorApplication.Exit(102);
}
if (result == BuildResult.Unknown) {
Console.WriteLine("Build result is unknown!");
EditorApplication.Exit(103);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e59b491a4124442ea7277f76761cdc8a
timeCreated: 1587503545

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b5da3bd7e18c43d79243410166c8dc9a
timeCreated: 1587493708

View File

@@ -0,0 +1,42 @@
using System.Diagnostics;
using System.Text;
public static class ProcessExtensions
{
// Execute an application or binary with given arguments
//
// See: https://stackoverflow.com/questions/4291912/process-start-how-to-get-the-output
public static int Run(this Process process, string application,
string arguments, string workingDirectory, out string output,
out string errors)
{
// Configure how to run the application
process.StartInfo = new ProcessStartInfo {
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = application,
Arguments = arguments,
WorkingDirectory = workingDirectory
};
// Read the output
var outputBuilder = new StringBuilder();
var errorsBuilder = new StringBuilder();
process.OutputDataReceived += (_, args) => outputBuilder.AppendLine(args.Data);
process.ErrorDataReceived += (_, args) => errorsBuilder.AppendLine(args.Data);
// Run the application and wait for it to complete
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
// Format the output
output = outputBuilder.ToString().TrimEnd();
errors = errorsBuilder.ToString().TrimEnd();
return process.ExitCode;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 29c1880a390c4af7be821b7877602815
timeCreated: 1587494270

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1c3bddf6d8984cde9208e3f0fe584879
timeCreated: 1587490700

View File

@@ -0,0 +1,116 @@
using System;
using UnityEngine;
namespace UnityBuilderAction.Versioning
{
public static class Git
{
const string application = @"git";
/// <summary>
/// Generate a version based on the latest tag and the amount of commits.
/// Format: 0.1.2 (where 2 is the amount of commits).
///
/// If no tag is present in the repository then v0.0 is assumed.
/// This would result in 0.0.# where # is the amount of commits.
/// </summary>
public static string GenerateSemanticCommitVersion()
{
string version;
if (HasAnyVersionTags()) {
version = GetSemanticCommitVersion();
Console.WriteLine("Repository has a valid version tag.");
} else {
version = $"0.0.{GetTotalNumberOfCommits()}";
Console.WriteLine("Repository does not have tags to base the version on.");
}
Console.WriteLine($"Version is {version}");
return version;
}
/// <summary>
/// Get the version of the current tag.
///
/// The tag must point at HEAD for this method to work.
///
/// Output Format:
/// #.* (where # is the major version and * can be any number of any type of character)
/// </summary>
public static string GetTagVersion()
{
string version = Run(@"tag --points-at HEAD | grep v[0-9]*");
version = version.Substring(1);
return version;
}
/// <summary>
/// Get the total number of commits.
/// </summary>
static int GetTotalNumberOfCommits()
{
string numberOfCommitsAsString = Run(@"git rev-list --count HEAD");
return int.Parse(numberOfCommitsAsString);
}
/// <summary>
/// Whether or not the repository has any version tags yet.
/// </summary>
static bool HasAnyVersionTags()
{
return "0" != Run(@"tag --list --merged HEAD | grep v[0-9]* | wc -l");
}
/// <summary>
/// Retrieves the build version from git based on the most recent matching tag and
/// commit history. This returns the version as: {major.minor.build} where 'build'
/// represents the nth commit after the tagged commit.
/// Note: The initial 'v' and the commit hash are removed.
/// </summary>
static string GetSemanticCommitVersion()
{
// v0.1-2-g12345678 (where 2 is the amount of commits, g stands for git)
string version = GetVersionString();
// 0.1-2
version = version.Substring(1, version.LastIndexOf('-') - 1);
// 0.1.2
version = version.Replace('-', '.');
return version;
}
/// <summary>
/// Get version string.
///
/// Format: `v0.1-2-g12345678` (where 2 is the amount of commits since the last tag)
///
/// See: https://softwareengineering.stackexchange.com/questions/141973/how-do-you-achieve-a-numeric-versioning-scheme-with-git
/// </summary>
static string GetVersionString()
{
return Run(@"describe --tags --long --match ""v[0-9]*""");
// Todo - implement split function based on this more complete query
// return Run(@"describe --long --tags --dirty --always");
}
/// <summary>
/// Runs git binary with any given arguments and returns the output.
/// </summary>
static string Run(string arguments)
{
using (var process = new System.Diagnostics.Process()) {
string workingDirectory = Application.dataPath;
int exitCode = process.Run(application, arguments, workingDirectory, out string output, out string errors);
if (exitCode != 0) { throw new GitException(exitCode, errors); }
return output;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cdec7fa0f5bb44958fdf74d4658a4601
timeCreated: 1587495075

View File

@@ -0,0 +1,14 @@
using System;
namespace UnityBuilderAction.Versioning
{
public class GitException : InvalidOperationException
{
public readonly int code;
public GitException(int code, string errors) : base(errors)
{
this.code = code;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4d375e209fd14fc5bc2f3dc3c78ac574
timeCreated: 1587490750

View File

@@ -0,0 +1,23 @@
using System;
using JetBrains.Annotations;
using UnityEditor;
namespace UnityBuilderAction.Versioning
{
public class VersionApplicator
{
public static void SetVersion(string version)
{
if (version == "none") {
return;
}
Apply(version);
}
static void Apply(string version)
{
PlayerSettings.bundleVersion = version;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 30483367ddc84699a0da377ccb93769a
timeCreated: 1587504315

View File

@@ -0,0 +1,10 @@
namespace UnityBuilderAction.Versioning
{
public static class VersionGenerator
{
public static string Generate()
{
return Git.GenerateSemanticCommitVersion();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9892e03ae8314b7eacd793c8002de007
timeCreated: 1587490842

View File

@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Untracked/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Versioning/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

1
action/index.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,29 +1,29 @@
#!/usr/bin/env bash
if [[ -n "$UNITY_LICENSE" ]]; then
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 2019.
# Note that this is the ONLY WAY for PERSONAL LICENSES in 2020.
# * See for more details: https://gitlab.com/gableroux/unity3d-gitlab-ci-example/issues/5#note_72815478
#
# The license file can be acquired using `webbertakken/request-manual-activation-file` action.
LICENSE_MODE="personal"
echo "Requesting activation (personal license)"
# Set the license file path
FILE_PATH=UnityLicenseFile.ulf
# Copy license file from Github variables
echo "$UNITY_LICENSE" | tr -d '\r' > $FILE_PATH
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
#
# This is expected to always exit with code 1 (both success and failure).
#
echo "Requesting activation"
ACTIVATION_OUTPUT=$(xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
@@ -31,17 +31,23 @@ if [[ -n "$UNITY_LICENSE" ]]; then
-logFile /dev/stdout \
-quit \
-manualLicenseFile $FILE_PATH)
# Convert to exit code 0 by echoing the current exit code.
echo $?
# Exit code is now 0
# TODO - remove debugging
echo $ACTIVATION_OUTPUT
echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default'
echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default' | wc -l
# Store the exit code from the verify command
UNITY_EXIT_CODE=$?
# TODO - Derive exit code by grepping success statement
UNITY_EXIT_CODE=$(echo $ACTIVATION_OUTPUT | grep 'config is NOT valid, switching to default' | wc -l)
# 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
@@ -54,8 +60,9 @@ elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
#
# Note: This is the preferred way for PROFESSIONAL LICENSES.
#
LICENSE_MODE="professional"
echo "Requesting activation (professional license)"
# Activate license
xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
/opt/Unity/Editor/Unity \
-batchmode \
@@ -71,16 +78,18 @@ elif [[ -n "$UNITY_SERIAL" && -n "$UNITY_EMAIL" && -n "$UNITY_PASSWORD" ]]; then
else
#
# LICENSE ACTIVATION FAILED
# NO LICENSE ACTIVATION STRATEGY MATCHED
#
# This will exit since both personal and professional activation modes failed
# This will exit since no activation strategies could be matched.
#
echo "No personal or professional licenses provided!"
echo "Please ensure you have setup one of these licensing methods:"
echo " - Personal: Set the UNITY_LICENSE environment variable."
echo " - Professional: Set the UNITY_EMAIL, UNITY_PASSWORD and UNITY_SERIAL environment variables."
echo "See https://github.com/webbertakken/unity-builder#usage for details."
echo "License activation strategy could not be determined."
echo ""
echo "Visit https://github.com/webbertakken/unity-builder#usage for more"
echo "details on how to set up one of the possible activation strategies."
# Immediately exit as no UNITY_EXIT_CODE can be derrived.
exit 1;
fi
#
@@ -88,10 +97,10 @@ fi
#
if [ $UNITY_EXIT_CODE -eq 0 ]; then
# Activation was a success
echo "Activation ($LICENSE_MODE) complete."
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_MODE) license."
echo "Unclassified error occured while trying to activate license."
echo "Exit code was: $UNITY_EXIT_CODE"
exit $UNITY_EXIT_CODE
fi

View File

@@ -58,13 +58,14 @@ else
# User has provided their own build method.
# Assume they also bring their own script.
#
echo "User set build method to $BUILD_METHOD."
echo "Using build method \"$BUILD_METHOD\"."
#
fi
# Set build method to execute as flag + argument
EXECUTE_BUILD_METHOD="-executeMethod $BUILD_METHOD"
#
# Display custom parameters
#
echo "Using custom parameters $CUSTOM_PARAMETERS."
# The build specification below may require Unity 2019.2.11f1 or later (not tested below).
# Reference: https://docs.unity3d.com/2019.3/Documentation/Manual/CommandLineArguments.html
@@ -107,7 +108,10 @@ xvfb-run --auto-servernum --server-args='-screen 0 640x480x24' \
-buildTarget "$BUILD_TARGET" \
-customBuildTarget "$BUILD_TARGET" \
-customBuildPath "$CUSTOM_BUILD_PATH" \
$EXECUTE_BUILD_METHOD
-executeMethod "$BUILD_METHOD" \
-versioning "$VERSIONING" \
-version "$VERSION" \
$CUSTOM_PARAMETERS
# Catch exit code
BUILD_EXIT_CODE=$?

View File

@@ -1,147 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;
namespace UnityBuilderAction
{
static class Builder
{
private static string EOL = Environment.NewLine;
private static void ParseCommandLineArguments(out Dictionary<string, string> providedArguments)
{
providedArguments = new Dictionary<string, string>();
string[] args = Environment.GetCommandLineArgs();
Console.WriteLine(
$"{EOL}" +
$"###########################{EOL}" +
$"# Parsing settings #{EOL}" +
$"###########################{EOL}" +
$"{EOL}"
);
// Extract flags with optional values
for (int current = 0, next = 1; current < args.Length; current++, next++) {
// Parse flag
bool isFlag = args[current].StartsWith("-");
if (!isFlag) continue;
string flag = args[current].TrimStart('-');
// Parse optional value
bool flagHasValue = next < args.Length && !args[next].StartsWith("-");
string value = flagHasValue ? args[next].TrimStart('-') : "";
// Assign
Console.WriteLine($"Found flag \"{flag}\" with value \"{value}\".");
providedArguments.Add(flag, value);
}
}
private static Dictionary<string, string> GetValidatedOptions()
{
ParseCommandLineArguments(out var validatedOptions);
if (!validatedOptions.TryGetValue("projectPath", out var projectPath)) {
Console.WriteLine("Missing argument -projectPath");
EditorApplication.Exit(110);
}
if (!validatedOptions.TryGetValue("buildTarget", out var buildTarget)) {
Console.WriteLine("Missing argument -buildTarget");
EditorApplication.Exit(120);
}
if (!Enum.IsDefined(typeof(BuildTarget), buildTarget)) {
EditorApplication.Exit(121);
}
if (!validatedOptions.TryGetValue("customBuildPath", out var customBuildPath)) {
Console.WriteLine("Missing argument -customBuildPath");
EditorApplication.Exit(130);
}
string defaultCustomBuildName = "TestBuild";
if (!validatedOptions.TryGetValue("customBuildName", out var customBuildName)) {
Console.WriteLine($"Missing argument -customBuildName, defaulting to {defaultCustomBuildName}.");
validatedOptions.Add("customBuildName", defaultCustomBuildName);
}
else if (customBuildName == "") {
Console.WriteLine($"Invalid argument -customBuildName, defaulting to {defaultCustomBuildName}.");
validatedOptions.Add("customBuildName", defaultCustomBuildName);
}
return validatedOptions;
}
public static void BuildProject()
{
// Gather values from args
var options = GetValidatedOptions();
// Gather values from project
var scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(s => s.path).ToArray();
// Define BuildPlayer Options
var buildOptions = new BuildPlayerOptions {
scenes = scenes,
locationPathName = options["customBuildPath"],
target = (BuildTarget) Enum.Parse(typeof(BuildTarget), options["buildTarget"]),
};
// Perform build
BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions);
// Summary
BuildSummary summary = buildReport.summary;
ReportSummary(summary);
// Result
BuildResult result = summary.result;
ExitWithResult(result);
}
private static void ReportSummary(BuildSummary summary)
{
Console.WriteLine(
$"{EOL}" +
$"###########################{EOL}" +
$"# Build results #{EOL}" +
$"###########################{EOL}" +
$"{EOL}" +
$"Duration: {summary.totalTime.ToString()}{EOL}" +
$"Warnings: {summary.totalWarnings.ToString()}{EOL}" +
$"Errors: {summary.totalErrors.ToString()}{EOL}" +
$"Size: {summary.totalSize.ToString()} bytes{EOL}" +
$"{EOL}"
);
}
private static void ExitWithResult(BuildResult result)
{
if (result == BuildResult.Succeeded) {
Console.WriteLine("Build succeeded!");
EditorApplication.Exit(0);
}
if (result == BuildResult.Failed) {
Console.WriteLine("Build failed!");
EditorApplication.Exit(101);
}
if (result == BuildResult.Cancelled) {
Console.WriteLine("Build cancelled!");
EditorApplication.Exit(102);
}
if (result == BuildResult.Unknown) {
Console.WriteLine("Build result is unknown!");
EditorApplication.Exit(103);
}
}
}
}

File diff suppressed because one or more lines are too long

39
codecov.yml Normal file
View File

@@ -0,0 +1,39 @@
codecov:
require_ci_to_pass: yes
coverage:
precision: 2
round: down
range: '70...100'
status:
patch:
default:
# basic
target: auto
threshold: 100% # don't require patch to have coverage per se
base: auto
project:
default:
# basic
target: auto
threshold: 5%
base: auto
flags:
- unit
paths:
- 'src'
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: 'reach,diff,flags,tree'
behavior: default
require_changes: no

View File

@@ -5,4 +5,5 @@ module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: { '^.+\\.(js|jsx)?$': 'babel-jest' },
transformIgnorePatterns: [`/node_modules/(?!${esModules})`],
setupFilesAfterEnv: ['./src/jest.setup.js'],
};

View File

@@ -2,44 +2,45 @@
"name": "unity-builder",
"version": "0.5.0",
"description": "Build Unity projects for different platforms.",
"main": "builder/index.js",
"main": "action/index.js",
"repository": "git@github.com:webbertakken/unity-builder.git",
"author": "Webber <webber@takken.io>",
"license": "MIT",
"scripts": {
"build": "ncc build src --out builder --minify",
"prebuild": "yarn",
"build": "ncc build src --out action --minify",
"lint": "prettier --check \"src/**/*.js\" && eslint src",
"test": "jest"
},
"dependencies": {
"@actions/core": "^1.2.0",
"@actions/exec": "1.0.2",
"@actions/github": "^2.0.0"
"@actions/core": "^1.2.4",
"@actions/exec": "1.0.4",
"@actions/github": "^2.1.1"
},
"devDependencies": {
"@babel/cli": "7.7.5",
"@babel/core": "7.7.5",
"@babel/preset-env": "7.7.7",
"@zeit/ncc": "0.20.5",
"babel-eslint": "10.0.3",
"eslint": "6.7.2",
"eslint-config-airbnb": "18.0.1",
"eslint-config-prettier": "6.7.0",
"eslint-plugin-flowtype": "4.5.2",
"eslint-plugin-import": "2.19.1",
"@babel/cli": "7.8.4",
"@babel/core": "7.9.6",
"@babel/preset-env": "7.9.6",
"@zeit/ncc": "0.22.1",
"babel-eslint": "10.1.0",
"eslint": "6.8.0",
"eslint-config-airbnb": "18.1.0",
"eslint-config-prettier": "6.11.0",
"eslint-plugin-flowtype": "4.7.0",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-prettier": "3.1.2",
"eslint-plugin-react": "7.17.0",
"eslint-plugin-unicorn": "14.0.1",
"husky": "4.0.0-beta.5",
"jest": "24.9.0",
"lint-staged": "9.5.0",
"eslint-plugin-prettier": "3.1.3",
"eslint-plugin-react": "7.19.0",
"eslint-plugin-unicorn": "19.0.1",
"husky": "4.2.5",
"jest": "25.5.3",
"lint-staged": "10.2.2",
"lodash-es": "4.17.15",
"prettier": "1.19.1"
"prettier": "2.0.5"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged && yarn build && git add builder/index.js"
"pre-commit": "lint-staged && yarn build && git add action/index.js"
}
},
"lint-staged": {

View File

@@ -1,25 +1,22 @@
import Action from './model/action';
import Docker from './model/docker';
import ImageTag from './model/image-tag';
import Input from './model/input';
import BuildParameters from './model/build-parameters';
import { Action, BuildParameters, Cache, Docker, Input, ImageTag } from './model';
const core = require('@actions/core');
async function action() {
Action.checkCompatibility();
Cache.verify();
const { dockerfile, workspace, builderFolder } = Action;
const buildParameters = BuildParameters.create(Input.getFromUser());
const { dockerfile, workspace, actionFolder } = Action;
const buildParameters = BuildParameters.create(await Input.getFromUser());
const baseImage = new ImageTag(buildParameters);
// Build docker image
const builtImage = await Docker.build({ path: builderFolder, dockerfile, baseImage });
const builtImage = await Docker.build({ path: actionFolder, dockerfile, baseImage });
// Run docker image
await Docker.run(builtImage, { workspace, ...buildParameters });
}
action().catch(error => {
action().catch((error) => {
core.setFailed(error.message);
});

49
src/jest.setup.js Normal file
View File

@@ -0,0 +1,49 @@
expect.extend({
toBeOfType(received, expectedType) {
const type = typeof received;
const pass = type === expectedType;
const message = () => `
Expected value to be of type ${this.utils.printExpected(expectedType)},
but received ${this.utils.printReceived(type)}`;
return {
message,
pass,
};
},
toBeEitherAFunctionOrAnObject(received) {
const type = typeof received;
const pass = ['object', 'function'].includes(type);
const message = () => `Expected a ${this.utils.printExpected('function')}
or an ${this.utils.printExpected('object')},
but received ${type}`;
return {
message,
pass,
};
},
toBeParsableToANumber(received) {
let pass = false;
let errorMessage = '';
try {
Number.parseInt(received, 10);
pass = true;
} catch (error) {
errorMessage = error;
}
const message = () => `Expected ${this.utils.printExpected(received)} to be parsable as a number
, but received error: ${this.utils.printReceived(errorMessage)}.`;
return {
message,
pass,
};
},
});

View File

@@ -0,0 +1,17 @@
// Import this named export into your test file:
import Platform from '../platform';
export const mockGetFromUser = jest.fn().mockResolvedValue({
version: '',
targetPlatform: Platform.types.Test,
projectPath: '.',
buildName: Platform.types.Test,
buildsPath: 'build',
buildMethod: undefined,
buildVersion: '1.3.37',
customParameters: '',
});
export default {
getFromUser: mockGetFromUser,
};

View File

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

View File

@@ -25,12 +25,12 @@ class Action {
return path.dirname(path.dirname(__filename));
}
static get builderFolder() {
return `${Action.rootFolder}/builder`;
static get actionFolder() {
return `${Action.rootFolder}/action`;
}
static get dockerfile() {
return `${Action.builderFolder}/Dockerfile`;
return `${Action.actionFolder}/Dockerfile`;
}
static get workspace() {

View File

@@ -20,11 +20,11 @@ describe('Action', () => {
expect(fs.existsSync(rootFolder)).toStrictEqual(true);
});
it('returns the builder folder', () => {
const { builderFolder } = Action;
it('returns the action folder', () => {
const { actionFolder } = Action;
expect(path.basename(builderFolder)).toStrictEqual('builder');
expect(fs.existsSync(builderFolder)).toStrictEqual(true);
expect(path.basename(actionFolder)).toStrictEqual('action');
expect(fs.existsSync(actionFolder)).toStrictEqual(true);
});
it('returns the docker file', () => {

View File

@@ -3,22 +3,26 @@ import Platform from './platform';
class BuildParameters {
static create(parameters) {
const {
unityVersion,
version,
targetPlatform,
projectPath,
buildName,
buildsPath,
buildMethod,
buildVersion,
customParameters,
} = parameters;
return {
version: unityVersion,
version,
platform: targetPlatform,
projectPath,
buildName,
buildPath: `${buildsPath}/${targetPlatform}`,
buildFile: this.parseBuildFile(buildName, targetPlatform),
buildMethod,
buildVersion,
customParameters,
};
}

View File

@@ -0,0 +1,83 @@
import BuildParameters from './build-parameters';
import Platform from './platform';
describe('BuildParameters', () => {
describe('create', () => {
const someParameters = {
version: 'someVersion',
targetPlatform: 'somePlatform',
projectPath: 'path/to/project',
buildName: 'someBuildName',
buildsPath: 'someBuildsPath',
buildMethod: 'Namespace.Class.Method',
customParameters: '-someParam someValue',
};
it('does not throw', () => {
expect(() => BuildParameters.create(someParameters)).not.toThrow();
});
it('returns the version', () => {
expect(BuildParameters.create(someParameters).version).toStrictEqual(someParameters.version);
});
it('returns the platform', () => {
expect(BuildParameters.create(someParameters).platform).toStrictEqual(
someParameters.targetPlatform,
);
});
it('returns the project path', () => {
expect(BuildParameters.create(someParameters).projectPath).toStrictEqual(
someParameters.projectPath,
);
});
it('returns the build name', () => {
expect(BuildParameters.create(someParameters).buildName).toStrictEqual(
someParameters.buildName,
);
});
it('returns the build path', () => {
expect(BuildParameters.create(someParameters).buildPath).toStrictEqual(
`${someParameters.buildsPath}/${someParameters.targetPlatform}`,
);
});
describe('build file', () => {
it('returns the build file', () => {
expect(BuildParameters.create(someParameters).buildFile).toStrictEqual(
someParameters.buildName,
);
});
test.each([Platform.types.StandaloneWindows, Platform.types.StandaloneWindows64])(
'appends exe for %s',
(targetPlatform) => {
expect(
BuildParameters.create({ ...someParameters, targetPlatform }).buildFile,
).toStrictEqual(`${someParameters.buildName}.exe`);
},
);
test.each([Platform.types.Android])('appends apk for %s', (targetPlatform) => {
expect(
BuildParameters.create({ ...someParameters, targetPlatform }).buildFile,
).toStrictEqual(`${someParameters.buildName}.apk`);
});
});
it('returns the build method', () => {
expect(BuildParameters.create(someParameters).buildMethod).toStrictEqual(
someParameters.buildMethod,
);
});
it('returns the custom parameters', () => {
expect(BuildParameters.create(someParameters).customParameters).toStrictEqual(
someParameters.customParameters,
);
});
});
});

25
src/model/cache.js Normal file
View File

@@ -0,0 +1,25 @@
import fs from 'fs';
import Action from './action';
import Project from './project';
class Cache {
static verify() {
if (!fs.existsSync(Project.libraryFolder)) {
this.notifyAboutCachingPossibility();
}
}
static notifyAboutCachingPossibility() {
if (Action.isRunningLocally) {
return;
}
// eslint-disable-next-line no-console
console.log(`
Library folder does not exist.
Consider setting up caching to speed up your workflow
If this is not your first build.`);
}
}
export default Cache;

11
src/model/cache.test.js Normal file
View File

@@ -0,0 +1,11 @@
import Cache from './cache';
jest.mock('./input');
describe('Cache', () => {
describe('Verification', () => {
it('does not throw', () => {
expect(() => Cache.verify()).not.toThrow();
});
});
});

View File

@@ -12,7 +12,7 @@ class Docker {
--build-arg IMAGE=${baseImage} \
--tag ${tag}`;
await exec(command, null, { silent });
await exec(command, undefined, { silent });
return tag;
}
@@ -27,22 +27,27 @@ class Docker {
buildPath,
buildFile,
buildMethod,
buildVersion,
customParameters,
} = parameters;
const command = `docker run \
--workdir /github/workspace \
--rm \
--env UNITY_LICENSE \
--env UNITY_LICENSE_FILE \
--env UNITY_EMAIL \
--env UNITY_PASSWORD \
--env UNITY_SERIAL \
--env UNITY_VERSION=${version} \
--env PROJECT_PATH=${projectPath} \
--env BUILD_TARGET=${platform} \
--env BUILD_NAME=${buildName} \
--env BUILD_PATH=${buildPath} \
--env BUILD_FILE=${buildFile} \
--env BUILD_METHOD=${buildMethod} \
--env UNITY_VERSION="${version}" \
--env PROJECT_PATH="${projectPath}" \
--env BUILD_TARGET="${platform}" \
--env BUILD_NAME="${buildName}" \
--env BUILD_PATH="${buildPath}" \
--env BUILD_FILE="${buildFile}" \
--env BUILD_METHOD="${buildMethod}" \
--env VERSION="${buildVersion}" \
--env CUSTOM_PARAMETERS="${customParameters}" \
--env HOME=/github/home \
--env GITHUB_REF \
--env GITHUB_SHA \
@@ -65,7 +70,7 @@ class Docker {
--volume "${workspace}":"/github/workspace" \
${image}`;
await exec(command, null, { silent });
await exec(command, undefined, { silent });
}
}

View File

@@ -4,7 +4,7 @@ import ImageTag from './image-tag';
describe('Docker', () => {
it('builds', async () => {
const path = Action.builderFolder;
const path = Action.actionFolder;
const dockerfile = `${path}/Dockerfile`;
const baseImage = new ImageTag({
repository: '',

View File

@@ -0,0 +1,8 @@
class CommandExecutionError extends Error {
constructor(message) {
super(message);
this.name = 'CommandExecutionError';
}
}
export default CommandExecutionError;

View File

@@ -0,0 +1,14 @@
import CommandExecutionError from './command-execution-error';
describe('CommandExecutionError', () => {
it('instantiates', () => {
expect(() => new CommandExecutionError()).not.toThrow();
});
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
const error = new CommandExecutionError(message);
expect(error.name).toStrictEqual('CommandExecutionError');
expect(error.message).toStrictEqual(message.toString());
});
});

View File

@@ -0,0 +1,8 @@
class NotImplementedException extends Error {
constructor(message) {
super(message);
this.name = 'NotImplementedException';
}
}
export default NotImplementedException;

View File

@@ -0,0 +1,14 @@
import NotImplementedException from './not-implemented-exception';
describe('NotImplementedException', () => {
it('instantiates', () => {
expect(() => new NotImplementedException()).not.toThrow();
});
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
const error = new NotImplementedException(message);
expect(error.name).toStrictEqual('NotImplementedException');
expect(error.message).toStrictEqual(message.toString());
});
});

View File

@@ -0,0 +1,8 @@
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
export default ValidationError;

View File

@@ -0,0 +1,14 @@
import ValidationError from './validation-error';
describe('ValidationError', () => {
it('instantiates', () => {
expect(() => new ValidationError()).not.toThrow();
});
test.each([1, 'one', { name: '!' }])('Displays title %s', (message) => {
const error = new ValidationError(message);
expect(error.name).toStrictEqual('ValidationError');
expect(error.message).toStrictEqual(message.toString());
});
});

View File

@@ -31,16 +31,16 @@ describe('UnityImageVersion', () => {
expect(image.builderPlatform).toStrictEqual(some.builderPlatform);
});
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', version => {
test.each(['2000.0.0f0', '2011.1.11f1'])('accepts %p version format', (version) => {
expect(() => new ImageTag({ version, platform: some.platform })).not.toThrow();
});
test.each(['some version', '', 1, null])('throws for incorrect versions %p', version => {
test.each(['some version', '', 1])('throws for incorrect versions %p', (version) => {
const { platform } = some;
expect(() => new ImageTag({ version, platform })).toThrow();
});
test.each([undefined, 'nonExisting'])('throws for unsupported target %p', platform => {
test.each([undefined, 'nonExisting'])('throws for unsupported target %p', (platform) => {
expect(() => new ImageTag({ platform })).toThrow();
});
});

23
src/model/index.js Normal file
View File

@@ -0,0 +1,23 @@
import Action from './action';
import BuildParameters from './build-parameters';
import Cache from './cache';
import Docker from './docker';
import Input from './input';
import ImageTag from './image-tag';
import Platform from './platform';
import Project from './project';
import Unity from './unity';
import Versioning from './versioning';
export {
Action,
BuildParameters,
Cache,
Docker,
Input,
ImageTag,
Platform,
Project,
Unity,
Versioning,
};

17
src/model/index.test.js Normal file
View File

@@ -0,0 +1,17 @@
import * as Index from '.';
describe('Index', () => {
test.each([
'Action',
'BuildParameters',
'Cache',
'Docker',
'ImageTag',
'Input',
'Platform',
'Project',
'Unity',
])('exports %s', (exportedModule) => {
expect(Index[exportedModule]).toBeEitherAFunctionOrAnObject();
});
});

View File

@@ -1,24 +1,37 @@
import Platform from './platform';
import Versioning from './versioning';
const core = require('@actions/core');
class Input {
static getFromUser() {
static async getFromUser() {
// Input variables specified in workflows using "with" prop.
const unityVersion = core.getInput('unityVersion');
const version = core.getInput('unityVersion');
const targetPlatform = core.getInput('targetPlatform') || Platform.default;
const projectPath = core.getInput('projectPath');
const rawProjectPath = core.getInput('projectPath') || '.';
const buildName = core.getInput('buildName') || targetPlatform;
const buildsPath = core.getInput('buildsPath') || 'build';
const buildMethod = core.getInput('buildMethod'); // processed in docker file
const versioningStrategy = core.getInput('versioning') || 'Semantic';
const specifiedVersion = core.getInput('version') || '';
const customParameters = core.getInput('customParameters') || '';
// Sanitise input
const projectPath = rawProjectPath.replace(/\/$/, '');
// Parse input
const buildVersion = await Versioning.determineVersion(versioningStrategy, specifiedVersion);
// Return validated input
return {
unityVersion,
version,
targetPlatform,
projectPath,
buildName,
buildsPath,
buildMethod,
buildVersion,
customParameters,
};
}
}

View File

@@ -1,9 +1,27 @@
import Input from './input';
import Versioning from './versioning';
const determineVersion = jest
.spyOn(Versioning, 'determineVersion')
.mockImplementation(() => '1.3.37');
afterEach(() => {
jest.clearAllMocks();
});
describe('Input', () => {
describe('getFromUser', () => {
it('does not throw', () => {
expect(() => Input.getFromUser()).not.toThrow();
it('does not throw', async () => {
await expect(Input.getFromUser()).resolves.not.toBeNull();
});
it('returns an object', async () => {
await expect(typeof (await Input.getFromUser())).toStrictEqual('object');
});
it('calls version generator once', async () => {
await Input.getFromUser();
expect(determineVersion).toHaveBeenCalledTimes(1);
});
});
});

View 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);
});
});
});

24
src/model/project.js Normal file
View File

@@ -0,0 +1,24 @@
import * as core from '@actions/core';
import Unity from './unity';
import Action from './action';
class Project {
static get relativePath() {
// Todo - properly use Input for this.
const projectPath = core.getInput('projectPath') || '.';
return `${projectPath}`;
}
static get absolutePath() {
const { workspace } = Action;
return `${workspace}/${this.relativePath}`;
}
static get libraryFolder() {
return `${this.relativePath}/${Unity.libraryFolder}`;
}
}
export default Project;

35
src/model/project.test.js Normal file
View File

@@ -0,0 +1,35 @@
import Project from './project';
jest.mock('./input');
describe('Platform', () => {
describe('relativePath', () => {
it('does not throw', () => {
expect(() => Project.relativePath).not.toThrow();
});
it('returns a string', () => {
expect(typeof Project.relativePath).toStrictEqual('string');
});
});
describe('absolutePath', () => {
it('does not throw', () => {
expect(() => Project.absolutePath).not.toThrow();
});
it('returns a string', () => {
expect(typeof Project.absolutePath).toStrictEqual('string');
});
});
describe('libraryFolder', () => {
it('does not throw', () => {
expect(() => Project.libraryFolder).not.toThrow();
});
it('returns a string', () => {
expect(typeof Project.libraryFolder).toStrictEqual('string');
});
});
});

44
src/model/system.js Normal file
View File

@@ -0,0 +1,44 @@
import * as core from '@actions/core';
import { exec } from '@actions/exec';
class System {
static async run(command, arguments_, options) {
let result = '';
let error = '';
let debug = '';
const listeners = {
stdout: (dataBuffer) => {
result += dataBuffer.toString();
},
stderr: (dataBuffer) => {
error += dataBuffer.toString();
},
debug: (dataString) => {
debug += dataString.toString();
},
};
const exitCode = await exec(command, arguments_, { silent: true, listeners, ...options });
if (debug !== '') {
core.debug(debug);
}
if (result !== '') {
core.info(result);
}
if (exitCode !== 0) {
throw new Error(error);
}
if (error !== '') {
core.warning(error);
}
return result;
}
}
export default System;

56
src/model/system.test.js Normal file
View File

@@ -0,0 +1,56 @@
import * as core from '@actions/core';
import System from './system';
jest.spyOn(core, 'debug').mockImplementation(() => {});
const info = jest.spyOn(core, 'info').mockImplementation(() => {});
jest.spyOn(core, 'warning').mockImplementation(() => {});
jest.spyOn(core, 'error').mockImplementation(() => {});
afterEach(() => {
jest.clearAllMocks();
});
describe('System', () => {
describe('run', () => {
it('runs a command successfully', async () => {
await expect(System.run('true')).resolves.not.toBeNull();
});
it('outputs results', async () => {
await expect(System.run('echo test')).resolves.toStrictEqual('test\n');
});
it('throws on when error code is not 0', async () => {
await expect(System.run('false')).rejects.toThrowError();
});
it('throws when no arguments are given', async () => {
await expect(System.run()).rejects.toThrowError();
});
it('outputs info', async () => {
await expect(System.run('echo test')).resolves.not.toBeNull();
expect(info).toHaveBeenLastCalledWith('test\n');
});
it('outputs info only once', async () => {
await expect(System.run('echo 1')).resolves.not.toBeNull();
expect(info).toHaveBeenCalledTimes(1);
expect(info).toHaveBeenLastCalledWith('1\n');
info.mockClear();
await expect(System.run('echo 2')).resolves.not.toBeNull();
await expect(System.run('echo 3')).resolves.not.toBeNull();
expect(info).toHaveBeenCalledTimes(2);
expect(info).toHaveBeenLastCalledWith('3\n');
});
it('allows pipes using buffer', async () => {
await expect(
System.run('sh', undefined, {
input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'),
}),
).resolves.toBeParsableToANumber();
});
});
});

7
src/model/unity.js Normal file
View File

@@ -0,0 +1,7 @@
class Unity {
static get libraryFolder() {
return 'Library';
}
}
export default Unity;

13
src/model/unity.test.js Normal file
View File

@@ -0,0 +1,13 @@
import Unity from './unity';
describe('Unity', () => {
describe('libraryFolder', () => {
it('does not throw', () => {
expect(() => Unity.libraryFolder).not.toThrow();
});
it('returns a string', () => {
expect(typeof Unity.libraryFolder).toStrictEqual('string');
});
});
});

204
src/model/versioning.js Normal file
View File

@@ -0,0 +1,204 @@
import * as core from '@actions/core';
import NotImplementedException from './error/not-implemented-exception';
import ValidationError from './error/validation-error';
import System from './system';
export default class Versioning {
static get strategies() {
return { None: 'None', Semantic: 'Semantic', Tag: 'Tag', Custom: 'Custom' };
}
/**
* Get the branch name of the (related) branch
*/
static get branch() {
// Todo - use optional chaining (https://github.com/zeit/ncc/issues/534)
return this.headRef || (this.ref && this.ref.slice(11));
}
/**
* For pull requests we can reliably use GITHUB_HEAD_REF
*/
static get headRef() {
return process.env.GITHUB_HEAD_REF;
}
/**
* For branches GITHUB_REF will have format `refs/heads/feature-branch-1`
*/
static get ref() {
return process.env.GITHUB_REF;
}
/**
* Regex to parse version description into separate fields
*/
static get descriptionRegex() {
return /^v([\d.]+)-(\d+)-g(\w+)-?(\w+)*/g;
}
static async determineVersion(strategy, inputVersion) {
// Validate input
if (!Object.hasOwnProperty.call(this.strategies, strategy)) {
throw new ValidationError(
`Versioning strategy should be one of ${Object.values(this.strategies).join(', ')}.`,
);
}
let version;
switch (strategy) {
case this.strategies.None:
version = 'none';
break;
case this.strategies.Custom:
version = inputVersion;
break;
case this.strategies.Semantic:
version = await this.generateSemanticVersion();
break;
case this.strategies.Tag:
version = await this.generateTagVersion();
break;
default:
throw new NotImplementedException(`Strategy ${strategy} is not implemented.`);
}
return version;
}
/**
* Automatically generates a version based on SemVer out of the box.
*
* The version works as follows: `<major>.<minor>.<patch>` for example `0.1.2`.
*
* The latest tag dictates `<major>.<minor>`
* The number of commits since that tag dictates`<patch>`.
*
* @See: https://semver.org/
*/
static async generateSemanticVersion() {
await this.fetch();
if (await this.isDirty()) {
throw new Error('Branch is dirty. Refusing to base semantic version on uncommitted changes');
}
if (!(await this.hasAnyVersionTags())) {
const version = `0.0.${await this.getTotalNumberOfCommits()}`;
core.info(`Generated version ${version} (no version tags found).`);
return version;
}
const { tag, commits, hash } = await this.parseSemanticVersion();
core.info(`Found semantic version ${tag}.${commits} for ${this.branch}@${hash}`);
return `${tag}.${commits}`;
}
/**
* Generate the proper version for unity based on an existing tag.
*/
static async generateTagVersion() {
let tag = await this.getTag();
if (tag.charAt(0) === 'v') {
tag = tag.slice(1);
}
return tag;
}
/**
* Parses the versionDescription into their named parts.
*/
static async parseSemanticVersion() {
const description = await this.getVersionDescription();
try {
const [match, tag, commits, hash] = this.descriptionRegex.exec(description);
return {
match,
tag,
commits,
hash,
};
} catch (error) {
throw new Error(`Failed to parse git describe output: "${description}".`);
}
}
/**
* Retrieves refs from the configured remote.
*
* Fetch unshallow for incomplete repository, but fall back to normal fetch.
*
* Note: `--all` should not be used, and would break fetching for push event.
*/
static async fetch() {
try {
await System.run('git', ['fetch', '--unshallow']);
} catch (error) {
core.warning(error);
await System.run('git', ['fetch']);
}
}
/**
* Retrieves information about the branch.
*
* Format: `v0.12-24-gd2198ab`
*
* In this format v0.12 is the latest tag, 24 are the number of commits since, and gd2198ab
* identifies the current commit.
*/
static async getVersionDescription() {
return System.run('git', [
'describe',
'--long',
'--tags',
'--always',
'--debug',
`origin/${this.branch}`,
]);
}
/**
* Returns whether there are uncommitted changes that are not ignored.
*/
static async isDirty() {
const output = await System.run('git', ['status', '--porcelain']);
return output !== '';
}
/**
* Get the tag if there is one pointing at HEAD
*/
static async getTag() {
return System.run('git', ['tag', '--points-at', 'HEAD']);
}
/**
* Whether or not the repository has any version tags yet.
*/
static async hasAnyVersionTags() {
const numberOfCommitsAsString = await System.run('sh', undefined, {
input: Buffer.from('git tag --list --merged HEAD | grep v[0-9]* | wc -l'),
silent: false,
});
const numberOfCommits = Number.parseInt(numberOfCommitsAsString, 10);
return numberOfCommits !== 0;
}
/**
* Get the total number of commits on head.
*/
static async getTotalNumberOfCommits() {
const numberOfCommitsAsString = await System.run('git', ['rev-list', '--count', 'HEAD']);
return Number.parseInt(numberOfCommitsAsString, 10);
}
}

View File

@@ -0,0 +1,307 @@
import * as core from '@actions/core';
import NotImplementedException from './error/not-implemented-exception';
import System from './system';
import Versioning from './versioning';
afterEach(() => {
jest.restoreAllMocks();
});
describe('Versioning', () => {
describe('strategies', () => {
it('returns an object', () => {
expect(typeof Versioning.strategies).toStrictEqual('object');
});
it('has items', () => {
expect(Object.values(Versioning.strategies).length).toBeGreaterThan(2);
});
it('has an opt out option', () => {
expect(Versioning.strategies).toHaveProperty('None');
});
it('has the semantic option', () => {
expect(Versioning.strategies).toHaveProperty('Semantic');
});
it('has a strategy for tags', () => {
expect(Versioning.strategies).toHaveProperty('Tag');
});
it('has an option that allows custom input', () => {
expect(Versioning.strategies).toHaveProperty('Custom');
});
});
describe('branch', () => {
it('returns headRef when set', () => {
const headReference = jest
.spyOn(Versioning, 'headRef', 'get')
.mockReturnValue('feature-branch-1');
expect(Versioning.branch).toStrictEqual('feature-branch-1');
expect(headReference).toHaveBeenCalledTimes(1);
});
it('returns part of Ref when set', () => {
jest.spyOn(Versioning, 'headRef', 'get').mockReturnValue(undefined);
const reference = jest
.spyOn(Versioning, 'ref', 'get')
.mockReturnValue('refs/heads/feature-branch-2');
expect(Versioning.branch).toStrictEqual('feature-branch-2');
expect(reference).toHaveBeenCalledTimes(2);
});
it('prefers headRef over ref when set', () => {
const headReference = jest
.spyOn(Versioning, 'headRef', 'get')
.mockReturnValue('feature-branch-1');
const reference = jest
.spyOn(Versioning, 'ref', 'get')
.mockReturnValue('refs/heads/feature-2');
expect(Versioning.branch).toStrictEqual('feature-branch-1');
expect(headReference).toHaveBeenCalledTimes(1);
expect(reference).toHaveBeenCalledTimes(0);
});
it('returns undefined when headRef and ref are not set', () => {
const headReference = jest.spyOn(Versioning, 'headRef', 'get').mockReturnValue(undefined);
const reference = jest.spyOn(Versioning, 'ref', 'get').mockReturnValue(undefined);
expect(Versioning.branch).not.toBeDefined();
expect(headReference).toHaveBeenCalledTimes(1);
expect(reference).toHaveBeenCalledTimes(1);
});
});
describe('headRef', () => {
it('does not throw', () => {
expect(() => Versioning.headRef).not.toThrow();
});
});
describe('ref', () => {
it('does not throw', () => {
expect(() => Versioning.ref).not.toThrow();
});
});
describe('descriptionRegex', () => {
it('is a valid regex', () => {
expect(Versioning.descriptionRegex).toBeInstanceOf(RegExp);
});
test.each(['v1.1-1-g12345678', 'v0.1-2-g12345678', 'v0.0-500-gA9B6C3D0-dirty'])(
'is happy with valid %s',
(description) => {
expect(Versioning.descriptionRegex.test(description)).toBeTruthy();
},
);
test.each([undefined, 'v0', 'v0.1', 'v0.1.2', 'v0.1-2', 'v0.1-2-g'])(
'does not like %s',
(description) => {
expect(Versioning.descriptionRegex.test(description)).toBeFalsy();
// Also never expect without the v to work for any of these cases.
expect(Versioning.descriptionRegex.test(description?.substr(1))).toBeFalsy();
},
);
});
describe('determineVersion', () => {
test.each([undefined, 0, 'somethingRandom'])(
'throws for invalid strategy %s',
async (strategy) => {
await expect(Versioning.determineVersion(strategy)).rejects.toThrowErrorMatchingSnapshot();
},
);
describe('opt out strategy', () => {
it("returns 'none'", async () => {
await expect(Versioning.determineVersion('None', 'v1.0')).resolves.toMatchInlineSnapshot(
`"none"`,
);
});
});
describe('custom strategy', () => {
test.each([undefined, 0, 'v0.1', '1', 'CamelCase', 'dashed-version'])(
'returns the inputVersion for %s',
async (inputVersion) => {
await expect(Versioning.determineVersion('Custom', inputVersion)).resolves.toStrictEqual(
inputVersion,
);
},
);
});
describe('semantic strategy', () => {
it('refers to generateSemanticVersion', async () => {
const generateSemanticVersion = jest
.spyOn(Versioning, 'generateSemanticVersion')
.mockResolvedValue('1.3.37');
await expect(Versioning.determineVersion('Semantic')).resolves.toStrictEqual('1.3.37');
expect(generateSemanticVersion).toHaveBeenCalledTimes(1);
});
});
describe('tag strategy', () => {
it('refers to generateTagVersion', async () => {
const generateTagVersion = jest
.spyOn(Versioning, 'generateTagVersion')
.mockResolvedValue('0.1');
await expect(Versioning.determineVersion('Tag')).resolves.toStrictEqual('0.1');
expect(generateTagVersion).toHaveBeenCalledTimes(1);
});
});
describe('not implemented strategy', () => {
it('throws a not implemented exception', async () => {
const strategy = 'Test';
jest.spyOn(Versioning, 'strategies', 'get').mockReturnValue({ [strategy]: strategy });
await expect(Versioning.determineVersion(strategy)).rejects.toThrowError(
NotImplementedException,
);
});
});
});
describe('generateTagVersion', () => {
it('removes the v', async () => {
jest.spyOn(Versioning, 'getTag').mockResolvedValue('v1.3.37');
await expect(Versioning.generateTagVersion()).resolves.toStrictEqual('1.3.37');
});
});
describe('parseSemanticVersion', () => {
it('returns the named parts', async () => {
jest.spyOn(Versioning, 'getVersionDescription').mockResolvedValue('v0.1-2-g12345678');
await expect(Versioning.parseSemanticVersion()).resolves.toMatchObject({
tag: '0.1',
commits: '2',
hash: '12345678',
});
});
it('throws when no match could be made', async () => {
jest.spyOn(Versioning, 'getVersionDescription').mockResolvedValue('no-match-can-be-made');
await expect(Versioning.parseSemanticVersion()).rejects.toThrowErrorMatchingInlineSnapshot(
`"Failed to parse git describe output: \\"no-match-can-be-made\\"."`,
);
});
});
describe('getVersionDescription', () => {
it('returns the commands output', async () => {
const runOutput = 'someValue';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.getVersionDescription()).resolves.toStrictEqual(runOutput);
});
});
describe('fetch', () => {
it('awaits the command', async () => {
jest.spyOn(core, 'warning').mockImplementation(() => {});
jest.spyOn(System, 'run').mockResolvedValue(undefined);
await expect(Versioning.fetch()).resolves.not.toThrow();
});
it('falls back to the second strategy when the first fails', async () => {
jest.spyOn(core, 'warning').mockImplementation(() => {});
const gitFetch = jest
.spyOn(System, 'run')
.mockResolvedValue(undefined)
.mockRejectedValueOnce(undefined);
await expect(Versioning.fetch()).resolves.not.toThrow();
expect(gitFetch).toHaveBeenCalledTimes(2);
});
});
describe('generateSemanticVersion', () => {
it('returns a proper version from description', async () => {
jest.spyOn(System, 'run').mockResolvedValue(undefined);
jest.spyOn(core, 'info').mockImplementation(() => {});
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(false);
jest.spyOn(Versioning, 'hasAnyVersionTags').mockResolvedValue(true);
jest.spyOn(Versioning, 'getTotalNumberOfCommits').mockResolvedValue(2);
jest.spyOn(Versioning, 'parseSemanticVersion').mockResolvedValue({
match: '0.1-2-g1b345678',
tag: '0.1',
commits: '2',
hash: '1b345678',
});
await expect(Versioning.generateSemanticVersion()).resolves.toStrictEqual('0.1.2');
});
it('throws when dirty', async () => {
jest.spyOn(System, 'run').mockResolvedValue(undefined);
jest.spyOn(core, 'info').mockImplementation(() => {});
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(true);
await expect(Versioning.generateSemanticVersion()).rejects.toThrowError();
});
it('falls back to commits only, when no tags are present', async () => {
const commits = Math.round(Math.random() * 10);
jest.spyOn(System, 'run').mockResolvedValue(undefined);
jest.spyOn(core, 'info').mockImplementation(() => {});
jest.spyOn(Versioning, 'isDirty').mockResolvedValue(false);
jest.spyOn(Versioning, 'hasAnyVersionTags').mockResolvedValue(false);
jest.spyOn(Versioning, 'getTotalNumberOfCommits').mockResolvedValue(commits);
await expect(Versioning.generateSemanticVersion()).resolves.toStrictEqual(`0.0.${commits}`);
});
});
describe('isDirty', () => {
it('returns true when there are files listed', async () => {
const runOutput = 'file.ext\nfile2.ext';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.isDirty()).resolves.toStrictEqual(true);
});
it('returns false when there is no output', async () => {
const runOutput = '';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.isDirty()).resolves.toStrictEqual(false);
});
});
describe('getTag', () => {
it('returns the commands output', async () => {
const runOutput = 'v1.0';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.getTag()).resolves.toStrictEqual(runOutput);
});
});
describe('hasAnyVersionTags', () => {
it('returns false when the command returns 0', async () => {
const runOutput = '0';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.hasAnyVersionTags()).resolves.toStrictEqual(false);
});
it('returns true when the command returns >= 0', async () => {
const runOutput = '9';
jest.spyOn(System, 'run').mockResolvedValue(runOutput);
await expect(Versioning.hasAnyVersionTags()).resolves.toStrictEqual(true);
});
});
describe('getTotalNumberOfCommits', () => {
it('returns a number from the command', async () => {
jest.spyOn(System, 'run').mockResolvedValue('9');
await expect(Versioning.getTotalNumberOfCommits()).resolves.toStrictEqual(9);
});
});
});

4822
yarn.lock

File diff suppressed because it is too large Load Diff