├── .github
├── bump
├── dependabot.yml
├── scripts
│ ├── pre-commit.js
│ └── pre-commit
│ │ ├── build.sh
│ │ └── readme-update.sh
└── workflows
│ ├── build.yml
│ └── test.yml
├── .gitignore
├── .releaserc.js
├── CHANGELOG.md
├── LICENSE
├── README.md
├── action.yml
├── dist
├── index.js
└── licenses.txt
├── index.ts
├── main.ts
├── package-lock.json
├── package.json
├── test
├── integration.spec.ts
├── test.zip
└── utils.spec.ts
├── tsconfig.json
└── utils.ts
/.github/bump:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | versioning-strategy: "increase-if-necessary"
8 |
--------------------------------------------------------------------------------
/.github/scripts/pre-commit.js:
--------------------------------------------------------------------------------
1 | const {join} = require("path")
2 | const {readdir} = require("fs").promises
3 | const proc = require("child_process")
4 | const {promisify} = require("util")
5 |
6 | const exec = promisify(proc.exec)
7 |
8 | exports.preCommit = async ({tag, version}) => {
9 | process.env["BUILD_TAG"] = tag
10 | process.env["BUILD_VERSION"] = version
11 | let basedir = join(__dirname, 'pre-commit')
12 |
13 | let files = await readdir(basedir)
14 | files = files.map(file => join(basedir, file))
15 | files = files.map(file => exec(file))
16 | await Promise.all(files)
17 | }
18 |
--------------------------------------------------------------------------------
/.github/scripts/pre-commit/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | npm run build
3 |
--------------------------------------------------------------------------------
/.github/scripts/pre-commit/readme-update.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | perl -pi -e "s/JoshPiper\/GModStore-Deployment\@([\w.]+)?/JoshPiper\/GModStore-Deployment\@$BUILD_TAG/g" README.md
3 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Builds
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | build:
10 | name: Build
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: '>=20.0.0'
18 | - name: Install Dependencies
19 | run: npm ci
20 | - name: Build Release
21 | run: npm run release
22 | env:
23 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
24 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: workflow_dispatch
4 |
5 | jobs:
6 | test:
7 | name: Test
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v4
12 | - name: Install Dependencies
13 | run: npm ci && npm run build
14 | - name: Test
15 | uses: ./
16 | with:
17 | product: ${{ secrets.GMS_ADDON_ID }}
18 | token: ${{ secrets.GMS_TOKEN }}
19 | version: 1.0.0
20 | type: private
21 | path: tests/test.zip
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea/
3 |
--------------------------------------------------------------------------------
/.releaserc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "branches": [
3 | "main",
4 | "build/semantic-release"
5 | ],
6 | "plugins": [
7 | ["@semantic-release/commit-analyzer", {
8 | "parserOpts": {
9 | "headerPattern": /^(\w*)(?:\((.*)\))?: (.*)$/,
10 | "breakingHeaderPattern": /^(\w*)(?:\((.*)\))?!: (.*)$/
11 | },
12 | "releaseRules": [{
13 | "type": "*!",
14 | "release": "major"
15 | }, {
16 | "type": "build",
17 | "scope": "*deps",
18 | "release": "patch"
19 | }]
20 | }],
21 | ["@semantic-release/exec", {
22 | prepareCmd: "npm run build"
23 | }],
24 | ["@semantic-release/exec", {
25 | prepareCmd: 'perl -pi -e "s/JoshPiper\\/deployment-for-gmodstore\\@([\\w.]+)?/JoshPiper\\/deployment-for-gmodstore\\@v${nextRelease.version}/g" README.md'
26 | }],
27 | ["@semantic-release/exec", {
28 | prepareCmd: 'git commit -am "chore: Prepare ${nextRelease.version}" && git push'
29 | }],
30 | ["@semantic-release/release-notes-generator", {
31 | "parserOpts": {
32 | "headerPattern": /^(\w*)(?:\((.*)\))?!?: (.*)$/,
33 | "breakingHeaderPattern": /^(\w*)(?:\((.*)\))?!: (.*)$/
34 | },
35 | "writerOpts": {
36 | "transform": (commit, context) => {
37 | let discard = false
38 | const issues = []
39 |
40 | if (commit.type === 'chore'){
41 | discard = true
42 | }
43 |
44 | commit.notes.forEach(note => {
45 | note.title = 'BREAKING CHANGES'
46 | discard = false
47 | })
48 |
49 | if (commit.type === 'feat') {
50 | commit.type = 'Features'
51 | } else if (commit.type === 'fix') {
52 | commit.type = 'Bug Fixes'
53 | } else if (commit.type === 'perf') {
54 | commit.type = 'Performance Improvements'
55 | } else if (commit.type === 'revert' || commit.revert) {
56 | commit.type = 'Reverts'
57 | } else if (discard) {
58 | return
59 | } else if (commit.type === 'docs') {
60 | commit.type = 'Documentation'
61 | } else if (commit.type === 'style') {
62 | commit.type = 'Styles'
63 | } else if (commit.type === 'refactor') {
64 | commit.type = 'Code Refactoring'
65 | } else if (commit.type === 'test' || commit.type === 'tests') {
66 | commit.type = 'Tests'
67 | } else if (commit.type === 'build') {
68 | if (commit.scope === 'dep' || commit.scope === 'deps'){
69 | commit.type = 'Dependencies'
70 | commit.scope = ''
71 | } else if (commit.scope === 'dev-dep' || commit.scope === 'dev-deps'){
72 | commit.type = 'Dependencies'
73 | commit.scope = 'development'
74 | } else {
75 | commit.type = 'Build System'
76 | }
77 | } else if (commit.type === 'ci') {
78 | commit.type = 'Continuous Integration'
79 | }
80 |
81 | if (commit.scope === '*') {
82 | commit.scope = ''
83 | }
84 |
85 | if (typeof commit.hash === 'string') {
86 | commit.shortHash = commit.hash.substring(0, 7)
87 | }
88 |
89 | if (typeof commit.subject === 'string') {
90 | let url = context.repository
91 | ? `${context.host}/${context.owner}/${context.repository}`
92 | : context.repoUrl
93 | if (url) {
94 | url = `${url}/issues/`
95 | // Issue URLs.
96 | commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => {
97 | issues.push(issue)
98 | return `[#${issue}](${url}${issue})`
99 | })
100 | }
101 | if (context.host) {
102 | // User URLs.
103 | commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => {
104 | if (username.includes('/')) {
105 | return `@${username}`
106 | }
107 |
108 | return `[@${username}](${context.host}/${username})`
109 | })
110 | }
111 | }
112 |
113 | // remove references that already appear in the subject
114 | commit.references = commit.references.filter(reference => {
115 | if (issues.indexOf(reference.issue) === -1) {
116 | return true
117 | }
118 |
119 | return false
120 | })
121 |
122 | return commit
123 | },
124 | }
125 | }],
126 | ["@semantic-release/github", {
127 | "successComment": false
128 | }]
129 | ]
130 | }
131 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [1.0.1](https://github.com//JoshPiper/GModStore-Deployment/compare/v1.0.0...v1.0.1) (2023-07-23)
2 |
3 |
4 | ### Bug Fixes
5 |
6 | * Corrected API Route. ([167d55e](https://github.com//JoshPiper/GModStore-Deployment/commit/167d55e3eb29c53fa45098c711dd29753dc0fcfd))
7 |
8 |
9 |
10 | # [1.0.0](https://github.com//JoshPiper/GModStore-Deployment/compare/v0.7.0...v1.0.0) (2022-12-02)
11 |
12 |
13 | * GMS API v3 (#53) ([a5df42b](https://github.com//JoshPiper/GModStore-Deployment/commit/a5df42b6276ff38c96a4ab5920dac0050e193c47)), closes [#53](https://github.com//JoshPiper/GModStore-Deployment/issues/53)
14 |
15 |
16 | ### BREAKING CHANGES
17 |
18 | * Addon input has been removed, and replaced with Product.
19 |
20 |
21 |
22 | # [0.7.0](https://github.com//JoshPiper/GModStore-Deployment/compare/v0.6.3...v0.7.0) (2022-03-22)
23 |
24 |
25 | ### Features
26 |
27 | * Display the error if a json decode error occurs. ([f381693](https://github.com//JoshPiper/GModStore-Deployment/commit/f3816935da8225f1381e14a7c4e47984c7bb4241))
28 |
29 |
30 |
31 | ## [0.6.3](https://github.com//JoshPiper/GModStore-Deployment/compare/v0.6.2...v0.6.3) (2021-06-10)
32 |
33 |
34 | ### Bug Fixes
35 |
36 | * guard against an invalid json response. ([#24](https://github.com//JoshPiper/GModStore-Deployment/issues/24)) ([a1272c2](https://github.com//JoshPiper/GModStore-Deployment/commit/a1272c20bfcf052f9798db95c1e16a0220441ab1))
37 |
38 |
39 |
40 | ## [0.6.2](https://github.com//JoshPiper/GModStore-Deployment/compare/v0.6.1...v0.6.2) (2021-05-04)
41 |
42 |
43 | ### Bug Fixes
44 |
45 | * Fixed Version-Type error. ([#19](https://github.com//JoshPiper/GModStore-Deployment/issues/19)) ([9e1eca0](https://github.com//JoshPiper/GModStore-Deployment/commit/9e1eca0bd8a278cf507d6d8eec9bef471f29a40b))
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) 2021, Joshua Piper
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GModStore Deployment Action
2 |
3 | Easily upload an addon build to GmodStore.
4 |
5 | ## Usage
6 | ```yml
7 | - name: Upload
8 | uses: JoshPiper/deployment-for-gmodstore@v1.0.3
9 | with:
10 | product: "00000000-0000-0000-0000-000000000000"
11 | token: "${{ secrets.GMS_TOKEN }}"
12 | version: "1.0.0"
13 | path: "addon.zip"
14 | ```
15 |
16 | ## Inputs
17 |
18 | | Input | State | Description |
19 | |-----------|---------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
20 | | token | | Your GmodStore API Token.
This token must have versions write permission. |
21 | | product | | The product ID, found in the product dashboard. |
22 | | path | | Path to zip file to upload. |
23 | | version | | The new version name to upload.
This input is limited to 80 characters.
If type is not set, this input is parsed as a SemVer to find a pre-release suffix to use as type instead. |
24 | | type | Default: "stable"
Enum: ["stable", "beta", "alpha", "private", "demo"] | Type of version to release. |
25 | | changelog | Default: "No changelog provided." | Markdown formatted changelog. |
26 | | baseurl | Default: https://api.gmodstore.com/v3/ | Base API URL, for mocking or local proxy. |
27 | | dryrun | Default: FALSE | If we should dry-run and handle all the prep, but refrain from the actual upload. |
28 | | nointuit | Default: FALSE | Disable attempting to intuit the type field from the version field. |
29 |
--------------------------------------------------------------------------------
/action.yml:
--------------------------------------------------------------------------------
1 | name: "Deployment-For-gmodstore"
2 | description: "Deploy scripts to gmodstore"
3 | author: "Joshua Piper "
4 | branding:
5 | icon: check
6 | color: blue
7 |
8 | runs:
9 | using: node20
10 | main: "dist/index.js"
11 |
12 | inputs:
13 | token:
14 | description: "GModStore API Token"
15 | required: true
16 | product:
17 | description: "The ID of the addon to deploy to."
18 | required: true
19 | version:
20 | description: "The new version name to deploy."
21 | required: true
22 | type:
23 | description: "The type of version to deploy. Can be stable, beta, alpha, private or demo. If omitted, uses '-type' at the end of version string (if it exists), otherwise uses stable"
24 | required: false
25 | default: "stable"
26 | changelog:
27 | description: "Markdown formatted changelog."
28 | required: true
29 | default: "No changelog."
30 | path:
31 | description: "Path to the addon. This must be in zip format."
32 | required: true
33 | baseurl:
34 | description: "API Base URL"
35 | required: true
36 | default: "https://api.gmodstore.com/v3/"
37 |
--------------------------------------------------------------------------------
/dist/licenses.txt:
--------------------------------------------------------------------------------
1 | @actions/core
2 | MIT
3 | The MIT License (MIT)
4 |
5 | Copyright 2019 GitHub
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 |
13 | @actions/http-client
14 | MIT
15 | Actions Http Client for Node.js
16 |
17 | Copyright (c) GitHub, Inc.
18 |
19 | All rights reserved.
20 |
21 | MIT License
22 |
23 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
24 | associated documentation files (the "Software"), to deal in the Software without restriction,
25 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
26 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
27 | subject to the following conditions:
28 |
29 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
32 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
33 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
34 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
35 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 |
37 |
38 | @vercel/ncc
39 | MIT
40 | Copyright 2018 ZEIT, Inc.
41 |
42 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
43 |
44 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
45 |
46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47 |
48 | form-data-encoder
49 | MIT
50 | The MIT License (MIT)
51 |
52 | Copyright (c) 2021-present Nick K.
53 |
54 | Permission is hereby granted, free of charge, to any person obtaining a copy
55 | of this software and associated documentation files (the "Software"), to deal
56 | in the Software without restriction, including without limitation the rights
57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58 | copies of the Software, and to permit persons to whom the Software is
59 | furnished to do so, subject to the following conditions:
60 |
61 | The above copyright notice and this permission notice shall be included in all
62 | copies or substantial portions of the Software.
63 |
64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
70 | SOFTWARE.
71 |
72 |
73 | formdata-node
74 | MIT
75 | The MIT License (MIT)
76 |
77 | Copyright (c) 2017-present Nick K.
78 |
79 | Permission is hereby granted, free of charge, to any person obtaining a copy
80 | of this software and associated documentation files (the "Software"), to deal
81 | in the Software without restriction, including without limitation the rights
82 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
83 | copies of the Software, and to permit persons to whom the Software is
84 | furnished to do so, subject to the following conditions:
85 |
86 | The above copyright notice and this permission notice shall be included in all
87 | copies or substantial portions of the Software.
88 |
89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
95 | SOFTWARE.
96 |
97 |
98 | lru-cache
99 | ISC
100 | The ISC License
101 |
102 | Copyright (c) Isaac Z. Schlueter and Contributors
103 |
104 | Permission to use, copy, modify, and/or distribute this software for any
105 | purpose with or without fee is hereby granted, provided that the above
106 | copyright notice and this permission notice appear in all copies.
107 |
108 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
111 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
112 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
113 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
114 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
115 |
116 |
117 | node-fetch
118 | MIT
119 | The MIT License (MIT)
120 |
121 | Copyright (c) 2016 David Frank
122 |
123 | Permission is hereby granted, free of charge, to any person obtaining a copy
124 | of this software and associated documentation files (the "Software"), to deal
125 | in the Software without restriction, including without limitation the rights
126 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
127 | copies of the Software, and to permit persons to whom the Software is
128 | furnished to do so, subject to the following conditions:
129 |
130 | The above copyright notice and this permission notice shall be included in all
131 | copies or substantial portions of the Software.
132 |
133 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
134 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
135 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
136 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
137 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
138 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
139 | SOFTWARE.
140 |
141 |
142 |
143 | semver
144 | ISC
145 | The ISC License
146 |
147 | Copyright (c) Isaac Z. Schlueter and Contributors
148 |
149 | Permission to use, copy, modify, and/or distribute this software for any
150 | purpose with or without fee is hereby granted, provided that the above
151 | copyright notice and this permission notice appear in all copies.
152 |
153 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
154 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
155 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
156 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
157 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
159 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160 |
161 |
162 | tr46
163 | MIT
164 |
165 | tunnel
166 | MIT
167 | The MIT License (MIT)
168 |
169 | Copyright (c) 2012 Koichi Kobayashi
170 |
171 | Permission is hereby granted, free of charge, to any person obtaining a copy
172 | of this software and associated documentation files (the "Software"), to deal
173 | in the Software without restriction, including without limitation the rights
174 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
175 | copies of the Software, and to permit persons to whom the Software is
176 | furnished to do so, subject to the following conditions:
177 |
178 | The above copyright notice and this permission notice shall be included in
179 | all copies or substantial portions of the Software.
180 |
181 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
182 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
183 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
184 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
185 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
186 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
187 | THE SOFTWARE.
188 |
189 |
190 | uuid
191 | MIT
192 | The MIT License (MIT)
193 |
194 | Copyright (c) 2010-2020 Robert Kieffer and other contributors
195 |
196 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
197 |
198 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
199 |
200 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
201 |
202 |
203 | webidl-conversions
204 | BSD-2-Clause
205 | # The BSD 2-Clause License
206 |
207 | Copyright (c) 2014, Domenic Denicola
208 | All rights reserved.
209 |
210 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
211 |
212 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
213 |
214 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
215 |
216 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
217 |
218 |
219 | whatwg-url
220 | MIT
221 | The MIT License (MIT)
222 |
223 | Copyright (c) 2015–2016 Sebastian Mayr
224 |
225 | Permission is hereby granted, free of charge, to any person obtaining a copy
226 | of this software and associated documentation files (the "Software"), to deal
227 | in the Software without restriction, including without limitation the rights
228 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
229 | copies of the Software, and to permit persons to whom the Software is
230 | furnished to do so, subject to the following conditions:
231 |
232 | The above copyright notice and this permission notice shall be included in
233 | all copies or substantial portions of the Software.
234 |
235 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
236 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
237 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
238 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
239 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
240 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
241 | THE SOFTWARE.
242 |
243 |
244 | yallist
245 | ISC
246 | The ISC License
247 |
248 | Copyright (c) Isaac Z. Schlueter and Contributors
249 |
250 | Permission to use, copy, modify, and/or distribute this software for any
251 | purpose with or without fee is hereby granted, provided that the above
252 | copyright notice and this permission notice appear in all copies.
253 |
254 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
255 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
256 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
257 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
258 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
259 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
260 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
261 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // noinspection JSIgnoredPromiseFromCall
3 |
4 | import {main} from "./main"
5 | main()
6 |
--------------------------------------------------------------------------------
/main.ts:
--------------------------------------------------------------------------------
1 | import * as core from "@actions/core"
2 | import fetch from "node-fetch"
3 | import * as fs from "node:fs"
4 | import {
5 | token as getToken,
6 | product as getProduct,
7 | effectiveNameVersion as getVersion,
8 | path as getPath,
9 | changelog as getChangelog,
10 | baseUrl as getBaseUrl,
11 | dry as isDryRun
12 | } from "./utils";
13 | import {setFailed} from "@actions/core"
14 | import {FormData} from "formdata-node"
15 | // @ts-ignore
16 | import {FormDataEncoder} from "form-data-encoder"
17 | import {Readable} from "stream";
18 |
19 | async function main(){
20 | let token, product, version, versionType, path, changelog, baseUrl
21 | const dry = isDryRun()
22 | try {
23 | token = getToken()
24 | product = getProduct()
25 | let v = getVersion()
26 | version = v[0]
27 | versionType = v[1]
28 | path = getPath()
29 | changelog = getChangelog()
30 | baseUrl = getBaseUrl()
31 | } catch (err){
32 | setFailed(`An error occured during input processing.\n${err}`)
33 | return
34 | }
35 |
36 | FormData
37 |
38 | let newVersion = new FormData()
39 | newVersion.append("name", version)
40 | newVersion.append("changelog", changelog)
41 | newVersion.append("file", new Blob([fs.readFileSync(path)]), path)
42 | newVersion.append("releaseType", versionType)
43 | let encoder = new FormDataEncoder(newVersion)
44 |
45 | if (!dry){
46 | console.log(`${baseUrl}products/${product}/versions`)
47 | let response = await fetch(`${baseUrl}products/${product}/versions`, {
48 | method: "POST",
49 | body: Readable.from(encoder),
50 | headers: {
51 | "Authorization": `Bearer ${token}`,
52 | ...encoder.headers
53 | }
54 | })
55 |
56 | if (response.status < 200 || response.status >= 300){
57 | let body
58 | try {
59 | body = await response.json()
60 | } catch (e){
61 | core.warning("An error occurred whilst decoding the JSON response.")
62 | core.warning("This shouldn't normally happen, and suggests an issue with the API itself.")
63 | if (e instanceof Error || typeof e === "string"){
64 | core.error(e)
65 | }
66 |
67 | return
68 | }
69 |
70 | core.setFailed(`An error occurred during upload, with HTTP code ${response.status} and message "${body.message}".`)
71 | if (body.errors){
72 | for (let id of Object.keys(body.errors)){
73 | let errs = body.errors[id]
74 | let leng = errs.length
75 | if (leng === 1){
76 | core.error(`An error occurred in the ${id} field`)
77 | } else {
78 | core.error(`Errors occurred in the ${id} field`)
79 | }
80 | for (let i = 0; i < leng; i++){
81 | core.error(errs[i])
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 |
89 | export default main
90 | export {main}
91 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@doctor_internet/deployment-for-gmodstore",
3 | "version": "1.0.0",
4 | "description": "GitHub Action for deploying to GModStore.",
5 | "main": "index.js",
6 | "scripts": {
7 | "build:source": "npx ncc build index.ts --license licenses.txt",
8 | "build:source:clean": "rm dist/index.js dist/licenses.txt; rmdir dist",
9 | "build:source:watch": "npx ncc build --watch index.ts",
10 | "build:modules:clean": "((ls node_modules > /dev/null 2>&1) && rm -r ./node_modules) || true",
11 | "build": "npm run build:source",
12 | "build:full": "npm run build:modules:clean && npm run build:source:clean && npm ci && npm run build:source",
13 | "test": "npm run test:utils",
14 | "test:utils": "mocha -r ts-node/register test/utils.spec.ts",
15 | "release": "npx semantic-release"
16 | },
17 | "repository": {
18 | "type": "github",
19 | "url": "https://github.com/JoshPiper/deployment-for-gmodstore.git"
20 | },
21 | "keywords": [],
22 | "author": "John Internet ",
23 | "license": "ISC",
24 | "dependencies": {
25 | "@actions/core": "^1.11.1",
26 | "form-data-encoder": "^1.9.0",
27 | "formdata-node": "^6.0.3",
28 | "node-fetch": "^2.7.0",
29 | "semver": "^7.7.1",
30 | "uuid": "^11.1.0"
31 | },
32 | "devDependencies": {
33 | "@semantic-release/exec": "^7.0.3",
34 | "@tsconfig/node20": "^20.1.4",
35 | "@types/chai": "^5.0.1",
36 | "@types/mocha": "^10.0.10",
37 | "@types/node": "^22.13.8",
38 | "@types/node-fetch": "^2.6.6",
39 | "@types/semver": "^7.5.8",
40 | "@types/sinon": "^17.0.4",
41 | "@types/uuid": "^10.0.0",
42 | "@vercel/ncc": "^0.38.3",
43 | "chai": "^5.2.0",
44 | "mocha": "^11.1.0",
45 | "nyc": "^17.1.0",
46 | "semantic-release": "^24.2.3",
47 | "sinon": "^19.0.2",
48 | "ts-node": "^10.9.2",
49 | "typescript": "^5.7.3",
50 | "yaml": "^2.7.0"
51 | },
52 | "engines": {
53 | "node": ">=20.0.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/integration.spec.ts:
--------------------------------------------------------------------------------
1 | import { join } from "path"
2 | import main from "../main"
3 |
4 | describe('Integration', () => {
5 | it('Uploads the Test Folder', async () => {
6 | process.env['INPUT_PRODUCT'] = "46529d74-df19-4297-865f-6d11b6a787fd"
7 | process.env['INPUT_TOKEN'] = process.env['GMS_TOKEN']
8 | process.env['INPUT_VERSION'] = `v1.0.0-private+test:${(new Date().getTime())}`
9 | process.env['INPUT_TYPE'] = 'private'
10 | process.env['INPUT_PATH'] = join(__dirname, "test.zip")
11 | process.env['INPUT_CHANGELOG'] = `
12 | # Version ${process.env['INPUT_VERSION']}
13 |
14 | Test Upload from deployment-for-gmodstore.
15 | Uploaded At: ${(new Date()).toString()}
16 | `
17 | await main()
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/test/test.zip:
--------------------------------------------------------------------------------
1 | PK
--------------------------------------------------------------------------------
/test/utils.spec.ts:
--------------------------------------------------------------------------------
1 | import {assert} from "chai"
2 | import {effectiveNameVersion, token} from "../utils";
3 |
4 | describe('#effectiveNameVersion', () => {
5 | it('Parses Complex Versions', () => {
6 | process.env.INPUT_VERSION = "1.0.0-alpha.1.beta.2.private.1.demo"
7 | let [name, type] = effectiveNameVersion()
8 | assert.strictEqual(name, "1.0.0-alpha.1.beta.2.private.1.demo")
9 | assert.strictEqual(type, 'private')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@tsconfig/node20/tsconfig.json",
3 |
4 | "files": [
5 | "index.ts",
6 | "main.ts",
7 | "utils.ts"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/utils.ts:
--------------------------------------------------------------------------------
1 | import {getInput, InputOptions} from "@actions/core"
2 | import {validate as validUUID} from "uuid"
3 | import {parse} from "semver"
4 |
5 | /**
6 | * List of version suffixes, ordered in MOST to LEAST public.
7 | * Demo is accessible to all users.
8 | * Stable is accessible to all purchasers.
9 | * Etc
10 | */
11 | const VERSIONS = ['demo', 'stable', 'beta', 'alpha', 'private'] as const
12 | type Version = typeof VERSIONS[number]
13 | const VERSION_MAP = new Set(VERSIONS)
14 | const VERSION_REGEX = /(.*?)-(stable|beta|alpha|private|demo)$/gi
15 |
16 | const defaultOptions: InputOptions & ((extra: Partial) => InputOptions) = function (this: Partial, extra: Partial): InputOptions {
17 | return {...this, ...extra}
18 | }
19 | defaultOptions.required = true
20 | defaultOptions.trimWhitespace = true
21 |
22 | const optional = defaultOptions({required: false})
23 |
24 | export function token(): string {
25 | return getInput("token", defaultOptions)
26 | }
27 |
28 | export function product(): string {
29 | let pid = getInput("product", defaultOptions)
30 |
31 | if (!validUUID(pid)){
32 | throw "Input 'product' is not a valid UUID."
33 | }
34 |
35 | return pid
36 | }
37 |
38 | export function version(): string {
39 | return getInput("version", defaultOptions)
40 | }
41 |
42 | export function hasType(): boolean {
43 | return getInput("type", optional).toLowerCase() !== ""
44 | }
45 |
46 | export function type(): Version {
47 | const type = getInput("type", optional).toLowerCase()
48 | if (type === ""){
49 | return "stable"
50 | } else if (VERSION_MAP.has(type)) {
51 | return type
52 | }
53 |
54 | throw `Input 'type' must be one of ${[...VERSION_MAP.keys()].join(", ")}, got "${type}"`
55 | }
56 |
57 | export function path(): string {
58 | const path = getInput("path", defaultOptions)
59 | if (!path.endsWith(".zip")){
60 | throw "Input path must end in .zip"
61 | }
62 |
63 | return path
64 | }
65 |
66 | export function changelog(): string {
67 | const log = getInput("changelog", optional)
68 | if (log === ""){
69 | return "No changelog provided."
70 | }
71 |
72 | return log
73 | }
74 |
75 | export function baseUrl(): URL {
76 | let url = getInput("baseurl", optional)
77 | if (url === ""){
78 | url = "https://api.gmodstore.com/v3/"
79 | }
80 |
81 | return new URL(url)
82 | }
83 |
84 | export function dry(): boolean {
85 | return getInput("dryrun", optional).toLowerCase() === "true"
86 | }
87 |
88 | /**
89 | * Set if we should disable intuiting versions, and instead only use the type input.
90 | */
91 | export function nointuit(): boolean {
92 | return getInput("nointuit", optional).toLowerCase() === "true"
93 | }
94 |
95 | /**
96 | * Get the effective name and version to upload.
97 | * First, attempt to parse as semver.
98 | * If a single, non-numbered, pre-release version is encountered, which is a valid suffix, it is removed and used as the version type.
99 | * Otherwise, use the legacy regex.
100 | * Lastly, fall back to type input.
101 | */
102 | export function effectiveNameVersion(): string[] {
103 | const intuit = !nointuit()
104 | const raw = version()
105 |
106 | if (hasType()){
107 | return [version(), type()]
108 | }
109 |
110 | if (intuit){
111 | console.log("Intuiting")
112 | const ver = parse(raw)
113 | console.log(ver)
114 | if (ver !== null){
115 | let last: string | number | null = null
116 | const parsed = new Map()
117 | for (const value of ver.prerelease){
118 | if (typeof last === "string"){
119 | if (typeof value === "number"){
120 | parsed.set(last, value)
121 | last = null
122 | } else {
123 | parsed.set(last, 0)
124 | last = null
125 | }
126 | }
127 |
128 | if (typeof value === "string"){
129 | last = value
130 | }
131 | }
132 | if (last){
133 | parsed.set(last, 0)
134 | }
135 | console.log(parsed)
136 | for (const suffix of VERSIONS.toReversed()){
137 | if (parsed.has(suffix)){
138 | console.log(`has ${suffix}`)
139 | if (parsed.size !== 1 || parsed.get(suffix) !== 0){
140 | console.log("returning")
141 | return [ver.raw, suffix]
142 | } else {
143 | ver.prerelease = []
144 | return [ver.format(), suffix]
145 | }
146 | }
147 | }
148 | }
149 |
150 | const res = VERSION_REGEX.exec(version())
151 | if (res !== null){
152 | return [res[1], res[2]]
153 | }
154 | }
155 |
156 | return [version(), type()]
157 | }
158 |
--------------------------------------------------------------------------------