@cycjimmy/semantic-release-action 6.0.0 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -51
- package/action.yml +5 -5
- package/docs/CHANGELOG.md +38 -0
- package/index.js +14 -4
- package/package.json +7 -7
- package/src/_exec.js +4 -2
- package/src/assertSemanticReleaseVersion.task.js +22 -0
- package/src/cleanupNpmrc.task.js +2 -2
- package/src/handleError.js +32 -0
- package/src/handleOptions.js +76 -34
- package/src/index.js +23 -13
- package/src/inputs.json +2 -2
- package/src/installSpecifyingVersionSemantic.task.js +23 -8
- package/src/isNpmSpec.js +8 -0
- package/src/preInstall.task.js +34 -6
- package/src/runNpm.js +50 -0
- package/src/setUpJob.task.js +12 -7
- package/src/stringToJson.js +15 -0
- package/src/windUpJob.task.js +6 -7
package/README.md
CHANGED
|
@@ -18,16 +18,16 @@ GitHub Action for [Semantic Release][semantic-url].
|
|
|
18
18
|
```yaml
|
|
19
19
|
steps:
|
|
20
20
|
- name: Checkout
|
|
21
|
-
uses: actions/checkout@
|
|
21
|
+
uses: actions/checkout@v7
|
|
22
22
|
- name: Semantic Release
|
|
23
|
-
uses: cycjimmy/semantic-release-action@
|
|
23
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
24
24
|
env:
|
|
25
25
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
26
26
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
**IMPORTANT**: `GITHUB_TOKEN` does not have the required permissions to operate on protected branches.
|
|
30
|
-
If you are using this action for protected branches, replace `GITHUB_TOKEN` with [Personal Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). If using the `@semantic-release/git` plugin for protected branches, avoid persisting credentials as part of `actions/checkout@
|
|
30
|
+
If you are using this action for protected branches, replace `GITHUB_TOKEN` with [Personal Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). If using the `@semantic-release/git` plugin for protected branches, avoid persisting credentials as part of `actions/checkout@v7` by setting the parameter `persist-credentials: false`. This credential does not have the required permission to operate on protected branches.
|
|
31
31
|
|
|
32
32
|
#### Private Packages
|
|
33
33
|
|
|
@@ -45,27 +45,27 @@ then make sure that you configure this in your `package.json` file:
|
|
|
45
45
|
### Inputs
|
|
46
46
|
| Input Parameter | Required | Description |
|
|
47
47
|
|:-----------------:|:--------:|--------------------------------------------------------------------------------------------------------------------------|
|
|
48
|
-
| semantic_version | false | Specify version range for semantic-release. [[Details](#semantic_version)]
|
|
49
|
-
| branches | false | The branches on which releases should happen.[[Details](#branches)]<br>
|
|
50
|
-
| branch | false | The branch on which releases should happen.[[Details](#branch)]<br>Only support for **semantic-release older than v16**. |
|
|
48
|
+
| semantic_version | false | Specify version range for semantic-release (v16 or above required). [[Details](#semantic_version)] |
|
|
49
|
+
| branches | false | The branches on which releases should happen.[[Details](#branches)]<br>Requires **semantic-release v16 or above**. |
|
|
51
50
|
| extra_plugins | false | Extra plugins for pre-install. [[Details](#extra_plugins)] |
|
|
52
51
|
| dry_run | false | Whether to run semantic release in `dry-run` mode. [[Details](#dry_run)] |
|
|
53
|
-
| ci | false | Whether to run semantic release with CI support. [[Details](#ci)]
|
|
52
|
+
| ci | false | Whether to run semantic release with CI support. [[Details](#ci)] |
|
|
54
53
|
| unset_gha_env | false | Whether to unset the GITHUB_ACTIONS environment variable. |
|
|
55
54
|
| extends | false | Use a sharable configuration [[Details](#extends)] |
|
|
56
55
|
| working_directory | false | Use another working directory for semantic release [[Details](#working_directory)] |
|
|
57
56
|
| tag_format | false | Specify format of tag (useful for monorepos) |
|
|
58
57
|
| repository_url | false | The Git repository url. If no repository url specified, current repository will be used by default. |
|
|
58
|
+
| skip_npm_plugin | false | Whether to skip the @semantic-release/npm default plugin. [[Details](#skip_npm_plugin)]<br>Useful for non-Node.js projects. |
|
|
59
59
|
|
|
60
60
|
#### semantic_version
|
|
61
|
-
> {Optional Input Parameter} Specify version range for semantic-release.
|
|
61
|
+
> {Optional Input Parameter} Specify version range for semantic-release.<br>The minimum supported semantic-release version is **v16**; older versions fail with an error.
|
|
62
62
|
|
|
63
63
|
```yaml
|
|
64
64
|
steps:
|
|
65
65
|
- name: Checkout
|
|
66
|
-
uses: actions/checkout@
|
|
66
|
+
uses: actions/checkout@v7
|
|
67
67
|
- name: Semantic Release
|
|
68
|
-
uses: cycjimmy/semantic-release-action@
|
|
68
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
69
69
|
with:
|
|
70
70
|
semantic_version: 19.0.5 # It is recommended to specify a version range
|
|
71
71
|
# for semantic-release when using
|
|
@@ -75,20 +75,20 @@ steps:
|
|
|
75
75
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
If no version range is specified with `cycjimmy/semantic-release-action@
|
|
78
|
+
If no version range is specified with `cycjimmy/semantic-release-action@v7` then [semantic-release@latest](https://github.com/semantic-release/semantic-release/releases) is used.
|
|
79
79
|
|
|
80
80
|
#### branches
|
|
81
|
-
> {Optional Input Parameter} The branches on which releases should happen.<br>`branches`
|
|
81
|
+
> {Optional Input Parameter} The branches on which releases should happen.<br>`branches` requires **semantic-release v16 or above**.
|
|
82
82
|
|
|
83
83
|
```yaml
|
|
84
84
|
steps:
|
|
85
85
|
- name: Checkout
|
|
86
|
-
uses: actions/checkout@
|
|
86
|
+
uses: actions/checkout@v7
|
|
87
87
|
- name: Semantic Release
|
|
88
|
-
uses: cycjimmy/semantic-release-action@
|
|
88
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
89
89
|
with:
|
|
90
90
|
semantic_version: 16
|
|
91
|
-
# you can set branches for semantic-release above
|
|
91
|
+
# you can set branches for semantic-release v16 or above.
|
|
92
92
|
branches: |
|
|
93
93
|
[
|
|
94
94
|
'+([0-9])?(.{+([0-9]),x}).x',
|
|
@@ -123,25 +123,7 @@ steps:
|
|
|
123
123
|
|
|
124
124
|
See [configuration#branches](https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches) for more information.
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
> {Optional Input Parameter} Similar to parameter `branches`. The branch on which releases should happen.<br>`branch` only supports for **semantic-release older than v16**.
|
|
128
|
-
|
|
129
|
-
```yaml
|
|
130
|
-
steps:
|
|
131
|
-
- name: Checkout
|
|
132
|
-
uses: actions/checkout@v5
|
|
133
|
-
- name: Semantic Release
|
|
134
|
-
uses: cycjimmy/semantic-release-action@v6
|
|
135
|
-
with:
|
|
136
|
-
semantic_version: 15.13.28
|
|
137
|
-
# you can set branch for semantic-release older than v16.
|
|
138
|
-
branch: your-branch
|
|
139
|
-
env:
|
|
140
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
141
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
It will override the `branch` attribute in your configuration file. If the attribute is not configured on both sides, the default is `master`.
|
|
126
|
+
**NOTE**: The `branches` input is evaluated as a JavaScript expression to support the array/object configuration above. Only pass content you trust — anyone able to edit the workflow file can already run arbitrary commands in your CI.
|
|
145
127
|
|
|
146
128
|
#### extra_plugins
|
|
147
129
|
> {Optional Input Parameter} Extra plugins for pre-install.
|
|
@@ -154,9 +136,9 @@ Github Action Workflow:
|
|
|
154
136
|
```yaml
|
|
155
137
|
steps:
|
|
156
138
|
- name: Checkout
|
|
157
|
-
uses: actions/checkout@
|
|
139
|
+
uses: actions/checkout@v7
|
|
158
140
|
- name: Semantic Release
|
|
159
|
-
uses: cycjimmy/semantic-release-action@
|
|
141
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
160
142
|
with:
|
|
161
143
|
# You can specify specifying version range for the extra plugins if you prefer.
|
|
162
144
|
extra_plugins: |
|
|
@@ -169,6 +151,8 @@ steps:
|
|
|
169
151
|
|
|
170
152
|
Similar to parameter `semantic_version`. *It is recommended to manually specify a version of semantic-release plugins to prevent errors caused.*
|
|
171
153
|
|
|
154
|
+
**NOTE**: `extra_plugins` accepts npm package specs (e.g. `@semantic-release/git@10.0.0` or `@semantic-release/git@>=10.0.0`) separated by whitespace or newlines. Each spec is passed to `npm install` as a single argument without a shell; tokens starting with `-` or containing quotes or similar unsafe characters are ignored and reported as a warning. Because whitespace separates specs, version ranges containing spaces (e.g. `>=1.0.0 <2.0.0`) are not supported. The same rules apply to the `extends` input.
|
|
155
|
+
|
|
172
156
|
Release Config:
|
|
173
157
|
```diff
|
|
174
158
|
plugins: [
|
|
@@ -184,9 +168,9 @@ Release Config:
|
|
|
184
168
|
```yaml
|
|
185
169
|
steps:
|
|
186
170
|
- name: Checkout
|
|
187
|
-
uses: actions/checkout@
|
|
171
|
+
uses: actions/checkout@v7
|
|
188
172
|
- name: Semantic Release
|
|
189
|
-
uses: cycjimmy/semantic-release-action@
|
|
173
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
190
174
|
with:
|
|
191
175
|
dry_run: true
|
|
192
176
|
env:
|
|
@@ -194,15 +178,17 @@ steps:
|
|
|
194
178
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
195
179
|
```
|
|
196
180
|
|
|
181
|
+
**NOTE**: `dry-run` mode still requires write access to the repository. At startup, semantic-release verifies push permission by running `git push --dry-run` ([`verifyAuth`](https://github.com/semantic-release/semantic-release/blob/master/lib/git.js)), and GitHub enforces write access for dry-run pushes as well — nothing is actually pushed. If the credentials cannot push — for example, the default `GITHUB_TOKEN` when the job does not grant `permissions: contents: write` — the action fails with `EGITNOPERMISSION: Cannot push to the Git repository.` even in `dry-run` mode. To fix it, grant write permission to the job, e.g. `permissions: contents: write` (or use a token with write access).
|
|
182
|
+
|
|
197
183
|
#### ci
|
|
198
|
-
> {Optional Input Parameter} Whether to run semantic release with CI support (default true)
|
|
184
|
+
> {Optional Input Parameter} Whether to run semantic release with CI support (default true).
|
|
199
185
|
|
|
200
186
|
```yaml
|
|
201
187
|
steps:
|
|
202
188
|
- name: Checkout
|
|
203
|
-
uses: actions/checkout@
|
|
189
|
+
uses: actions/checkout@v7
|
|
204
190
|
- name: Semantic Release
|
|
205
|
-
uses: cycjimmy/semantic-release-action@
|
|
191
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
206
192
|
with:
|
|
207
193
|
ci: false
|
|
208
194
|
env:
|
|
@@ -218,9 +204,9 @@ The action can be used with `extends` option to extend an existing [sharable con
|
|
|
218
204
|
```yaml
|
|
219
205
|
steps:
|
|
220
206
|
- name: Checkout
|
|
221
|
-
uses: actions/checkout@
|
|
207
|
+
uses: actions/checkout@v7
|
|
222
208
|
- name: Semantic Release
|
|
223
|
-
uses: cycjimmy/semantic-release-action@
|
|
209
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
224
210
|
with:
|
|
225
211
|
# You can extend an existing shareable configuration.
|
|
226
212
|
# And you can specify version range for the shareable configuration if you prefer.
|
|
@@ -238,9 +224,9 @@ This action run semantic release in the github provided workspace by default. Yo
|
|
|
238
224
|
```yaml
|
|
239
225
|
steps:
|
|
240
226
|
- name: Checkout
|
|
241
|
-
uses: actions/checkout@
|
|
227
|
+
uses: actions/checkout@v7
|
|
242
228
|
- name: Semantic Release
|
|
243
|
-
uses: cycjimmy/semantic-release-action@
|
|
229
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
244
230
|
with:
|
|
245
231
|
# You can select another working directory like a subdirectory for example.
|
|
246
232
|
working_directory: ./code
|
|
@@ -255,9 +241,9 @@ The default tag format on semantic-release is `v{version}`. You can override tha
|
|
|
255
241
|
```yaml
|
|
256
242
|
steps:
|
|
257
243
|
- name: Checkout
|
|
258
|
-
uses: actions/checkout@
|
|
244
|
+
uses: actions/checkout@v7
|
|
259
245
|
- name: Semantic Release
|
|
260
|
-
uses: cycjimmy/semantic-release-action@
|
|
246
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
261
247
|
with:
|
|
262
248
|
tag_format: custom-v${version}
|
|
263
249
|
env:
|
|
@@ -271,7 +257,7 @@ Setting this to true will unset the `GITHUB_ACTIONS` environment variable. This
|
|
|
271
257
|
```yaml
|
|
272
258
|
steps:
|
|
273
259
|
- name: Checkout
|
|
274
|
-
uses: actions/checkout@
|
|
260
|
+
uses: actions/checkout@v7
|
|
275
261
|
- name: Temporarily merge PR branch
|
|
276
262
|
if: ${{ github.event_name == 'pull_request' }}
|
|
277
263
|
run: |
|
|
@@ -279,7 +265,7 @@ steps:
|
|
|
279
265
|
git config --global user.email github-actions@github.com
|
|
280
266
|
git merge --no-ff origin/${{ github.event.pull_request.head.ref }} --message "${{ github.event.pull_request.title }}"
|
|
281
267
|
- name: Semantic Release
|
|
282
|
-
uses: cycjimmy/semantic-release-action@
|
|
268
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
283
269
|
with:
|
|
284
270
|
unset_gha_env: ${{ github.event_name == 'pull_request' }}
|
|
285
271
|
ci: ${{ github.event_name == 'pull_request' && false || '' }}
|
|
@@ -288,6 +274,31 @@ steps:
|
|
|
288
274
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
289
275
|
```
|
|
290
276
|
|
|
277
|
+
#### skip_npm_plugin
|
|
278
|
+
> {Optional Input Parameter} Whether to skip the `@semantic-release/npm` default plugin.<br>Useful for running the action in a project that is not a Node.js project (i.e. without a `package.json` file).
|
|
279
|
+
|
|
280
|
+
```yaml
|
|
281
|
+
steps:
|
|
282
|
+
- name: Checkout
|
|
283
|
+
uses: actions/checkout@v7
|
|
284
|
+
- name: Semantic Release
|
|
285
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
286
|
+
with:
|
|
287
|
+
skip_npm_plugin: true
|
|
288
|
+
env:
|
|
289
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The `@semantic-release/npm` default plugin requires a `package.json` file in the working directory. Without one, semantic-release fails with `SemanticReleaseError: Missing package.json file.` (ENOPKG) — even in `dry-run` mode. Set `skip_npm_plugin: true` to remove the npm plugin from the default plugins. The default plugins are then replaced with the following list (the [default plugins](https://semantic-release.gitbook.io/semantic-release/usage/plugins#default-plugins) of semantic-release without `@semantic-release/npm`):
|
|
293
|
+
|
|
294
|
+
- `@semantic-release/commit-analyzer`
|
|
295
|
+
- `@semantic-release/release-notes-generator`
|
|
296
|
+
- `@semantic-release/github`
|
|
297
|
+
|
|
298
|
+
Similar to the other options, it will override the `plugins` attribute in your configuration file. If you already maintain your own `plugins` array in your release configuration, you don't need this input — just omit `@semantic-release/npm` from your array.
|
|
299
|
+
|
|
300
|
+
**NOTE**: `NPM_TOKEN` is not required when the npm plugin is skipped. Also note that configuring `npmPublish: false` or `private: true` on the npm plugin does **not** avoid the ENOPKG error, as the plugin checks for a `package.json` file before taking those settings into account. The only way to release a project without a `package.json` file is to not use the npm plugin at all.
|
|
301
|
+
|
|
291
302
|
### Outputs
|
|
292
303
|
| Output Parameter | Description |
|
|
293
304
|
|:-------------------------:|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
@@ -308,9 +319,9 @@ steps:
|
|
|
308
319
|
```yaml
|
|
309
320
|
steps:
|
|
310
321
|
- name: Checkout
|
|
311
|
-
uses: actions/checkout@
|
|
322
|
+
uses: actions/checkout@v7
|
|
312
323
|
- name: Semantic Release
|
|
313
|
-
uses: cycjimmy/semantic-release-action@
|
|
324
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
314
325
|
id: semantic # Need an `id` for output variables
|
|
315
326
|
env:
|
|
316
327
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -325,6 +336,24 @@ steps:
|
|
|
325
336
|
echo ${{ steps.semantic.outputs.new_release_patch_version }}
|
|
326
337
|
```
|
|
327
338
|
|
|
339
|
+
## Migration Notes
|
|
340
|
+
|
|
341
|
+
### The `branch` input has been removed
|
|
342
|
+
The `branch` input is no longer supported. Use the `branches` input instead:
|
|
343
|
+
|
|
344
|
+
```diff
|
|
345
|
+
- name: Semantic Release
|
|
346
|
+
uses: cycjimmy/semantic-release-action@v7
|
|
347
|
+
with:
|
|
348
|
+
- branch: your-branch
|
|
349
|
+
+ branches: your-branch
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
If the `branch` input is still passed, the action prints a deprecation warning and ignores it.
|
|
353
|
+
|
|
354
|
+
### semantic-release below v16 is no longer supported
|
|
355
|
+
This action now requires **semantic-release v16 or above**. If the installed semantic-release version is older (for example via `semantic_version: 15`), the action fails with an error. Update the `semantic_version` input to v16 or above, or remove it to use the latest version.
|
|
356
|
+
|
|
328
357
|
## Changelog
|
|
329
358
|
See [CHANGELOG][changelog-url].
|
|
330
359
|
|
package/action.yml
CHANGED
|
@@ -7,13 +7,10 @@ branding:
|
|
|
7
7
|
inputs:
|
|
8
8
|
semantic_version:
|
|
9
9
|
required: false
|
|
10
|
-
description: 'Specify specifying version range for semantic-release. If no version range is specified, latest version will be used by default'
|
|
10
|
+
description: 'Specify specifying version range for semantic-release (v16 or above required). If no version range is specified, latest version will be used by default'
|
|
11
11
|
branches:
|
|
12
12
|
required: false
|
|
13
|
-
description: 'The branches on which releases should happen. It will override the branches attribute in your configuration file.
|
|
14
|
-
branch:
|
|
15
|
-
required: false
|
|
16
|
-
description: 'The branch on which releases should happen. It will override the branch attribute in your configuration file. If the attribute is not configured on both sides, the default is master. Support for semantic-release older than v16.'
|
|
13
|
+
description: 'The branches on which releases should happen. It will override the branches attribute in your configuration file. Requires semantic-release v16 or above. See https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches for more information.'
|
|
17
14
|
extra_plugins:
|
|
18
15
|
required: false
|
|
19
16
|
description: 'Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer.'
|
|
@@ -38,6 +35,9 @@ inputs:
|
|
|
38
35
|
repository_url:
|
|
39
36
|
required: false
|
|
40
37
|
description: 'The Git repository url. If no repository url specified, current repository will be used by default.'
|
|
38
|
+
skip_npm_plugin:
|
|
39
|
+
required: false
|
|
40
|
+
description: 'Whether to skip the @semantic-release/npm default plugin. Useful for non-Node.js projects without a package.json file. When true, the default plugins are replaced with @semantic-release/commit-analyzer, @semantic-release/release-notes-generator and @semantic-release/github. It will override the plugins attribute in your configuration file.'
|
|
41
41
|
outputs:
|
|
42
42
|
new_release_published:
|
|
43
43
|
description: 'Whether a new release was published'
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
## [7.1.1](https://github.com/cycjimmy/semantic-release-action/compare/v7.1.0...v7.1.1) (2026-10-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **ci:** improve error handling for push permission failures ([895d556](https://github.com/cycjimmy/semantic-release-action/commit/895d556be9f4f2e382d2713f135c582cfd36d619)), closes [#312](https://github.com/cycjimmy/semantic-release-action/issues/312)
|
|
7
|
+
|
|
8
|
+
# [7.1.0](https://github.com/cycjimmy/semantic-release-action/compare/v7.0.0...v7.1.0) (2026-10-09)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **core:** add option to skip npm plugin for non-Node.js projects ([d1038bc](https://github.com/cycjimmy/semantic-release-action/commit/d1038bc60313f92bfcba1be105b18a41e4501b18)), closes [#313](https://github.com/cycjimmy/semantic-release-action/issues/313)
|
|
14
|
+
|
|
15
|
+
# [7.0.0](https://github.com/cycjimmy/semantic-release-action/compare/v6.0.0...v7.0.0) (2026-10-09)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **ci:** improve error handling and npm package installation ([b7ca30e](https://github.com/cycjimmy/semantic-release-action/commit/b7ca30e8f5630203651f721e521e114ee905bace))
|
|
21
|
+
* **release:** update GitHub Actions workflow for enhanced permissions and Node.js setup ([45d484c](https://github.com/cycjimmy/semantic-release-action/commit/45d484c29bc15ed2b7cb63b79fab2024d8f5e228))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* upgrade deps ([3341766](https://github.com/cycjimmy/semantic-release-action/commit/3341766fa2b64a1ede0f9e0fba9d8a63d57f26f2)), closes [#302](https://github.com/cycjimmy/semantic-release-action/issues/302)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Performance Improvements
|
|
30
|
+
|
|
31
|
+
* require semantic-release v16 or above and remove branch input ([3d0cb78](https://github.com/cycjimmy/semantic-release-action/commit/3d0cb78a35a8c728aaf92f57448f7a366a501728))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### BREAKING CHANGES
|
|
35
|
+
|
|
36
|
+
* require semantic-release v16 or above and remove branch input
|
|
37
|
+
* upgrade deps and use module type
|
|
38
|
+
|
|
1
39
|
# [6.0.0](https://github.com/cycjimmy/semantic-release-action/compare/v5.0.2...v6.0.0) (2025-11-17)
|
|
2
40
|
|
|
3
41
|
|
package/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import exec from './src/_exec.js';
|
|
2
|
+
import path, {dirname} from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
3
7
|
|
|
4
8
|
const run = async () => {
|
|
5
9
|
// Install Dependencies
|
|
@@ -13,7 +17,13 @@ const run = async () => {
|
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
const mod = await import('./src/index.js');
|
|
21
|
+
await mod.default();
|
|
17
22
|
};
|
|
18
23
|
|
|
19
|
-
run().catch(
|
|
24
|
+
run().catch((error) => {
|
|
25
|
+
console.error(error instanceof Error ? error.stack : error);
|
|
26
|
+
|
|
27
|
+
// Exit with a non-zero code so the workflow step is marked as failed
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
});
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cycjimmy/semantic-release-action",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.1.1",
|
|
4
4
|
"description": "GitHub Action for Semantic Release",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
9
|
},
|
|
@@ -21,11 +22,10 @@
|
|
|
21
22
|
},
|
|
22
23
|
"homepage": "https://github.com/cycjimmy/semantic-release-action#readme",
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@actions/core": "^
|
|
25
|
-
"@actions/io": "^
|
|
26
|
-
"@
|
|
27
|
-
"@semantic-release/
|
|
28
|
-
"
|
|
29
|
-
"semantic-release": "^25.0.2"
|
|
25
|
+
"@actions/core": "^3.0.1",
|
|
26
|
+
"@actions/io": "^3.0.2",
|
|
27
|
+
"@semantic-release/changelog": "^7.0.0",
|
|
28
|
+
"@semantic-release/git": "^11.0.1",
|
|
29
|
+
"semantic-release": "^25.0.9"
|
|
30
30
|
}
|
|
31
31
|
}
|
package/src/_exec.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
|
|
3
|
+
const MINIMUM_MAJOR_VERSION = 16;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Assert the installed semantic-release version is supported (v16 or above)
|
|
7
|
+
* @returns {Promise<void>}
|
|
8
|
+
* @throws {Error} when the installed semantic-release major version is below the minimum
|
|
9
|
+
*/
|
|
10
|
+
export default async () => {
|
|
11
|
+
const { default: { version } } = await import('semantic-release/package.json', { with: { type: 'json' } });
|
|
12
|
+
const majorVersion = Number(version.replace(/\..+/g, ''));
|
|
13
|
+
core.debug(`semantic-release version: ${version}`);
|
|
14
|
+
|
|
15
|
+
if (Number.isNaN(majorVersion) || majorVersion < MINIMUM_MAJOR_VERSION) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`Unsupported semantic-release version: ${version}. ` +
|
|
18
|
+
`This action requires semantic-release v${MINIMUM_MAJOR_VERSION} or above. ` +
|
|
19
|
+
`Update the 'semantic_version' input to v${MINIMUM_MAJOR_VERSION} or above, or remove it to use the latest version.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
};
|
package/src/cleanupNpmrc.task.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import * as io from '@actions/io';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Clean up `.npmrc` file in the repo after releasing
|
|
5
5
|
* @returns {Promise<never>}
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
export default async () => {
|
|
8
8
|
await io.rmRF('.npmrc');
|
|
9
9
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
|
|
3
|
+
const EGITNOPERMISSION_HINT =
|
|
4
|
+
`Push permission check failed (EGITNOPERMISSION). If you use the default GITHUB_TOKEN, ` +
|
|
5
|
+
`grant write access to the job, e.g. "permissions: contents: write". ` +
|
|
6
|
+
`This is also required in dry-run mode: semantic-release verifies push permission with "git push --dry-run". ` +
|
|
7
|
+
`See https://github.com/cycjimmy/semantic-release-action#dry_run`;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check whether an error, or any aggregated sub-error, has the given code.
|
|
11
|
+
* @param {Error|String} error
|
|
12
|
+
* @param {String} code
|
|
13
|
+
* @returns {Boolean}
|
|
14
|
+
*/
|
|
15
|
+
const hasErrorCode = (error, code) =>
|
|
16
|
+
error?.code === code ||
|
|
17
|
+
(Array.isArray(error?.errors) && error.errors.some((subError) => hasErrorCode(subError, code)));
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Report a failed release to GitHub Actions, adding extra hints for known semantic-release error codes.
|
|
21
|
+
* @param {Error|String} error
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
const handleError = (error) => {
|
|
25
|
+
if (hasErrorCode(error, 'EGITNOPERMISSION')) {
|
|
26
|
+
core.warning(EGITNOPERMISSION_HINT);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
core.setFailed(error);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default handleError;
|
package/src/handleOptions.js
CHANGED
|
@@ -1,51 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import stringToJson from './stringToJson.js';
|
|
4
|
+
import inputs from './inputs.json' with { type: 'json' };
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Handle Branches Option
|
|
7
|
-
* @returns {{}|{
|
|
8
|
+
* @returns {{}|{branches: string|Array}}
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
+
export const handleBranchesOption = () => {
|
|
10
11
|
const branchesOption = {};
|
|
11
12
|
const branches = core.getInput(inputs.branches);
|
|
12
|
-
const branch = core.getInput(inputs.branch);
|
|
13
|
-
|
|
14
13
|
core.debug(`branches input: ${branches}`);
|
|
15
|
-
core.debug(`branch input: ${branch}`);
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
if (!branches) {
|
|
16
|
+
return branchesOption;
|
|
17
|
+
}
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const jsonOrStr = stringToJson('' + branches);
|
|
20
|
+
core.debug(`Converted branches attribute: ${JSON.stringify(jsonOrStr)}`);
|
|
21
|
+
branchesOption.branches = jsonOrStr;
|
|
22
|
+
return branchesOption;
|
|
23
|
+
};
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Warn about removed legacy inputs. The `branch` input is no longer declared
|
|
27
|
+
* in action.yml; the runner still exports it as INPUT_BRANCH when users pass it.
|
|
28
|
+
*/
|
|
29
|
+
export const warnDeprecatedInputs = () => {
|
|
30
|
+
// hardcoded: 'branch' was removed from inputs.json
|
|
31
|
+
const branch = core.getInput('branch');
|
|
32
|
+
|
|
33
|
+
if (branch) {
|
|
34
|
+
core.warning(
|
|
35
|
+
`The 'branch' input is no longer supported and will be ignored. ` +
|
|
36
|
+
`Use the 'branches' input instead (requires semantic-release v16 or above). ` +
|
|
37
|
+
`See https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches`
|
|
38
|
+
);
|
|
29
39
|
}
|
|
40
|
+
};
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Warn when the working directory has no package.json and the npm default
|
|
44
|
+
* plugin is not skipped: @semantic-release/npm fails with ENOPKG in that case.
|
|
45
|
+
*/
|
|
46
|
+
export const warnIfNoPackageJson = () => {
|
|
47
|
+
const skipNpmPlugin = core.getInput(inputs.skip_npm_plugin) === 'true';
|
|
33
48
|
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
49
|
+
if (skipNpmPlugin || fs.existsSync('package.json')) {
|
|
50
|
+
return;
|
|
36
51
|
}
|
|
37
52
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
core.warning(
|
|
54
|
+
`No package.json file found in ${process.cwd()}. ` +
|
|
55
|
+
`The default @semantic-release/npm plugin requires one and will fail with ` +
|
|
56
|
+
`"Missing package.json file." (ENOPKG). ` +
|
|
57
|
+
`If this is not a Node.js project, set the 'skip_npm_plugin' input to true, ` +
|
|
58
|
+
`or define a custom 'plugins' array without @semantic-release/npm in your release configuration.`
|
|
59
|
+
);
|
|
42
60
|
};
|
|
43
61
|
|
|
44
62
|
/**
|
|
45
63
|
* Handle DryRun Option
|
|
46
64
|
* @returns {{}|{dryRun: boolean}}
|
|
47
65
|
*/
|
|
48
|
-
|
|
66
|
+
export const handleDryRunOption = () => {
|
|
49
67
|
const dryRun = core.getInput(inputs.dry_run);
|
|
50
68
|
core.debug(`dryRun input: ${dryRun}`);
|
|
51
69
|
|
|
@@ -65,7 +83,7 @@ exports.handleDryRunOption = () => {
|
|
|
65
83
|
* Handle Ci Option
|
|
66
84
|
* @returns {{}|{ci: boolean}}
|
|
67
85
|
*/
|
|
68
|
-
|
|
86
|
+
export const handleCiOption = () => {
|
|
69
87
|
const ci = core.getInput(inputs.ci);
|
|
70
88
|
core.debug(`ci input: ${ci}`);
|
|
71
89
|
|
|
@@ -85,7 +103,7 @@ exports.handleCiOption = () => {
|
|
|
85
103
|
* Handle Extends Option
|
|
86
104
|
* @returns {{}|{extends: Array}|{extends: String}}
|
|
87
105
|
*/
|
|
88
|
-
|
|
106
|
+
export const handleExtends = () => {
|
|
89
107
|
const extend = core.getInput(inputs.extends);
|
|
90
108
|
core.debug(`extend input: ${extend}`);
|
|
91
109
|
|
|
@@ -104,9 +122,9 @@ exports.handleExtends = () => {
|
|
|
104
122
|
* Handle TagFormat Option
|
|
105
123
|
* @returns {{}|{tagFormat: String}}
|
|
106
124
|
*/
|
|
107
|
-
|
|
125
|
+
export const handleTagFormat = () => {
|
|
108
126
|
const tagFormat = core.getInput(inputs.tag_format);
|
|
109
|
-
core.debug(`
|
|
127
|
+
core.debug(`tagFormat input: ${tagFormat}`);
|
|
110
128
|
|
|
111
129
|
if (tagFormat) {
|
|
112
130
|
return {
|
|
@@ -119,15 +137,39 @@ exports.handleTagFormat = () => {
|
|
|
119
137
|
|
|
120
138
|
/**
|
|
121
139
|
* Handle repository-url Option
|
|
122
|
-
* @returns {{}|{
|
|
140
|
+
* @returns {{}|{repositoryUrl: String}}
|
|
123
141
|
*/
|
|
124
|
-
|
|
142
|
+
export const handleRepositoryUrlOption = () => {
|
|
125
143
|
const repositoryUrl = core.getInput(inputs.repository_url);
|
|
126
144
|
core.debug(`repository_url input: ${repositoryUrl}`);
|
|
127
145
|
|
|
128
146
|
if (repositoryUrl) {
|
|
129
|
-
return {
|
|
147
|
+
return { repositoryUrl };
|
|
130
148
|
} else {
|
|
131
149
|
return {};
|
|
132
150
|
}
|
|
133
151
|
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Handle SkipNpmPlugin Option
|
|
155
|
+
* @returns {{}|{plugins: string[]}}
|
|
156
|
+
*/
|
|
157
|
+
export const handleSkipNpmPluginOption = () => {
|
|
158
|
+
const skipNpmPlugin = core.getInput(inputs.skip_npm_plugin);
|
|
159
|
+
core.debug(`skip_npm_plugin input: ${skipNpmPlugin}`);
|
|
160
|
+
|
|
161
|
+
switch (skipNpmPlugin) {
|
|
162
|
+
case 'true':
|
|
163
|
+
return {
|
|
164
|
+
plugins: [
|
|
165
|
+
'@semantic-release/commit-analyzer',
|
|
166
|
+
'@semantic-release/release-notes-generator',
|
|
167
|
+
'@semantic-release/github'
|
|
168
|
+
]
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
case 'false':
|
|
172
|
+
default:
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
import {
|
|
3
|
+
warnDeprecatedInputs,
|
|
4
|
+
warnIfNoPackageJson,
|
|
3
5
|
handleBranchesOption,
|
|
4
6
|
handleDryRunOption,
|
|
5
7
|
handleCiOption,
|
|
6
8
|
handleExtends,
|
|
7
9
|
handleTagFormat,
|
|
8
10
|
handleRepositoryUrlOption,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
handleSkipNpmPluginOption,
|
|
12
|
+
} from './handleOptions.js';
|
|
13
|
+
import handleError from './handleError.js';
|
|
14
|
+
import setUpJob from './setUpJob.task.js';
|
|
15
|
+
import installSpecifyingVersionSemantic from './installSpecifyingVersionSemantic.task.js';
|
|
16
|
+
import assertSemanticReleaseVersion from './assertSemanticReleaseVersion.task.js';
|
|
17
|
+
import preInstall from './preInstall.task.js';
|
|
18
|
+
import cleanupNpmrc from './cleanupNpmrc.task.js';
|
|
19
|
+
import windUpJob from './windUpJob.task.js';
|
|
20
|
+
import inputs from './inputs.json' with { type: 'json' };
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* Release main task
|
|
@@ -23,7 +28,10 @@ const release = async () => {
|
|
|
23
28
|
process.chdir(core.getInput(inputs.working_directory));
|
|
24
29
|
}
|
|
25
30
|
await setUpJob();
|
|
31
|
+
warnDeprecatedInputs();
|
|
32
|
+
warnIfNoPackageJson();
|
|
26
33
|
await installSpecifyingVersionSemantic();
|
|
34
|
+
await assertSemanticReleaseVersion();
|
|
27
35
|
await preInstall(core.getInput(inputs.extra_plugins));
|
|
28
36
|
await preInstall(core.getInput(inputs.extends));
|
|
29
37
|
|
|
@@ -33,20 +41,22 @@ const release = async () => {
|
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
const semanticRelease = await import('semantic-release');
|
|
44
|
+
const branchesOption = handleBranchesOption();
|
|
36
45
|
const result = await semanticRelease.default({
|
|
37
|
-
...
|
|
46
|
+
...branchesOption,
|
|
38
47
|
...handleDryRunOption(),
|
|
39
48
|
...handleCiOption(),
|
|
40
49
|
...handleExtends(),
|
|
41
50
|
...handleTagFormat(),
|
|
42
|
-
...handleRepositoryUrlOption()
|
|
51
|
+
...handleRepositoryUrlOption(),
|
|
52
|
+
...handleSkipNpmPluginOption()
|
|
43
53
|
});
|
|
44
54
|
|
|
45
55
|
await cleanupNpmrc();
|
|
46
56
|
await windUpJob(result);
|
|
47
57
|
};
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
export default async () => {
|
|
50
60
|
core.debug('Initialization successful');
|
|
51
|
-
release().catch(
|
|
61
|
+
release().catch(handleError);
|
|
52
62
|
};
|
package/src/inputs.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"semantic_version": "semantic_version",
|
|
3
3
|
"branches": "branches",
|
|
4
|
-
"branch": "branch",
|
|
5
4
|
"extra_plugins": "extra_plugins",
|
|
6
5
|
"dry_run": "dry_run",
|
|
7
6
|
"ci": "ci",
|
|
@@ -9,5 +8,6 @@
|
|
|
9
8
|
"extends": "extends",
|
|
10
9
|
"working_directory": "working_directory",
|
|
11
10
|
"tag_format": "tag_format",
|
|
12
|
-
"repository_url": "repository_url"
|
|
11
|
+
"repository_url": "repository_url",
|
|
12
|
+
"skip_npm_plugin": "skip_npm_plugin"
|
|
13
13
|
}
|
|
@@ -1,21 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
import runNpm from './runNpm.js';
|
|
3
|
+
import isNpmSpec from './isNpmSpec.js';
|
|
4
|
+
import inputs from './inputs.json' with { type: 'json' };
|
|
5
|
+
import path, {dirname} from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* Install Specifying Version semantic-release
|
|
8
13
|
* @returns {Promise<void>}
|
|
9
14
|
*/
|
|
10
|
-
|
|
15
|
+
export default async () => {
|
|
11
16
|
const semantic_version = core.getInput(inputs.semantic_version);
|
|
17
|
+
|
|
18
|
+
// Reject implausible version specs early (also prevents silently falling
|
|
19
|
+
// back to "latest"); the spec is passed to npm without a shell
|
|
20
|
+
if (semantic_version && !isNpmSpec(semantic_version)) {
|
|
21
|
+
throw new Error(`Invalid semantic_version input: ${semantic_version}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
const versionSuffix = semantic_version
|
|
13
25
|
? `@${semantic_version}`
|
|
14
26
|
: '';
|
|
15
27
|
|
|
16
|
-
const {stdout, stderr} = await
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
const {stdout, stderr} = await runNpm(
|
|
29
|
+
['install', `semantic-release${versionSuffix}`, '--no-audit', '--silent'],
|
|
30
|
+
{
|
|
31
|
+
cwd: path.resolve(__dirname, '..')
|
|
32
|
+
}
|
|
33
|
+
);
|
|
19
34
|
core.debug(stdout);
|
|
20
35
|
core.error(stderr);
|
|
21
36
|
};
|
package/src/isNpmSpec.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// isNpmSpec.js
|
|
2
|
+
// A plausible npm package/version spec: any characters except whitespace,
|
|
3
|
+
// quotes and other shell-like punctuation (kept as defense in depth even
|
|
4
|
+
// though the install commands run without a shell). A token starting with
|
|
5
|
+
// `-` is rejected so it can never be read as an npm option/flag.
|
|
6
|
+
const NPM_SPEC_PATTERN = /^[^\s'"`$;&(){}]+$/;
|
|
7
|
+
|
|
8
|
+
export default (spec) => !spec.startsWith('-') && NPM_SPEC_PATTERN.test(spec);
|
package/src/preInstall.task.js
CHANGED
|
@@ -1,20 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import path, {dirname} from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import * as core from '@actions/core';
|
|
4
|
+
import runNpm from './runNpm.js';
|
|
5
|
+
import isNpmSpec from './isNpmSpec.js';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Pre-install extra dependecies
|
|
7
12
|
* @returns {Promise<void>}
|
|
8
13
|
*/
|
|
9
|
-
|
|
14
|
+
export default async extras => {
|
|
10
15
|
if (!extras) {
|
|
11
16
|
return Promise.resolve();
|
|
12
17
|
}
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
// Split into tokens and keep only plausible npm package specs: specs are
|
|
20
|
+
// passed to npm without a shell, and tokens starting with `-` are dropped
|
|
21
|
+
// so they can never be read as npm options
|
|
22
|
+
const extrasList = extras
|
|
23
|
+
.replace(/['"]/g, '')
|
|
24
|
+
.split(/\s+/)
|
|
25
|
+
.filter(Boolean);
|
|
26
|
+
const validSpecs = extrasList.filter((spec) => isNpmSpec(spec));
|
|
27
|
+
const invalidTokens = extrasList.filter((spec) => !isNpmSpec(spec));
|
|
28
|
+
|
|
29
|
+
if (invalidTokens.length) {
|
|
30
|
+
core.warning(`Ignored invalid package specs: ${invalidTokens.join(', ')}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!validSpecs.length) {
|
|
34
|
+
return Promise.resolve();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
core.debug(`Installing extra packages: ${validSpecs.join(', ')}`);
|
|
38
|
+
|
|
15
39
|
const silentFlag = process.env.RUNNER_DEBUG === '1' ? '' : '--silent';
|
|
40
|
+
const args = ['install', ...validSpecs, '--no-audit'];
|
|
41
|
+
if (silentFlag) {
|
|
42
|
+
args.push(silentFlag);
|
|
43
|
+
}
|
|
16
44
|
|
|
17
|
-
const { stdout, stderr } = await
|
|
45
|
+
const { stdout, stderr } = await runNpm(args, {
|
|
18
46
|
cwd: path.resolve(__dirname, '..')
|
|
19
47
|
});
|
|
20
48
|
core.debug(stdout);
|
package/src/runNpm.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import { execFile } from 'child_process';
|
|
5
|
+
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
|
|
8
|
+
// npm's cli entry bundled with the running Node distribution. Running npm
|
|
9
|
+
// through the current Node executable keeps the invocation shell-free on
|
|
10
|
+
// every platform (spawning `npm.cmd` on Windows would require a shell).
|
|
11
|
+
const resolveNpmCliPath = () => {
|
|
12
|
+
const nodeDir = path.dirname(process.execPath);
|
|
13
|
+
|
|
14
|
+
// Layout of the official Node distributions:
|
|
15
|
+
// - Windows: <node-dir>/node_modules/npm/bin/npm-cli.js
|
|
16
|
+
// - POSIX: <node-dir>/../lib/node_modules/npm/bin/npm-cli.js
|
|
17
|
+
const npmCliPath = process.platform === 'win32'
|
|
18
|
+
? path.join(nodeDir, 'node_modules', 'npm', 'bin', 'npm-cli.js')
|
|
19
|
+
: path.join(nodeDir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
20
|
+
|
|
21
|
+
return fs.existsSync(npmCliPath) ? npmCliPath : '';
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Run npm with the given argument list without a shell.
|
|
26
|
+
* Every argument is passed as a single argv element, so user-provided
|
|
27
|
+
* package specs can never be interpreted as shell commands.
|
|
28
|
+
* @param {string[]} args
|
|
29
|
+
* @param {Object} [options] child_process options (e.g. cwd)
|
|
30
|
+
* @returns {Promise<{stdout: string, stderr: string}>}
|
|
31
|
+
*/
|
|
32
|
+
export default async (args, options = {}) => {
|
|
33
|
+
const npmCliPath = resolveNpmCliPath();
|
|
34
|
+
|
|
35
|
+
if (npmCliPath) {
|
|
36
|
+
return execFileAsync(process.execPath, [npmCliPath, ...args], options);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (process.platform === 'win32') {
|
|
40
|
+
// `npm` on Windows is npm.cmd, which cannot be spawned without a shell.
|
|
41
|
+
// Fail with a clear message instead of an opaque ENOENT.
|
|
42
|
+
throw new Error(
|
|
43
|
+
'Unable to locate npm-cli.js for the current Node installation on Windows. ' +
|
|
44
|
+
'semantic-release-action requires Node to be installed with npm bundled.'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Non-Windows fallback: plain `npm` executable from PATH
|
|
49
|
+
return execFileAsync('npm', args, options);
|
|
50
|
+
};
|
package/src/setUpJob.task.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import path, { dirname } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import * as core from '@actions/core';
|
|
4
|
+
import outputs from './outputs.json' with { type: 'json' };
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* setUpJob
|
|
7
11
|
* @returns {Promise<void>}
|
|
8
12
|
*/
|
|
9
|
-
|
|
10
|
-
// set outputs
|
|
13
|
+
export default async () => {
|
|
14
|
+
// set defaults for all outputs so they always exist
|
|
15
|
+
Object.values(outputs).forEach((output) => {
|
|
16
|
+
core.setOutput(output, '');
|
|
17
|
+
});
|
|
11
18
|
core.setOutput(outputs.new_release_published, 'false');
|
|
12
19
|
|
|
13
20
|
core.debug('action_workspace: ' + path.resolve(__dirname, '..'));
|
|
14
21
|
core.debug('process.cwd: ' + process.cwd());
|
|
15
|
-
|
|
16
|
-
return Promise.resolve();
|
|
17
22
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// stringToJson.js
|
|
2
|
+
// NOTE: The input string is evaluated as a JavaScript expression. This is
|
|
3
|
+
// required for backward compatibility with documented `branches` configs
|
|
4
|
+
// which use JS syntax (single-quoted strings, unquoted object keys), so it
|
|
5
|
+
// must only be fed with trusted input from the workflow file.
|
|
6
|
+
const strToJsonFunc = (str) => (new Function(`return ${str}`))();
|
|
7
|
+
const strToJson = (str) => {
|
|
8
|
+
try {
|
|
9
|
+
return strToJsonFunc(str);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return str;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default (str) => strToJson(str);
|
package/src/windUpJob.task.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as core from '@actions/core';
|
|
2
|
+
import outputs from './outputs.json' with { type: 'json' };
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* windUpJob
|
|
6
6
|
* @param result
|
|
7
7
|
* @returns {Promise<void>}
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!resolved) {
|
|
9
|
+
export default async (result) => {
|
|
10
|
+
if (!result) {
|
|
12
11
|
core.debug('No release published.');
|
|
13
12
|
return;
|
|
14
13
|
}
|
|
@@ -18,7 +17,7 @@ module.exports = async (result) => {
|
|
|
18
17
|
commits = [],
|
|
19
18
|
nextRelease = {},
|
|
20
19
|
releases = [],
|
|
21
|
-
} =
|
|
20
|
+
} = result;
|
|
22
21
|
|
|
23
22
|
if (lastRelease?.version) {
|
|
24
23
|
core.debug(`The last release was "${lastRelease.version}".`);
|
|
@@ -48,7 +47,7 @@ module.exports = async (result) => {
|
|
|
48
47
|
core.setOutput(outputs.new_release_minor_version, minor);
|
|
49
48
|
core.setOutput(outputs.new_release_patch_version, patch);
|
|
50
49
|
core.setOutput(outputs.new_release_channel, channel);
|
|
51
|
-
core.setOutput(outputs.new_release_notes, notes);
|
|
50
|
+
core.setOutput(outputs.new_release_notes, notes);
|
|
52
51
|
core.setOutput(outputs.new_release_git_head, gitHead);
|
|
53
52
|
core.setOutput(outputs.new_release_git_tag, gitTag);
|
|
54
53
|
};
|