├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── question.md
└── workflows
│ ├── release.yml
│ ├── test.yml
│ └── update-changesets.yml
├── .gitignore
├── .tool-versions
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── README.md
├── build
├── .releaserc.json
└── build_npm.ts
├── deno.json
├── deno.lock
└── src
├── cli.ts
├── index.ts
├── unityChangeset.test.ts
├── unityChangeset.ts
└── unityGraphQL.ts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: mob-sakai # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: mob-sakai # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: mob-sakai
7 |
8 | ---
9 |
10 | NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
11 |
12 | **Describe the bug**
13 | A clear and concise description of what the bug is.
14 |
15 | **To Reproduce**
16 | Steps to reproduce the behavior:
17 | 1. Go to '...'
18 | 2. Click on '....'
19 | 3. Scroll down to '....'
20 | 4. See error
21 |
22 | **Expected behavior**
23 | A clear and concise description of what you expected to happen.
24 |
25 | **Screenshots**
26 | If applicable, add screenshots to help explain your problem.
27 |
28 | **Environment (please complete the following information):**
29 | - OS: [e.g. Windows 10, MacOS 10.14]
30 | - Node: [e.g. 8.15]
31 | - Version: [e.g. 1.0.0]
32 |
33 | **Additional context**
34 | Add any other context about the problem here.
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: mob-sakai
7 |
8 | ---
9 |
10 | NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
11 |
12 | **Is your feature request related to a problem? Please describe.**
13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
14 |
15 | **Describe the solution you'd like**
16 | A clear and concise description of what you want to happen.
17 |
18 | **Describe alternatives you've considered**
19 | A clear and concise description of any alternative solutions or features you've considered.
20 |
21 | **Additional context**
22 | Add any other context or screenshots about the feature request here.
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask a question about this project
4 | title: ''
5 | labels: question
6 | assignees: mob-sakai
7 |
8 | ---
9 |
10 | NOTE: Your issue may already be reported! Please search on the [issue tracker](../) before creating one.
11 |
12 | **Describe what help do you need**
13 | A description of the question.
14 |
15 | **Additional context**
16 | Add any other context or screenshots about the question here.
17 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - beta
8 | tags-ignore:
9 | - "**"
10 |
11 | jobs:
12 | release:
13 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }}
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v4
17 |
18 | - uses: asdf-vm/actions/install@v3
19 |
20 | - run: deno task build
21 |
22 | - uses: actions/setup-node@v4
23 | with:
24 | node-version: 16
25 |
26 | - uses: cycjimmy/semantic-release-action@v4
27 | with:
28 | working_directory: npm
29 | env:
30 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
31 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
32 |
33 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - "**.ts"
7 | push:
8 | branches:
9 | - "develop"
10 | paths:
11 | - "**.ts"
12 | workflow_dispatch:
13 |
14 | jobs:
15 | test:
16 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]') }}
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - uses: asdf-vm/actions/install@v3
22 |
23 | - run: deno task build
24 |
--------------------------------------------------------------------------------
/.github/workflows/update-changesets.yml:
--------------------------------------------------------------------------------
1 | name: update-changesets
2 |
3 | env:
4 | WORKFLOW_FILE: update-changesets.yml
5 |
6 | on:
7 | issue_comment:
8 | types:
9 | - created
10 |
11 | jobs:
12 | build:
13 | if: startsWith(github.event.comment.body, '/update-changesets') && github.event.issue.locked
14 | name: 🛠️ Update changesets
15 | runs-on: ubuntu-latest
16 | permissions:
17 | contents: write
18 | actions: read
19 | steps:
20 | - name: 🚚 Checkout (gh_pages)
21 | uses: actions/checkout@v4
22 | with:
23 | fetch-depth: 0
24 | ref: gh_pages
25 |
26 | - name: 🔍 Check other workflows
27 | run: |
28 | # Get in-progress or queued workflows.
29 | gh auth login --with-token < <(echo ${{ github.token }})
30 | RESULT=`gh run list --workflow ${{ env.WORKFLOW_FILE }} --json status --jq '[.[] | select(.status == "in_progress")] | length == 1'`
31 |
32 | # [ERROR] Other workflows are in progress.
33 | [ "$RESULT" = "false" ] && echo "::error::Other '${{ env.WORKFLOW_FILE }}' workflows are in progress." && exit 1 || :
34 |
35 | - name: 🛠️ Update changesets file
36 | run: npx unity-changeset@latest list --all --all-lifecycles > db
37 |
38 | - name: Commit & Push changes
39 | uses: actions-js/push@master
40 | with:
41 | github_token: ${{ github.token }}
42 | amend: true
43 | force: true
44 | branch: gh_pages
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 | .DS_Store
106 | /npm
107 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | deno 2.0.4
2 | nodejs 16.19.1
3 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // IntelliSense を使用して利用可能な属性を学べます。
3 | // 既存の属性の説明をホバーして表示します。
4 | // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "request": "launch",
9 | "name": "list",
10 | "type": "node",
11 | "program": "${workspaceFolder}/src/cli.ts",
12 | "cwd": "${workspaceFolder}",
13 | "env": {},
14 | "runtimeExecutable": "/Users/takashi.sakai/.asdf/shims/deno",
15 | "runtimeArgs": [
16 | "run",
17 | "--unstable",
18 | "--inspect-brk",
19 | "--allow-all"
20 | ],
21 | "args": [
22 | "list"
23 | ],
24 | "attachSimplePort": 9229
25 | },
26 | {
27 | "request": "launch",
28 | "name": "list --versions --all --all-lifecycles",
29 | "type": "node",
30 | "program": "${workspaceFolder}/src/cli.ts",
31 | "cwd": "${workspaceFolder}",
32 | "env": {},
33 | "runtimeExecutable": "/Users/takashi.sakai/.asdf/shims/deno",
34 | "runtimeArgs": [
35 | "run",
36 | "--unstable",
37 | "--inspect-brk",
38 | "--allow-all"
39 | ],
40 | "args": [
41 | "list",
42 | "--versions",
43 | "--all",
44 | "--all-lifecycles"
45 | ],
46 | "attachSimplePort": 9229
47 | },
48 | {
49 | "request": "launch",
50 | "name": "6000.0.25f1",
51 | "type": "node",
52 | "program": "${workspaceFolder}/src/cli.ts",
53 | "cwd": "${workspaceFolder}",
54 | "env": {},
55 | "runtimeExecutable": "/Users/takashi.sakai/.asdf/shims/deno",
56 | "runtimeArgs": [
57 | "run",
58 | "--unstable",
59 | "--inspect-brk",
60 | "--allow-all"
61 | ],
62 | "args": [
63 | "6000.0.25f1"
64 | ],
65 | "attachSimplePort": 9229
66 | },
67 | {
68 | "request": "launch",
69 | "name": "6000.0.25f2",
70 | "type": "node",
71 | "program": "${workspaceFolder}/src/cli.ts",
72 | "cwd": "${workspaceFolder}",
73 | "env": {},
74 | "runtimeExecutable": "/Users/takashi.sakai/.asdf/shims/deno",
75 | "runtimeArgs": [
76 | "run",
77 | "--unstable",
78 | "--inspect-brk",
79 | "--allow-all"
80 | ],
81 | "args": [
82 | "6000.0.25f2"
83 | ],
84 | "attachSimplePort": 9229
85 | },
86 | {
87 | "request": "launch",
88 | "name": "--help",
89 | "type": "node",
90 | "program": "${workspaceFolder}/src/cli.ts",
91 | "cwd": "${workspaceFolder}",
92 | "env": {},
93 | "runtimeExecutable": "/Users/takashi.sakai/.asdf/shims/deno",
94 | "runtimeArgs": [
95 | "run",
96 | "--unstable",
97 | "--inspect-brk",
98 | "--allow-all"
99 | ],
100 | "args": [
101 | "--help"
102 | ],
103 | "attachSimplePort": 9229
104 | }
105 | ]
106 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "deno.enable": true,
3 | "deno.lint": true,
4 | "deno.unstable": true,
5 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 mob-sakai
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | unity-changeset
2 | ===
3 |
4 | Get/List Unity editor changeset
5 |
6 | [](https://deno.land/x/unity_changeset)
7 | [](https://www.npmjs.com/package/unity-changeset)
8 | 
9 | 
10 | 
11 | [](https://github.com/semantic-release/semantic-release)
12 |
13 |
14 |
15 | ## Usage as a node module
16 |
17 | Requirement: NodeJs 14 or later
18 |
19 | ### Install
20 |
21 | ```sh
22 | npm install unity-changeset
23 | ```
24 |
25 | ### Import
26 |
27 | ```js
28 | // javascript
29 | const { getUnityChangeset, scrapeArchivedChangesets, scrapeBetaChangesets } = require('unity-changeset');
30 | // or, typescript
31 | const { getUnityChangeset, scrapeArchivedChangesets, scrapeBetaChangesets } = from 'unity-changeset';
32 | ```
33 |
34 | ### Example
35 |
36 | ```js
37 | const { getUnityChangeset, scrapeArchivedChangesets, scrapeBetaChangesets } = require('unity-changeset');
38 |
39 | (async () => {
40 | const changeset = await getUnityChangeset('2020.1.14f1');
41 | console.log(changeset);
42 | //=> UnityChangeset {version: '2020.1.14f1', changeset: 'd81f64f5201d'}
43 | console.log(changeset.toString());
44 | //=> 2020.1.14f1 d81f64f5201d
45 | const changesets = await scrapeArchivedChangesets();
46 | console.dir(changesets);
47 | //=> [
48 | // UnityChangeset { version: '2020.1.15f1', changeset: '97d0ae02d19d' },
49 | // UnityChangeset { version: '2020.1.14f1', changeset: 'd81f64f5201d' },
50 | // UnityChangeset { version: '2020.1.13f1', changeset: '5e24f28bfbc0' },
51 | // ...
52 | // ]
53 | const betaChangesets = await scrapeBetaChangesets();
54 | console.log(betaChangesets);
55 | //=> [
56 | // UnityChangeset { version: '2020.2.0b13', changeset: '655e1a328b90' },
57 | // UnityChangeset { version: '2020.2.0b12', changeset: '92852ae685d8' },
58 | // UnityChangeset { version: '2020.2.0b11', changeset: 'c499c2bf2e80' },
59 | // ...
60 | // ]
61 | })();
62 | ```
63 |
64 |
65 | ## Usage as a deno module
66 |
67 | ```js
68 | const { getUnityChangeset, scrapeArchivedChangesets, scrapeBetaChangesets } = from 'https://deno.land/x/unity_changeset/src/index.ts';
69 |
70 | // or, specific version
71 | const { getUnityChangeset, scrapeArchivedChangesets, scrapeBetaChangesets } = from 'https://deno.land/x/unity_changeset@2.0.0/src/index.ts';
72 | ```
73 |
74 |
75 |
76 | ## Usage as a command-line utility
77 |
78 | ### Install
79 |
80 | ```sh
81 | # Requirement: NodeJs 14 or later
82 | npm install -g unity-changeset
83 |
84 | # Use without installation
85 | npx unity-changeset ...
86 | ```
87 |
88 | or
89 |
90 | ```
91 | deno install -A -f -n unity-changeset https://deno.land/x/unity_changeset/src/cli.ts
92 | ```
93 |
94 |
95 | ### Help
96 |
97 | ```
98 | Usage: unity-changeset
99 |
100 | Description:
101 |
102 | Find Unity changesets.
103 |
104 | Options:
105 |
106 | -h, --help - Show this help.
107 | -V, --version - Show the version number for this program.
108 | ```
109 |
110 | ```
111 | Usage: unity-changeset list
112 |
113 | Description:
114 |
115 | List Unity changesets.
116 |
117 | Options:
118 |
119 | -h, --help - Show this help.
120 |
121 | Search options:
122 |
123 | --all - Search all changesets (alpha/beta included)
124 | --pre-release, --beta - Search only pre-release (alpha/beta) changesets
125 | --lts - Only the LTS versions
126 | --xlts - Only the LTS/XLTS versions (require 'Enterprise' or 'Industry' license to install XLTS version)
127 |
128 | Filter options:
129 |
130 | --min - Minimum version (included)
131 | --max - Maximum version (included)
132 | --grep - Regular expression (e.g. '20(18|19).4.*')
133 | --latest-lifecycle - Only the latest lifecycle (default)
134 | --all-lifecycles - All lifecycles
135 |
136 | Group options:
137 |
138 | --latest-patch - The latest patch versions only
139 | --oldest-patch - The oldest patch versions in lateat lifecycle only (Conflicts: --latest-patch)
140 |
141 | Output options:
142 |
143 | --version-only, --versions - Outputs only the version (no changesets)
144 | --minor-version-only, --minor-versions - Outputs only the minor version (no changesets)
145 | --json - Output in json format
146 | --pretty-json - Output in pretty json format
147 | ```
148 |
149 |
150 | ### Get a changeset for specific version:
151 |
152 | ```sh
153 | $ unity-changeset 2020.2.14f1
154 | d81f64f5201d
155 | ```
156 |
157 |
158 | ### Get a changeset for specific version
159 |
160 | ```sh
161 | $ unity-changeset list
162 | 2020.1.14f1 d81f64f5201d
163 | 2020.1.13f1 5e24f28bfbc0
164 | 2020.1.12f1 55b56f0a86e3
165 | ...
166 |
167 | # List changesets in json format:
168 | $ unity-changeset list --json
169 | [{"version":"2020.1.15f1","changeset":"97d0ae02d19d"},{"version":"2020.1.14f1","changeset":"d81f64f5201d"},...]
170 |
171 | # List changesets in pretty json format:
172 | $ unity-changeset list --pretty-json
173 | [
174 | {
175 | "version": "2020.1.15f1",
176 | "changeset": "97d0ae02d19d"
177 | },
178 | {
179 | "version": "2020.1.14f1",
180 | "changeset": "d81f64f5201d"
181 | },
182 | ...
183 | ]
184 |
185 | # List changesets (alpha/beta):
186 | $ unity-changeset list --beta
187 | 2020.2.0b13 655e1a328b90
188 | 2020.2.0b12 92852ae685d8
189 | 2020.2.0b11 c499c2bf2e80
190 | ...
191 |
192 | # List changesets (all):
193 | $ unity-changeset list --all
194 | 2020.2.0b13 655e1a328b90
195 | 2020.2.0b12 92852ae685d8
196 | ...
197 | 2020.1.14f1 d81f64f5201d
198 | 2020.1.13f1 5e24f28bfbc0
199 | ...
200 |
201 | # List the available Unity versions:
202 | $ unity-changeset list --versions
203 | 2020.1.14f1
204 | 2020.1.13f1
205 | 2020.1.12f1
206 | ...
207 |
208 | # List the available Unity versions (alpha/beta):
209 | $ unity-changeset list --beta --versions
210 | 2020.2.0b13
211 | 2020.2.0b12
212 | 2020.2.0b11
213 | ...
214 |
215 | # List Unity 2018.3 or later, and 2019.1 or earlier:
216 | $ unity-changeset list --min 2018.3 --max 2019.1
217 | 2019.1.14f1 148b5891095a
218 | ...
219 | 2018.3.1f1 bb579dc42f1d
220 | 2018.3.0f2 6e9a27477296
221 |
222 | # List all Unity 2018.3 versions:
223 | $ unity-changeset list --grep 2018.3
224 | 2018.3.14f1 d0e9f15437b1
225 | 2018.3.13f1 06548a9e9582
226 | ...
227 | 2018.3.1f1 bb579dc42f1d
228 | 2018.3.0f2 6e9a27477296
229 |
230 | # List the available Unity minor versions:
231 | $ unity-changeset list --minor-versions
232 | 2020.1
233 | ...
234 | 2017.2
235 | 2017.1
236 |
237 | # List the latest Unity patch versions:
238 | $ unity-changeset list --latest-patch
239 | 2020.1.14f1 d81f64f5201d
240 | ...
241 | 2017.2.5f1 588dc79c95ed
242 | 2017.1.5f1 9758a36cfaa6
243 | ```
244 |
245 | ### Install a specific version of Unity via UnityHub
246 |
247 | ```sh
248 | # /path/to/unity/hub:
249 | # Windows: C:\\Program\ Files\\Unity\ Hub\\Unity\ Hub.exe
250 | # MacOS: /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub
251 |
252 | # Show UnityHub help:
253 | $ /path/to/unity/hub -- --headless help
254 |
255 | # Install Unity 2020.1.15f1 with modules for iOS and Android:
256 | $ /path/to/unity/hub -- --headless install \
257 | --version 2020.1.15f1 \
258 | --changeset `unity-changeset 2020.1.15f1` \
259 | --module ios,android
260 | ```
261 |
262 |
263 |
264 | ## Contributing
265 |
266 | ### Issues
267 |
268 | Issues are very valuable to this project.
269 |
270 | - Ideas are a valuable source of contributions others can make
271 | - Problems show where this project is lacking
272 | - With a question you show where contributors can improve the user experience
273 |
274 | ### Pull Requests
275 |
276 | Pull requests are, a great way to get your ideas into this repository.
277 |
278 | ### Support
279 |
280 | This is an open source project that I am developing in my spare time.
281 | If you like it, please support me.
282 | With your support, I can spend more time on development. :)
283 |
284 | [](https://github.com/users/mob-sakai/sponsorship)
285 |
286 |
287 |
288 | ## License
289 |
290 | * MIT
291 |
292 | ## Author
293 |
294 | *  [mob-sakai](https://github.com/mob-sakai) [](https://twitter.com/intent/follow?screen_name=mob_sakai) 
295 |
296 | ## See Also
297 |
298 | * GitHub page : https://github.com/mob-sakai/unity-changeset
299 | * Releases : https://github.com/mob-sakai/unity-changeset/releases
300 | * Issue tracker : https://github.com/mob-sakai/unity-changeset/issues
301 | * Change log : https://github.com/mob-sakai/unity-changeset/blob/main/CHANGELOG.md
302 |
--------------------------------------------------------------------------------
/build/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "branches": [
3 | "main",
4 | {
5 | "name": "beta",
6 | "prerelease": true
7 | }
8 | ],
9 | "tagFormat": "${version}",
10 | "plugins": [
11 | "@semantic-release/commit-analyzer",
12 | "@semantic-release/release-notes-generator",
13 | "@semantic-release/npm",
14 | "@semantic-release/github"
15 | ]
16 | }
--------------------------------------------------------------------------------
/build/build_npm.ts:
--------------------------------------------------------------------------------
1 | import { build, emptyDir } from "https://deno.land/x/dnt@0.40.0/mod.ts";
2 |
3 | // delete previous build
4 | await emptyDir("./npm");
5 |
6 | // build
7 | await build({
8 | entryPoints: [
9 | "./src/index.ts",
10 | {
11 | kind: "bin",
12 | name: "unity-changeset",
13 | path: "./src/cli.ts",
14 | },
15 | ],
16 | outDir: "./npm",
17 | shims: {
18 | deno: true, // for Deno namespace
19 | },
20 | // package.json properties
21 | package: {
22 | name: "unity-changeset",
23 | version: "0.0.1",
24 | description: "Get/List Unity changeset",
25 | author: "mob-sakai ",
26 | license: "MIT",
27 | repository: {
28 | type: "git",
29 | url: "git+https://github.com/mob-sakai/unity-changeset.git",
30 | },
31 | bugs: {
32 | url: "https://github.com/mob-sakai/unity-changeset/issues",
33 | },
34 | engines: {
35 | node: ">=14",
36 | },
37 | },
38 | postBuild() {
39 | Deno.copyFileSync("LICENSE", "npm/LICENSE");
40 | Deno.copyFileSync("README.md", "npm/README.md");
41 | Deno.copyFileSync("build/.releaserc.json", "npm/.releaserc.json");
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/deno.json:
--------------------------------------------------------------------------------
1 | {
2 | "tasks": {
3 | "run": "deno run -A src/cli.ts",
4 | "build": "deno run -A build/build_npm.ts",
5 | "test": "deno test -A src/",
6 | "lint": "deno lint src/ && deno fmt src/"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/deno.lock:
--------------------------------------------------------------------------------
1 | {
2 | "version": "4",
3 | "remote": {
4 | "https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
5 | "https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49",
6 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d",
7 | "https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9",
8 | "https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf",
9 | "https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37",
10 | "https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f",
11 | "https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d",
12 | "https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b",
13 | "https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
14 | "https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
15 | "https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
16 | "https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
17 | "https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
18 | "https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d",
19 | "https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44",
20 | "https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
21 | "https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757",
22 | "https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21",
23 | "https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
24 | "https://deno.land/std@0.181.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
25 | "https://deno.land/std@0.181.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e",
26 | "https://deno.land/std@0.181.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32",
27 | "https://deno.land/std@0.181.0/fs/empty_dir.ts": "c3d2da4c7352fab1cf144a1ecfef58090769e8af633678e0f3fabaef98594688",
28 | "https://deno.land/std@0.181.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40",
29 | "https://deno.land/std@0.181.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a",
30 | "https://deno.land/std@0.181.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32",
31 | "https://deno.land/std@0.181.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
32 | "https://deno.land/std@0.181.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
33 | "https://deno.land/std@0.181.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
34 | "https://deno.land/std@0.181.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
35 | "https://deno.land/std@0.181.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
36 | "https://deno.land/std@0.181.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c",
37 | "https://deno.land/std@0.181.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
38 | "https://deno.land/std@0.181.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
39 | "https://deno.land/std@0.181.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
40 | "https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
41 | "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
42 | "https://deno.land/x/deno_cache@0.6.2/auth_tokens.ts": "5d1d56474c54a9d152e44d43ea17c2e6a398dd1e9682c69811a313567c01ee1e",
43 | "https://deno.land/x/deno_cache@0.6.2/cache.ts": "58b53c128b742757efcad10af9a3871f23b4e200674cb5b0ddf61164fb9b2fe7",
44 | "https://deno.land/x/deno_cache@0.6.2/deno_dir.ts": "1ea355b8ba11c630d076b222b197cfc937dd81e5a4a260938997da99e8ff93a0",
45 | "https://deno.land/x/deno_cache@0.6.2/deps.ts": "12cca94516cf2d3ed42fccd4b721ecd8060679253f077d83057511045b0081aa",
46 | "https://deno.land/x/deno_cache@0.6.2/dirs.ts": "009c6f54e0b610914d6ce9f72f6f6ccfffd2d47a79a19061e0a9eb4253836069",
47 | "https://deno.land/x/deno_cache@0.6.2/disk_cache.ts": "66a1e604a8d564b6dd0500326cac33d08b561d331036bf7272def80f2f7952aa",
48 | "https://deno.land/x/deno_cache@0.6.2/file_fetcher.ts": "4f3e4a2c78a5ca1e4812099e5083f815a8525ab20d389b560b3517f6b1161dd6",
49 | "https://deno.land/x/deno_cache@0.6.2/http_cache.ts": "407135eaf2802809ed373c230d57da7ef8dff923c4abf205410b9b99886491fd",
50 | "https://deno.land/x/deno_cache@0.6.2/lib/deno_cache_dir.generated.js": "59f8defac32e8ebf2a30f7bc77e9d88f0e60098463fb1b75e00b9791a4bbd733",
51 | "https://deno.land/x/deno_cache@0.6.2/lib/snippets/deno_cache_dir-a2aecaa9536c9402/fs.js": "cbe3a976ed63c72c7cb34ef845c27013033a3b11f9d8d3e2c4aa5dda2c0c7af6",
52 | "https://deno.land/x/deno_cache@0.6.2/mod.ts": "b4004287e1c6123d7f07fe9b5b3e94ce6d990c4102949a89c527c68b19627867",
53 | "https://deno.land/x/deno_cache@0.6.2/util.ts": "f3f5a0cfc60051f09162942fb0ee87a0e27b11a12aec4c22076e3006be4cc1e2",
54 | "https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66",
55 | "https://deno.land/x/dnt@0.40.0/lib/compiler.ts": "7f4447531581896348b8a379ab94730856b42ae50d99043f2468328360293cb1",
56 | "https://deno.land/x/dnt@0.40.0/lib/compiler_transforms.ts": "f21aba052f5dcf0b0595c734450842855c7f572e96165d3d34f8fed2fc1f7ba1",
57 | "https://deno.land/x/dnt@0.40.0/lib/mod.deps.ts": "8d6123c8e1162037e58aa8126686a03d1e2cffb250a8757bf715f80242097597",
58 | "https://deno.land/x/dnt@0.40.0/lib/npm_ignore.ts": "57fbb7e7b935417d225eec586c6aa240288905eb095847d3f6a88e290209df4e",
59 | "https://deno.land/x/dnt@0.40.0/lib/package_json.ts": "607b0a4f44acad071a4c8533b312a27d6671eac8e6a23625c8350ce29eadb2ba",
60 | "https://deno.land/x/dnt@0.40.0/lib/pkg/dnt_wasm.generated.js": "2694546844a50861d6d1610859afbf5130baca4dc6cf304541b7ec2d6d998142",
61 | "https://deno.land/x/dnt@0.40.0/lib/pkg/snippets/dnt-wasm-a15ef721fa5290c5/helpers.js": "aba69a019a6da6f084898a6c7b903b8b583bc0dbd82bfb338449cf0b5bce58fd",
62 | "https://deno.land/x/dnt@0.40.0/lib/shims.ts": "39e5c141f0315c0faf30b479b53f92b9078d92e1fd67ee34cc60b701d8e68dab",
63 | "https://deno.land/x/dnt@0.40.0/lib/test_runner/get_test_runner_code.ts": "4dc7a73a13b027341c0688df2b29a4ef102f287c126f134c33f69f0339b46968",
64 | "https://deno.land/x/dnt@0.40.0/lib/test_runner/test_runner.ts": "4d0da0500ec427d5f390d9a8d42fb882fbeccc92c92d66b6f2e758606dbd40e6",
65 | "https://deno.land/x/dnt@0.40.0/lib/transform.deps.ts": "2e159661e1c5c650de9a573babe0e319349fe493105157307ec2ad2f6a52c94e",
66 | "https://deno.land/x/dnt@0.40.0/lib/types.ts": "b8e228b2fac44c2ae902fbb73b1689f6ab889915bd66486c8a85c0c24255f5fb",
67 | "https://deno.land/x/dnt@0.40.0/lib/utils.ts": "224f15f33e7226a2fd991e438d0291d7ed8c7889807efa2e1ecb67d2d1db6720",
68 | "https://deno.land/x/dnt@0.40.0/mod.ts": "ae1890fbe592e4797e7dd88c1e270f22b8334878e9bf187c4e11ae75746fe778",
69 | "https://deno.land/x/dnt@0.40.0/transform.ts": "f68743a14cf9bf53bfc9c81073871d69d447a7f9e3453e0447ca2fb78926bb1d",
70 | "https://deno.land/x/ts_morph@20.0.0/bootstrap/mod.ts": "b53aad517f106c4079971fcd4a81ab79fadc40b50061a3ab2b741a09119d51e9",
71 | "https://deno.land/x/ts_morph@20.0.0/bootstrap/ts_morph_bootstrap.js": "6645ac03c5e6687dfa8c78109dc5df0250b811ecb3aea2d97c504c35e8401c06",
72 | "https://deno.land/x/ts_morph@20.0.0/common/DenoRuntime.ts": "6a7180f0c6e90dcf23ccffc86aa8271c20b1c4f34c570588d08a45880b7e172d",
73 | "https://deno.land/x/ts_morph@20.0.0/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed",
74 | "https://deno.land/x/ts_morph@20.0.0/common/ts_morph_common.js": "2325f94f61dc5f3f98a1dab366dc93048d11b1433d718b10cfc6ee5a1cfebe8f",
75 | "https://deno.land/x/ts_morph@20.0.0/common/typescript.js": "b9edf0a451685d13e0467a7ed4351d112b74bd1e256b915a2b941054e31c1736",
76 | "https://deno.land/x/wasmbuild@0.15.1/cache.ts": "9d01b5cb24e7f2a942bbd8d14b093751fa690a6cde8e21709ddc97667e6669ed",
77 | "https://deno.land/x/wasmbuild@0.15.1/loader.ts": "8c2fc10e21678e42f84c5135d8ab6ab7dc92424c3f05d2354896a29ccfd02a63"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------
1 | // deno-fmt-ignore-file
2 | import { Command } from "https://deno.land/x/cliffy@v0.25.7/command/command.ts";
3 | import { resolve } from "https://deno.land/std@0.181.0/path/mod.ts";
4 | import {
5 | getUnityChangeset,
6 | listChangesets,
7 | SearchMode,
8 | FilterOptions,
9 | GroupMode,
10 | OutputMode,
11 | FormatMode,
12 | } from "./index.ts";
13 |
14 | function getPackageVersion(): string {
15 | try {
16 | return JSON.parse(Deno.readTextFileSync(
17 | resolve(new URL(import.meta.url).pathname, "../../package.json"),
18 | )).version;
19 | } catch {
20 | return "-";
21 | }
22 | }
23 |
24 | new Command()
25 | /*
26 | * Main command
27 | */
28 | .name("unity-changeset")
29 | .version(getPackageVersion)
30 | .description("Find Unity changesets.")
31 | .example("unity-changeset 2018.4.36f1", "Get changeset of Unity 2018.4.36f1 ('6cd387d23174' will be output).")
32 | .arguments("")
33 | .action((_, version) => {
34 | getUnityChangeset(version)
35 | .then((c) => console.log(c.changeset))
36 | .catch(() => {
37 | console.error("The given version was not found.");
38 | Deno.exit(1);
39 | });
40 | })
41 | /*
42 | * Sub command: list.
43 | */
44 | .command(
45 | "list",
46 | new Command()
47 | .description("List Unity changesets.")
48 | .example("unity-changeset list", "List changesets.")
49 | .example("unity-changeset list --all --json", "List changesets of all versions in json format.")
50 | .example("unity-changeset list --version-only --min 2018.3 --max 2019.4", "List all versions from 2018.3 to 2019.4.")
51 | .example("unity-changeset list --version-only --grep '(2018.4|2019.4)'", "List all versions in 2018.4 and 2019.4.")
52 | .example("unity-changeset list --lts --latest-patch", "List changesets of the latest patch versions (LTS only).")
53 | // Search options.
54 | .group("Search options")
55 | .option("--all", "Search all changesets (alpha/beta included)")
56 | .option("--pre-release, --beta", "Search only pre-release (alpha/beta) changesets", { conflicts: ["all", "lts", "xlts"] })
57 | .option("--lts", "Only the LTS versions", { conflicts: ["all", "pre-release", "xlts", "supported"] })
58 | .option("--xlts", "Only the LTS/XLTS versions (require 'Enterprise' or 'Industry' license to install XLTS version)", { conflicts: ["all", "pre-release", "lts", "supported"] })
59 | .option("--supported", "Only the supported versions (including Unity 6000)", { conflicts: ["all", "pre-release", "lts", "xlts"] })
60 | // Filter options.
61 | .group("Filter options")
62 | .option("--min ", "Minimum version (included)")
63 | .option("--max ", "Maximum version (included)")
64 | .option("--grep ", "Regular expression (e.g. '20(18|19).4.*')")
65 | .option("--latest-lifecycle", "Only the latest lifecycle (default)")
66 | .option("--all-lifecycles", "All lifecycles", { conflicts: ["latest-lifecycle"] })
67 | // Group options.
68 | .group("Group options")
69 | .option("--latest-patch", "The latest patch versions only")
70 | .option("--oldest-patch", "The oldest patch versions in lateat lifecycle only", { conflicts: ["latest-patch"] })
71 | // Output options.
72 | .group("Output options")
73 | .option("--version-only, --versions", "Outputs only the version (no changesets)")
74 | .option("--minor-version-only, --minor-versions", "Outputs only the minor version (no changesets)", { conflicts: ["version-only"] })
75 | .option("--json", "Output in json format")
76 | .option("--pretty-json", "Output in pretty json format")
77 | .action((options) => {
78 | // Search mode.
79 | const searchMode = options.all
80 | ? SearchMode.All
81 | : options.preRelease
82 | ? SearchMode.PreRelease
83 | : options.lts
84 | ? SearchMode.LTS
85 | : options.xlts
86 | ? SearchMode.XLTS
87 | : options.supported
88 | ? SearchMode.SUPPORTED
89 | : SearchMode.Default;
90 |
91 | // Group mode.
92 | const groupMode = (options.latestPatch || options.minorVersionOnly)
93 | ? GroupMode.LatestPatch
94 | : options.oldestPatch
95 | ? GroupMode.OldestPatch
96 | : GroupMode.All;
97 |
98 | // Filter options.
99 | const filterOptions: FilterOptions = {
100 | min: options.min || "",
101 | max: options.max || "",
102 | grep: options.grep || "",
103 | allLifecycles: (options.allLifecycles && !options.latestLifecycle)
104 | ? true
105 | : false,
106 | lts: options.lts || false,
107 | };
108 |
109 | // Output mode.
110 | const outputMode = options.versionOnly
111 | ? OutputMode.VersionOnly
112 | : options.minorVersionOnly
113 | ? OutputMode.MinorVersionOnly
114 | : OutputMode.Changeset;
115 |
116 | // Format mode.
117 | const formatMode = options.json
118 | ? FormatMode.Json
119 | : options.prettyJson
120 | ? FormatMode.PrettyJson
121 | : FormatMode.None;
122 |
123 | listChangesets(searchMode, filterOptions, groupMode, outputMode, formatMode)
124 | .then((result) => console.log(result));
125 | }),
126 | )
127 | /*
128 | * Run with arguments.
129 | */
130 | .parse(Deno.args);
131 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { UnityChangeset as UnityChangesetClass } from "./unityChangeset.ts";
2 | import {
3 | getUnityReleases,
4 | getUnityReleasesInLTS,
5 | UnityReleaseEntitlement,
6 | UnityReleaseStream,
7 | } from "./unityGraphQL.ts";
8 |
9 | export const UnityChangeset = UnityChangesetClass;
10 | export type UnityChangeset = UnityChangesetClass;
11 |
12 | /*
13 | * Get an Unity changeset from specific Unity version.
14 | * @param version The Unity version.
15 | * @returns An Unity changeset.
16 | */
17 | export async function getUnityChangeset(
18 | version: string,
19 | ): Promise {
20 | const changesets = (await getUnityReleases(version, [])).filter(
21 | (c) => c.version === version,
22 | );
23 | if (0 < changesets.length) {
24 | return changesets[0];
25 | }
26 |
27 | throw Error(`The given version '${version}' was not found.`);
28 | }
29 |
30 | /*
31 | * Search mode.
32 | *
33 | * All: All changesets.
34 | * Default: Only non pre-release changesets.
35 | * PreRelease: Only pre-release (alpha/beta) changesets.
36 | */
37 | export enum SearchMode {
38 | All = 0,
39 | Default = 2,
40 | PreRelease = 3,
41 | LTS = 4,
42 | XLTS = 5,
43 | SUPPORTED = 6,
44 | }
45 |
46 | /*
47 | * Group mode.
48 | *
49 | * All: All the changesets.
50 | * OldestPatch: Only the oldest patch changesets.
51 | * LatestPatch: Only the latest patch changesets.
52 | * LatestLifecycle: Only the latest lifecycle changesets.
53 | */
54 | export enum GroupMode {
55 | All = "all",
56 | OldestPatch = "oldest-patch",
57 | LatestPatch = "latest-patch",
58 | LatestLifecycle = "latest-lifecycle",
59 | }
60 |
61 | /*
62 | * Filter options.
63 | *
64 | * min: The minimum version. eg. 2018.4
65 | * max: The maximum version. eg. 2019.4
66 | * grep: The grep pattern. eg. 20(18|19)
67 | * allLifecycles: Include all the lifecycles.
68 | * lts: Include only the LTS versions.
69 | */
70 | export interface FilterOptions {
71 | min: string;
72 | max: string;
73 | grep: string;
74 | allLifecycles: boolean;
75 | lts: boolean;
76 | }
77 |
78 | /*
79 | * Output mode.
80 | *
81 | * Changeset: The changeset.
82 | * VersionOnly: Only the version.
83 | * MinorVersionOnly: Only the minor version.
84 | */
85 | export enum OutputMode {
86 | Changeset = "changeset",
87 | VersionOnly = "version",
88 | MinorVersionOnly = "minor-version",
89 | }
90 |
91 | /*
92 | * Format mode.
93 | *
94 | * None: No format.
95 | * Json: JSON format.
96 | * PrettyJson: Pretty JSON format.
97 | */
98 | export enum FormatMode {
99 | None = "none",
100 | Json = "json",
101 | PrettyJson = "pretty-json",
102 | }
103 |
104 | export function listChangesets(
105 | searchMode: SearchMode,
106 | filterOptions: FilterOptions,
107 | groupMode: GroupMode,
108 | outputMode: OutputMode,
109 | formatMode: FormatMode,
110 | ): Promise {
111 | return searchChangesets(searchMode)
112 | .then((results) => filterChangesets(results, filterOptions))
113 | .then((results) =>
114 | results.sort((a, b) => b.versionNumber - a.versionNumber)
115 | )
116 | .then((results) => groupChangesets(results, groupMode))
117 | .then((results) => {
118 | switch (outputMode) {
119 | case OutputMode.Changeset:
120 | return results;
121 | case OutputMode.VersionOnly:
122 | return results.map((c) => c.version);
123 | case OutputMode.MinorVersionOnly:
124 | return results.map((c) => c.minor);
125 | default:
126 | throw Error(
127 | `The given output mode '${outputMode}' was not supported`,
128 | );
129 | }
130 | })
131 | .then((results) => {
132 | switch (formatMode) {
133 | case FormatMode.None:
134 | return results.join("\n");
135 | case FormatMode.Json:
136 | return JSON.stringify(results);
137 | case FormatMode.PrettyJson:
138 | return JSON.stringify(results, null, 2);
139 | default:
140 | throw Error(
141 | `The given format mode '${formatMode}' was not supported`,
142 | );
143 | }
144 | });
145 | }
146 |
147 | export function searchChangesets(
148 | searchMode: SearchMode,
149 | ): Promise {
150 | switch (searchMode) {
151 | case SearchMode.All:
152 | return getUnityReleases(".", [
153 | UnityReleaseStream.LTS,
154 | UnityReleaseStream.SUPPORTED,
155 | UnityReleaseStream.TECH,
156 | UnityReleaseStream.BETA,
157 | UnityReleaseStream.ALPHA,
158 | ]);
159 | case SearchMode.Default:
160 | return getUnityReleases(".", [
161 | UnityReleaseStream.LTS,
162 | UnityReleaseStream.SUPPORTED,
163 | UnityReleaseStream.TECH,
164 | ]);
165 | case SearchMode.PreRelease:
166 | return getUnityReleases(".", [
167 | UnityReleaseStream.BETA,
168 | UnityReleaseStream.ALPHA,
169 | ]);
170 | case SearchMode.LTS:
171 | return getUnityReleasesInLTS();
172 | case SearchMode.XLTS:
173 | return getUnityReleasesInLTS([UnityReleaseEntitlement.XLTS]);
174 | case SearchMode.SUPPORTED:
175 | return getUnityReleases(".", [UnityReleaseStream.SUPPORTED]);
176 | default:
177 | throw Error(`The given search mode '${searchMode}' was not supported`);
178 | }
179 | }
180 |
181 | export function filterChangesets(
182 | changesets: UnityChangeset[],
183 | options: FilterOptions,
184 | ): UnityChangeset[] {
185 | if (!changesets || changesets.length == 0) return [];
186 |
187 | // Min version number
188 | const min = options.min
189 | ? UnityChangeset.toNumber(options.min, false)
190 | : Number.MIN_VALUE;
191 | // Max version number
192 | const max = options.max
193 | ? UnityChangeset.toNumber(options.max, true)
194 | : Number.MAX_VALUE;
195 | // Grep pattern
196 | const regex = options.grep ? new RegExp(options.grep, "i") : null;
197 | // Lifecycle filter
198 | const lc = options.allLifecycles
199 | ? null
200 | : Object.values(groupBy(changesets, (r) => r.minor)).map((g) => g[0]);
201 |
202 | return changesets.filter(
203 | (c) =>
204 | min <= c.versionNumber &&
205 | c.versionNumber <= max &&
206 | (!options.lts || c.lts) &&
207 | (!regex || regex.test(c.version)) &&
208 | (!lc || lc.some((l) => l.minor == c.minor && l.lifecycle == c.lifecycle)),
209 | );
210 | }
211 |
212 | export function groupChangesets(
213 | changesets: UnityChangeset[],
214 | groupMode: GroupMode,
215 | ): UnityChangeset[] {
216 | if (!changesets || changesets.length == 0) return [];
217 |
218 | switch (groupMode) {
219 | case GroupMode.All:
220 | return changesets;
221 | case GroupMode.LatestLifecycle:
222 | return Object.values(groupBy(changesets, (r) => r.minor))
223 | .map((g) => g.filter((v) => v.lifecycle == g[0].lifecycle))
224 | .flat();
225 | case GroupMode.LatestPatch:
226 | return Object.values(groupBy(changesets, (r) => r.minor)).map(
227 | (g) => g[0],
228 | );
229 | case GroupMode.OldestPatch:
230 | return Object.values(groupBy(changesets, (r) => r.minor))
231 | .map((g) => g.filter((v) => v.lifecycle == g[0].lifecycle))
232 | .map((g) => g[g.length - 1]);
233 | default:
234 | throw Error(`The given group mode '${groupMode}' was not supported`);
235 | }
236 | }
237 |
238 | const groupBy = (arr: T[], key: (i: T) => K) =>
239 | arr.reduce((groups, item) => {
240 | (groups[key(item)] ||= []).push(item);
241 | return groups;
242 | }, {} as Record);
243 |
--------------------------------------------------------------------------------
/src/unityChangeset.test.ts:
--------------------------------------------------------------------------------
1 | // deno-fmt-ignore-file
2 | import {
3 | assertEquals,
4 | assertNotEquals,
5 | assertRejects,
6 | } from "https://deno.land/std@0.181.0/testing/asserts.ts";
7 | import {
8 | filterChangesets,
9 | getUnityChangeset,
10 | groupChangesets,
11 | searchChangesets,
12 | GroupMode,
13 | SearchMode,
14 | UnityChangeset,
15 | } from "./index.ts";
16 |
17 | Deno.test("UnityChangeset.toNumber min", () => {
18 | assertEquals(UnityChangeset.toNumber("2018.3", false), 201803000000);
19 | });
20 |
21 | Deno.test("UnityChangeset.toNumber max", () => {
22 | assertEquals(UnityChangeset.toNumber("2018.3", true), 201803992599);
23 | });
24 |
25 | // getUnityChangeset
26 | [
27 | { version: "2018.3.0f1", expected: "f023c421e164" },
28 | { version: "2018.3.0f2", expected: "6e9a27477296" },
29 | { version: "2018.3.0f3", expected: undefined },
30 | { version: "2019.1.0a9", expected: "0acd256790e8" },
31 | { version: "2019.1.0b1", expected: "83b3ba1f99df" },
32 | { version: "6000.1.0f1", expected: "9ea152932a88" },
33 | ].forEach((testcase) => {
34 | Deno.test(`getUnityChangeset (${testcase.version})`, async () => {
35 | if (testcase.expected) {
36 | const changeset = (await getUnityChangeset(testcase.version)).changeset;
37 | assertEquals(changeset, testcase.expected);
38 | }
39 | else {
40 | await assertRejects(() => getUnityChangeset(testcase.version));
41 | }
42 | })
43 | });
44 |
45 | Deno.test("scrapeArchivedChangesets", async () => {
46 | const changesets = await searchChangesets(SearchMode.Default);
47 | assertNotEquals(changesets.length, 0);
48 | });
49 |
50 | Deno.test("scrapeBetaChangesets", async () => {
51 | const changesets = await searchChangesets(SearchMode.PreRelease);
52 | console.log(changesets.map((c) => c.version));
53 | assertNotEquals(changesets.length, 0);
54 | });
55 |
56 | // At least one changeset from unity 6000 version should be found.
57 | Deno.test("scrapeUnity6000Supported", async () => {
58 | const changesets = await searchChangesets(SearchMode.SUPPORTED);
59 | console.log(changesets.map((c) => c.version));
60 | assertNotEquals(changesets.length, 0);
61 |
62 | const unity6000 = changesets.find(c => c.version.startsWith("6000"));
63 | assertNotEquals(unity6000, undefined);
64 | });
65 |
66 | // searchChangesets
67 | [
68 | { searchMode: SearchMode.All },
69 | { searchMode: SearchMode.Default },
70 | { searchMode: SearchMode.PreRelease },
71 | { searchMode: SearchMode.SUPPORTED },
72 | ].forEach((testcase) => {
73 | Deno.test(`filterChangesets(${JSON.stringify(testcase.searchMode)})`, async () => {
74 | const changesets = await searchChangesets(testcase.searchMode);
75 | assertNotEquals(changesets.length, 0);
76 | });
77 | });
78 |
79 | const changesetsForTest = [
80 | new UnityChangeset("2018.2.0f1", "000000000000"),
81 | new UnityChangeset("2018.2.1f1", "000000000000"),
82 | new UnityChangeset("2018.2.2f1", "000000000000"),
83 | new UnityChangeset("2018.3.0f1", "000000000000"),
84 | new UnityChangeset("2018.3.1f1", "000000000000"),
85 | new UnityChangeset("2018.3.2f1", "000000000000"),
86 | new UnityChangeset("2018.4.0f1", "000000000000", true),
87 | new UnityChangeset("2018.4.1f1", "000000000000", true),
88 | new UnityChangeset("2018.4.2f1", "000000000000", true),
89 | new UnityChangeset("2019.1.0a1", "000000000000"),
90 | new UnityChangeset("2019.1.0a2", "000000000000"),
91 | new UnityChangeset("2019.1.0b1", "000000000000"),
92 | new UnityChangeset("2019.1.0b2", "000000000000"),
93 | new UnityChangeset("2019.1.0f1", "000000000000"),
94 | new UnityChangeset("2019.1.0f2", "000000000000"),
95 | new UnityChangeset("2019.1.1f1", "000000000000"),
96 | new UnityChangeset("2019.2.0a1", "000000000000"),
97 | new UnityChangeset("2019.2.0a2", "000000000000"),
98 | new UnityChangeset("2019.2.0b1", "000000000000"),
99 | new UnityChangeset("2019.2.0b2", "000000000000"),
100 | new UnityChangeset("2019.2.0a1", "000000000000"),
101 | new UnityChangeset("2019.2.0a2", "000000000000"),
102 | ].sort((a, b) => b.versionNumber - a.versionNumber);
103 |
104 | // filterChangesets
105 | [
106 | { options: { min: "2018.3", max: "2018.4", grep: "", allLifecycles: false, lts: false, }, expected: 6, },
107 | { options: { min: "2018.3", max: "", grep: "2018", allLifecycles: false, lts: false, }, expected: 6, },
108 | { options: { min: "", max: "", grep: "", allLifecycles: false, lts: true }, expected: 3, },
109 | { options: { min: "2019", max: "", grep: "", allLifecycles: true, lts: false, }, expected: 13, },
110 | { options: { min: "2019", max: "", grep: "b", allLifecycles: true, lts: false, }, expected: 4, },
111 | ].forEach((testcase) => {
112 | Deno.test(`filterChangesets(${JSON.stringify(testcase.options)})`, () => {
113 | const changesets = filterChangesets(changesetsForTest, testcase.options);
114 | console.log(changesets.map((c) => `${c.version}`));
115 | assertEquals(changesets.length, testcase.expected);
116 | });
117 | });
118 |
119 | // groupChangesets
120 | [
121 | { groupMode: GroupMode.All, expected: 22 },
122 | { groupMode: GroupMode.LatestLifecycle, expected: 14 },
123 | { groupMode: GroupMode.LatestPatch, expected: 5 },
124 | { groupMode: GroupMode.OldestPatch, expected: 5 },
125 | ].forEach((testcase) => {
126 | Deno.test(`groupChangesets(${testcase.groupMode})`, () => {
127 | const changesets = groupChangesets(changesetsForTest, testcase.groupMode);
128 | console.log(changesets.map((c) => `${c.version}`));
129 | assertEquals(changesets.length, testcase.expected);
130 | });
131 | });
132 |
--------------------------------------------------------------------------------
/src/unityChangeset.ts:
--------------------------------------------------------------------------------
1 | const REGEXP_UNITY = /^(\d+)\.(\d+)\.(\d+)([a-zA-Z]+)(\d+)/;
2 | const REGEXP_UNITY_NUM = /^(\d+)\.?(\d+)?\.?(\d+)?([a-zA-Z]+)?(\d+)?/;
3 |
4 | /*
5 | Unity Changeset
6 | */
7 | export class UnityChangeset {
8 | version = "";
9 | changeset = "";
10 | versionNumber = 0;
11 | minor = "";
12 | lifecycle = "";
13 | lts = false;
14 |
15 | constructor(version: string, changeset: string, lts: boolean = false) {
16 | Object.assign(this, { version, changeset, lts });
17 |
18 | const match = this.version.match(REGEXP_UNITY);
19 | if (match) {
20 | this.versionNumber = UnityChangeset.toNumber(this.version, false);
21 | this.minor = `${match[1]}.${match[2]}`;
22 | this.lifecycle = `${match[4]}`;
23 | }
24 | }
25 |
26 | toString = (): string => {
27 | return `${this.version}\t${this.changeset}`;
28 | };
29 |
30 | static toNumber = (version: string, max: boolean): number => {
31 | const match = version.toString().match(REGEXP_UNITY_NUM);
32 | if (match === null) return 0;
33 |
34 | return parseInt(match[1] || (max ? "9999" : "0")) * 100 * 100 * 100 * 100 +
35 | parseInt(match[2] || (max ? "99" : "0")) * 100 * 100 * 100 +
36 | parseInt(match[3] || (max ? "99" : "0")) * 100 * 100 +
37 | ((match[4] || (max ? "z" : "a")).toUpperCase().charCodeAt(0) - 65) * 100 +
38 | parseInt(match[5] || (max ? "99" : "0"));
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/src/unityGraphQL.ts:
--------------------------------------------------------------------------------
1 | import { UnityChangeset } from "./unityChangeset.ts";
2 | import { gql, GraphQLClient } from "npm:graphql-request@6.1.0";
3 |
4 | const UNITY_GRAPHQL_ENDPOINT: string = "https://services.unity.com/graphql";
5 |
6 | export enum UnityReleaseStream {
7 | SUPPORTED = "SUPPORTED",
8 | LTS = "LTS",
9 | TECH = "TECH",
10 | BETA = "BETA",
11 | ALPHA = "ALPHA",
12 | }
13 |
14 | export enum UnityReleaseEntitlement {
15 | XLTS = "XLTS",
16 | U7_ALPHA = "U7_ALPHA",
17 | }
18 |
19 | interface UnityReleasesResponse {
20 | getUnityReleases: {
21 | totalCount: number;
22 | edges: { node: { version: string; shortRevision: string; stream: UnityReleaseStream } }[];
23 | pageInfo: { hasNextPage: boolean };
24 | };
25 | }
26 |
27 | interface UnityReleasesMajorVersionsResponse {
28 | getUnityReleaseMajorVersions: { version: string; }[];
29 | }
30 |
31 | export async function getUnityReleases(
32 | version: string,
33 | stream: UnityReleaseStream[] = [],
34 | entitlements: UnityReleaseEntitlement[] = []
35 | ): Promise {
36 | const client = new GraphQLClient(UNITY_GRAPHQL_ENDPOINT);
37 | const query = gql`
38 | query GetRelease($limit: Int, $skip: Int, $version: String!, $stream: [UnityReleaseStream!], $entitlements: [UnityReleaseEntitlement!])
39 | {
40 | getUnityReleases(
41 | limit: $limit
42 | skip: $skip
43 | stream: $stream
44 | version: $version
45 | entitlements: $entitlements
46 | ) {
47 | totalCount
48 | edges {
49 | node {
50 | version
51 | shortRevision
52 | stream
53 | }
54 | }
55 | pageInfo {
56 | hasNextPage
57 | }
58 | }
59 | }
60 | `;
61 |
62 | const variables = {
63 | limit: 250,
64 | skip: 0,
65 | version: version,
66 | stream: stream,
67 | entitlements: entitlements,
68 | };
69 |
70 | const results: UnityChangeset[] = [];
71 | while (true) {
72 | const data: UnityReleasesResponse = await client.request(query, variables);
73 | results.push(
74 | ...data.getUnityReleases.edges.map((edge) =>
75 | new UnityChangeset(edge.node.version, edge.node.shortRevision, edge.node.stream == UnityReleaseStream.LTS)
76 | ),
77 | );
78 | if (data.getUnityReleases.pageInfo.hasNextPage === false) {
79 | break;
80 | }
81 |
82 | variables.skip += variables.limit;
83 | }
84 |
85 | return results;
86 | }
87 |
88 | export async function getUnityReleasesInLTS(
89 | entitlements: UnityReleaseEntitlement[] = [],
90 | ): Promise {
91 | const client = new GraphQLClient(UNITY_GRAPHQL_ENDPOINT);
92 | const query = gql`
93 | query GetReleaseMajorVersions($entitlements: [UnityReleaseEntitlement!])
94 | {
95 | getUnityReleaseMajorVersions(
96 | stream: []
97 | platform: []
98 | architecture: []
99 | entitlements: $entitlements
100 | ) {
101 | version
102 | }
103 | }
104 | `;
105 |
106 | const variables = {
107 | entitlements: entitlements,
108 | };
109 |
110 | const data: UnityReleasesMajorVersionsResponse = await client.request(query, variables);
111 | const results = await Promise.all(data.getUnityReleaseMajorVersions
112 | .map(async (v) => {
113 | return await getUnityReleases(v.version, [UnityReleaseStream.LTS], entitlements);
114 | }));
115 |
116 | return results.flat();
117 | }
118 |
--------------------------------------------------------------------------------