mirror of
https://github.com/softprops/action-gh-release.git
synced 2025-12-09 21:37:53 +00:00
Compare commits
20 Commits
v2.4.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4399d47e47 | ||
|
|
60cfd9a691 | ||
|
|
69bd94bb12 | ||
|
|
8dca0e43c6 | ||
|
|
a06a81a03e | ||
|
|
7da8983734 | ||
|
|
87973286a4 | ||
|
|
1bfc62a71b | ||
|
|
5be0e66d93 | ||
|
|
af658b4d5d | ||
|
|
237aaccf71 | ||
|
|
00362bea6f | ||
|
|
0adea5aa98 | ||
|
|
aa05f9d779 | ||
|
|
bbaccb3a0c | ||
|
|
50fda3f773 | ||
|
|
5434409c2b | ||
|
|
6da8fa9354 | ||
|
|
f38efdea4c | ||
|
|
cec1a1113b |
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@@ -8,9 +8,9 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
|
||||||
|
|
||||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v4
|
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||||
with:
|
with:
|
||||||
node-version-file: ".tool-versions"
|
node-version-file: ".tool-versions"
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
nodejs 24.2.0
|
nodejs 24.11.0
|
||||||
|
|||||||
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,3 +1,36 @@
|
|||||||
|
## 2.5.0
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
|
||||||
|
### Exciting New Features 🎉
|
||||||
|
|
||||||
|
* feat: mark release as draft until all artifacts are uploaded by @dumbmoron in https://github.com/softprops/action-gh-release/pull/692
|
||||||
|
|
||||||
|
### Other Changes 🔄
|
||||||
|
|
||||||
|
* dependency updates
|
||||||
|
|
||||||
|
## 2.4.2
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
|
||||||
|
### Exciting New Features 🎉
|
||||||
|
|
||||||
|
* feat: Ensure generated release notes cannot be over 125000 characters by @BeryJu in https://github.com/softprops/action-gh-release/pull/684
|
||||||
|
|
||||||
|
### Other Changes 🔄
|
||||||
|
|
||||||
|
* dependency updates
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
|
||||||
|
### Other Changes 🔄
|
||||||
|
|
||||||
|
* fix(util): support brace expansion globs containing commas in parseInputFiles by @Copilot in https://github.com/softprops/action-gh-release/pull/672
|
||||||
|
* fix: gracefully fallback to body when body_path cannot be read by @Copilot in https://github.com/softprops/action-gh-release/pull/671
|
||||||
|
|
||||||
## 2.4.0
|
## 2.4.0
|
||||||
|
|
||||||
## What's Changed
|
## What's Changed
|
||||||
@@ -168,7 +201,7 @@
|
|||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
- `2.0.0`!? this release corrects a disjunction between git tag versions used in the marketplace and versions list this file. Previous versions should have really been 1.\*. Going forward this should be better aligned.
|
- `2.0.0`!? this release corrects a disjunction between git tag versions used in the marketplace and the versions listed in this file. Previous versions should have really been 1.\*. Going forward this should be better aligned.
|
||||||
- Upgrade action.yml declaration to node20 to address deprecations
|
- Upgrade action.yml declaration to node20 to address deprecations
|
||||||
|
|
||||||
## 0.1.15
|
## 0.1.15
|
||||||
@@ -179,7 +212,7 @@
|
|||||||
|
|
||||||
## 0.1.14
|
## 0.1.14
|
||||||
|
|
||||||
- provides an new workflow input option `generate_release_notes` which when set to true will automatically generate release notes for you based on GitHub activity [#179](https://github.com/softprops/action-gh-release/pull/179). Please see the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information
|
- provides a new workflow input option `generate_release_notes` which when set to true will automatically generate release notes for you based on GitHub activity [#179](https://github.com/softprops/action-gh-release/pull/179). Please see the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information
|
||||||
|
|
||||||
## 0.1.13
|
## 0.1.13
|
||||||
|
|
||||||
@@ -187,7 +220,7 @@
|
|||||||
|
|
||||||
## 0.1.12
|
## 0.1.12
|
||||||
|
|
||||||
- fix bug leading to empty strings subsituted for inputs users don't provide breaking api calls [#144](https://github.com/softprops/action-gh-release/pull/144)
|
- fix bug leading to empty strings substituted for inputs users don't provide breaking api calls [#144](https://github.com/softprops/action-gh-release/pull/144)
|
||||||
|
|
||||||
## 0.1.11
|
## 0.1.11
|
||||||
|
|
||||||
@@ -204,7 +237,7 @@
|
|||||||
## 0.1.8
|
## 0.1.8
|
||||||
|
|
||||||
- address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134)
|
- address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134)
|
||||||
- fix backwards compatibility with `GITHUB_TOKEN` resolution. `GITHUB_TOKEN` is no resolved first from an env varibale and then from and input [#133](https://github.com/softprops/action-gh-release/pull/133)
|
- fix backwards compatibility with `GITHUB_TOKEN` resolution. `GITHUB_TOKEN` is now resolved first from an env variable and then from an input [#133](https://github.com/softprops/action-gh-release/pull/133)
|
||||||
- trim white space in provided `tag_name` [#130](https://github.com/softprops/action-gh-release/pull/130)
|
- trim white space in provided `tag_name` [#130](https://github.com/softprops/action-gh-release/pull/130)
|
||||||
|
|
||||||
## 0.1.7
|
## 0.1.7
|
||||||
@@ -217,14 +250,14 @@
|
|||||||
|
|
||||||
This is a release catch up have a hiatus. Future releases will happen more frequently
|
This is a release catch up have a hiatus. Future releases will happen more frequently
|
||||||
|
|
||||||
- Add 'fail_on_unmatched_files' input, useful for catching cases were your `files` input does not actually match what you expect [#55](https://github.com/softprops/action-gh-release/pull/55)
|
- Add 'fail_on_unmatched_files' input, useful for catching cases where your `files` input does not actually match what you expect [#55](https://github.com/softprops/action-gh-release/pull/55)
|
||||||
- Add `repository` input, useful for creating a release in an external repository [#61](https://github.com/softprops/action-gh-release/pull/61)
|
- Add `repository` input, useful for creating a release in an external repository [#61](https://github.com/softprops/action-gh-release/pull/61)
|
||||||
- Add release `id` to outputs, useful for refering to release in workflow steps following the step that uses this action [#60](https://github.com/softprops/action-gh-release/pull/60)
|
- Add release `id` to outputs, useful for referring to release in workflow steps following the step that uses this action [#60](https://github.com/softprops/action-gh-release/pull/60)
|
||||||
- Add `upload_url` as action output, useful for managing uploads separately [#75](https://github.com/softprops/action-gh-release/pull/75)
|
- Add `upload_url` as action output, useful for managing uploads separately [#75](https://github.com/softprops/action-gh-release/pull/75)
|
||||||
- Support custom `target_commitish` value, useful to customize the default [#76](https://github.com/softprops/action-gh-release/pull/76)
|
- Support custom `target_commitish` value, useful to customize the default [#76](https://github.com/softprops/action-gh-release/pull/76)
|
||||||
- fix `body_path` input first then fall back on `body` input. this was the originally documented precedence but was implemened the the opposite order! [#85](https://github.com/softprops/action-gh-release/pull/85)
|
- fix `body_path` input first then fall back on `body` input. This was the originally documented precedence but was implemented in the opposite order! [#85](https://github.com/softprops/action-gh-release/pull/85)
|
||||||
- Retain original release info if the keys are not set, useful for filling in blanks for a release you've already started separately [#109](https://github.com/softprops/action-gh-release/pull/109)
|
- Retain original release info if the keys are not set, useful for filling in blanks for a release you've already started separately [#109](https://github.com/softprops/action-gh-release/pull/109)
|
||||||
- Limit number of times github api request to create a release is retried, useful for avoiding eating up your rate limit and action minutes do to either an invalid token or other circumstance causing the api call to fail [#111](https://github.com/softprops/action-gh-release/pull/111)
|
- Limit number of times github api request to create a release is retried, useful for avoiding eating up your rate limit and action minutes due to either an invalid token or other circumstance causing the api call to fail [#111](https://github.com/softprops/action-gh-release/pull/111)
|
||||||
|
|
||||||
## 0.1.5
|
## 0.1.5
|
||||||
|
|
||||||
@@ -234,7 +267,7 @@ This is a release catch up have a hiatus. Future releases will happen more frequ
|
|||||||
|
|
||||||
- Added support for updating releases body [#36](https://github.com/softprops/action-gh-release/pull/36)
|
- Added support for updating releases body [#36](https://github.com/softprops/action-gh-release/pull/36)
|
||||||
- Steps can now access the url of releases with the `url` output of this Action [#28](https://github.com/softprops/action-gh-release/pull/28)
|
- Steps can now access the url of releases with the `url` output of this Action [#28](https://github.com/softprops/action-gh-release/pull/28)
|
||||||
- Added basic GitHub API retry support to manage API turbulance [#26](https://github.com/softprops/action-gh-release/pull/26)
|
- Added basic GitHub API retry support to manage API turbulence [#26](https://github.com/softprops/action-gh-release/pull/26)
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
@@ -249,7 +282,7 @@ This is now fixed.
|
|||||||
|
|
||||||
- Add support for newline-delimited asset list [#18](https://github.com/softprops/action-gh-release/pull/18)
|
- Add support for newline-delimited asset list [#18](https://github.com/softprops/action-gh-release/pull/18)
|
||||||
|
|
||||||
GitHub actions inputs don't inherently support lists of things and one might like to append a list of files to include in a release. Previously this was possible using a comma-delimited list of asset path patterns to upload. You can now provide these as a newline delimieted list for better readability
|
GitHub actions inputs don't inherently support lists of things and one might like to append a list of files to include in a release. Previously this was possible using a comma-delimited list of asset path patterns to upload. You can now provide these as a newline delimited list for better readability
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Release
|
- name: Release
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -51,7 +51,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
if: github.ref_type == 'tag'
|
if: github.ref_type == 'tag'
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
```
|
```
|
||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
- name: Build
|
- name: Build
|
||||||
run: echo ${{ github.sha }} > Release.txt
|
run: echo ${{ github.sha }} > Release.txt
|
||||||
- name: Test
|
- name: Test
|
||||||
@@ -123,7 +123,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
- name: Build
|
- name: Build
|
||||||
run: echo ${{ github.sha }} > Release.txt
|
run: echo ${{ github.sha }} > Release.txt
|
||||||
- name: Test
|
- name: Test
|
||||||
@@ -157,7 +157,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@v6
|
||||||
- name: Generate Changelog
|
- name: Generate Changelog
|
||||||
run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
|
run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
|
||||||
- name: Release
|
- name: Release
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ describe('github', () => {
|
|||||||
getReleaseByTag: () => Promise.reject('Not implemented'),
|
getReleaseByTag: () => Promise.reject('Not implemented'),
|
||||||
createRelease: () => Promise.reject('Not implemented'),
|
createRelease: () => Promise.reject('Not implemented'),
|
||||||
updateRelease: () => Promise.reject('Not implemented'),
|
updateRelease: () => Promise.reject('Not implemented'),
|
||||||
|
finalizeRelease: () => Promise.reject('Not implemented'),
|
||||||
allReleases: async function* () {
|
allReleases: async function* () {
|
||||||
yield { data: [mockRelease] };
|
yield { data: [mockRelease] };
|
||||||
},
|
},
|
||||||
@@ -254,11 +255,12 @@ describe('github', () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
body: 'test',
|
body: 'test',
|
||||||
target_commitish: 'main',
|
target_commitish: 'main',
|
||||||
draft: false,
|
draft: true,
|
||||||
prerelease: false,
|
prerelease: false,
|
||||||
assets: [],
|
assets: [],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
finalizeRelease: async () => {},
|
||||||
allReleases: async function* () {
|
allReleases: async function* () {
|
||||||
yield {
|
yield {
|
||||||
data: [
|
data: [
|
||||||
|
|||||||
@@ -39,6 +39,18 @@ describe('util', () => {
|
|||||||
'loom',
|
'loom',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
it('handles globs with brace groups containing commas', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb,tar.gz}\nfoo,bar'), [
|
||||||
|
'./**/*.{exe,deb,tar.gz}',
|
||||||
|
'foo',
|
||||||
|
'bar',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('handles single-line brace pattern correctly', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb,tar.gz}'), [
|
||||||
|
'./**/*.{exe,deb,tar.gz}',
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('releaseBody', () => {
|
describe('releaseBody', () => {
|
||||||
it('uses input body', () => {
|
it('uses input body', () => {
|
||||||
@@ -110,6 +122,52 @@ describe('util', () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('falls back to body when body_path is missing', () => {
|
||||||
|
assert.equal(
|
||||||
|
releaseBody({
|
||||||
|
github_ref: '',
|
||||||
|
github_repository: '',
|
||||||
|
github_token: '',
|
||||||
|
input_body: 'fallback-body',
|
||||||
|
input_body_path: '__tests__/does-not-exist.txt',
|
||||||
|
input_draft: false,
|
||||||
|
input_prerelease: false,
|
||||||
|
input_files: [],
|
||||||
|
input_overwrite_files: undefined,
|
||||||
|
input_preserve_order: undefined,
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined,
|
||||||
|
input_generate_release_notes: false,
|
||||||
|
input_make_latest: undefined,
|
||||||
|
}),
|
||||||
|
'fallback-body',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('returns undefined when body_path is missing and body is not provided', () => {
|
||||||
|
assert.equal(
|
||||||
|
releaseBody({
|
||||||
|
github_ref: '',
|
||||||
|
github_repository: '',
|
||||||
|
github_token: '',
|
||||||
|
input_body: undefined,
|
||||||
|
input_body_path: '__tests__/does-not-exist.txt',
|
||||||
|
input_draft: false,
|
||||||
|
input_prerelease: false,
|
||||||
|
input_files: [],
|
||||||
|
input_overwrite_files: undefined,
|
||||||
|
input_preserve_order: undefined,
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined,
|
||||||
|
input_generate_release_notes: false,
|
||||||
|
input_make_latest: undefined,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe('parseConfig', () => {
|
describe('parseConfig', () => {
|
||||||
it('parses basic config', () => {
|
it('parses basic config', () => {
|
||||||
@@ -432,3 +490,36 @@ describe('util', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('parseInputFiles edge cases', () => {
|
||||||
|
it('handles multiple brace groups on same line', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('./**/*.{exe,deb},./dist/**/*.{zip,tar.gz}'), [
|
||||||
|
'./**/*.{exe,deb}',
|
||||||
|
'./dist/**/*.{zip,tar.gz}',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nested braces', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('path/{a,{b,c}}/file.txt'), ['path/{a,{b,c}}/file.txt']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty comma-separated values', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('foo,,bar'), ['foo', 'bar']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles commas with spaces around braces', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles(' ./**/*.{exe,deb} , file.txt '), [
|
||||||
|
'./**/*.{exe,deb}',
|
||||||
|
'file.txt',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles mixed newlines and commas with braces', () => {
|
||||||
|
assert.deepStrictEqual(parseInputFiles('file1.txt\n./**/*.{exe,deb},file2.txt\nfile3.txt'), [
|
||||||
|
'file1.txt',
|
||||||
|
'./**/*.{exe,deb}',
|
||||||
|
'file2.txt',
|
||||||
|
'file3.txt',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
4
dist/index.js
vendored
4
dist/index.js
vendored
File diff suppressed because one or more lines are too long
1585
package-lock.json
generated
1585
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "action-gh-release",
|
"name": "action-gh-release",
|
||||||
"version": "2.4.0",
|
"version": "2.5.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "GitHub Action for creating GitHub Releases",
|
"description": "GitHub Action for creating GitHub Releases",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
@@ -24,21 +24,21 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^6.0.1",
|
||||||
"@octokit/plugin-retry": "^8.0.2",
|
"@octokit/plugin-retry": "^8.0.3",
|
||||||
"@octokit/plugin-throttling": "^11.0.2",
|
"@octokit/plugin-throttling": "^11.0.3",
|
||||||
"glob": "^11.0.3",
|
"glob": "^13.0.0",
|
||||||
"mime-types": "^3.0.1"
|
"mime-types": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/glob": "^9.0.0",
|
"@types/glob": "^9.0.0",
|
||||||
"@types/mime-types": "^3.0.1",
|
"@types/mime-types": "^3.0.1",
|
||||||
"@types/node": "^20.19.19",
|
"@types/node": "^20.19.25",
|
||||||
"@vercel/ncc": "^0.38.4",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"@vitest/coverage-v8": "^3.2.4",
|
"@vitest/coverage-v8": "^4.0.14",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.7.3",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-formatter": "^7.2.2",
|
"typescript-formatter": "^7.2.2",
|
||||||
"vitest": "^3.1.4"
|
"vitest": "^4.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
106
src/github.ts
106
src/github.ts
@@ -58,6 +58,12 @@ export interface Releaser {
|
|||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
||||||
}): Promise<{ data: Release }>;
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
|
finalizeRelease(params: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
release_id: number;
|
||||||
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }>;
|
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +81,27 @@ export class GitHubReleaser implements Releaser {
|
|||||||
return this.github.rest.repos.getReleaseByTag(params);
|
return this.github.rest.repos.getReleaseByTag(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
createRelease(params: {
|
async getReleaseNotes(params: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
tag_name: string;
|
||||||
|
target_commitish: string | undefined;
|
||||||
|
}): Promise<{
|
||||||
|
data: {
|
||||||
|
name: string;
|
||||||
|
body: string;
|
||||||
|
};
|
||||||
|
}> {
|
||||||
|
return await this.github.rest.repos.generateReleaseNotes(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
truncateReleaseNotes(input: string): string {
|
||||||
|
// release notes can be a maximum of 125000 characters
|
||||||
|
const githubNotesMaxCharLength = 125000;
|
||||||
|
return input.substring(0, githubNotesMaxCharLength - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async createRelease(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
tag_name: string;
|
tag_name: string;
|
||||||
@@ -94,11 +120,20 @@ export class GitHubReleaser implements Releaser {
|
|||||||
) {
|
) {
|
||||||
params.make_latest = undefined;
|
params.make_latest = undefined;
|
||||||
}
|
}
|
||||||
|
if (params.generate_release_notes) {
|
||||||
|
const releaseNotes = await this.getReleaseNotes(params);
|
||||||
|
params.generate_release_notes = false;
|
||||||
|
if (params.body) {
|
||||||
|
params.body = `${params.body}\n\n${releaseNotes.data.body}`;
|
||||||
|
} else {
|
||||||
|
params.body = releaseNotes.data.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.body = params.body ? this.truncateReleaseNotes(params.body) : undefined;
|
||||||
return this.github.rest.repos.createRelease(params);
|
return this.github.rest.repos.createRelease(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRelease(params: {
|
async updateRelease(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
release_id: number;
|
release_id: number;
|
||||||
@@ -118,10 +153,28 @@ export class GitHubReleaser implements Releaser {
|
|||||||
) {
|
) {
|
||||||
params.make_latest = undefined;
|
params.make_latest = undefined;
|
||||||
}
|
}
|
||||||
|
if (params.generate_release_notes) {
|
||||||
|
const releaseNotes = await this.getReleaseNotes(params);
|
||||||
|
params.generate_release_notes = false;
|
||||||
|
if (params.body) {
|
||||||
|
params.body = `${params.body}\n\n${releaseNotes.data.body}`;
|
||||||
|
} else {
|
||||||
|
params.body = releaseNotes.data.body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.body = params.body ? this.truncateReleaseNotes(params.body) : undefined;
|
||||||
return this.github.rest.repos.updateRelease(params);
|
return this.github.rest.repos.updateRelease(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async finalizeRelease(params: { owner: string; repo: string; release_id: number }) {
|
||||||
|
return await this.github.rest.repos.updateRelease({
|
||||||
|
owner: params.owner,
|
||||||
|
repo: params.repo,
|
||||||
|
release_id: params.release_id,
|
||||||
|
draft: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }> {
|
allReleases(params: { owner: string; repo: string }): AsyncIterableIterator<{ data: Release[] }> {
|
||||||
const updatedParams = { per_page: 100, ...params };
|
const updatedParams = { per_page: 100, ...params };
|
||||||
return this.github.paginate.iterator(
|
return this.github.paginate.iterator(
|
||||||
@@ -265,7 +318,6 @@ export const release = async (
|
|||||||
body = workflowBody || existingReleaseBody;
|
body = workflowBody || existingReleaseBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
const draft = config.input_draft !== undefined ? config.input_draft : existingRelease.draft;
|
|
||||||
const prerelease =
|
const prerelease =
|
||||||
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
|
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
|
||||||
|
|
||||||
@@ -279,7 +331,7 @@ export const release = async (
|
|||||||
target_commitish,
|
target_commitish,
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
draft,
|
draft: existingRelease.draft,
|
||||||
prerelease,
|
prerelease,
|
||||||
discussion_category_name,
|
discussion_category_name,
|
||||||
generate_release_notes,
|
generate_release_notes,
|
||||||
@@ -307,6 +359,45 @@ export const release = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalizes a release by unmarking it as "draft" (if relevant)
|
||||||
|
* after all artifacts have been uploaded.
|
||||||
|
*
|
||||||
|
* @param config - Release configuration as specified by user
|
||||||
|
* @param releaser - The GitHub API wrapper for release operations
|
||||||
|
* @param release - The existing release to be finalized
|
||||||
|
* @param maxRetries - The maximum number of attempts to finalize the release
|
||||||
|
*/
|
||||||
|
export const finalizeRelease = async (
|
||||||
|
config: Config,
|
||||||
|
releaser: Releaser,
|
||||||
|
release: Release,
|
||||||
|
maxRetries: number = 3,
|
||||||
|
): Promise<Release> => {
|
||||||
|
if (config.input_draft === true) {
|
||||||
|
return release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxRetries <= 0) {
|
||||||
|
console.log(`❌ Too many retries. Aborting...`);
|
||||||
|
throw new Error('Too many retries.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const [owner, repo] = config.github_repository.split('/');
|
||||||
|
try {
|
||||||
|
const { data } = await releaser.finalizeRelease({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
release_id: release.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch {
|
||||||
|
console.log(`retrying... (${maxRetries - 1} retries remaining)`);
|
||||||
|
return finalizeRelease(config, releaser, release, maxRetries - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a release by tag name from all a repository's releases.
|
* Finds a release by tag name from all a repository's releases.
|
||||||
*
|
*
|
||||||
@@ -347,7 +438,6 @@ async function createRelease(
|
|||||||
const tag_name = tag;
|
const tag_name = tag;
|
||||||
const name = config.input_name || tag;
|
const name = config.input_name || tag;
|
||||||
const body = releaseBody(config);
|
const body = releaseBody(config);
|
||||||
const draft = config.input_draft;
|
|
||||||
const prerelease = config.input_prerelease;
|
const prerelease = config.input_prerelease;
|
||||||
const target_commitish = config.input_target_commitish;
|
const target_commitish = config.input_target_commitish;
|
||||||
const make_latest = config.input_make_latest;
|
const make_latest = config.input_make_latest;
|
||||||
@@ -363,7 +453,7 @@ async function createRelease(
|
|||||||
tag_name,
|
tag_name,
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
draft,
|
draft: true,
|
||||||
prerelease,
|
prerelease,
|
||||||
target_commitish,
|
target_commitish,
|
||||||
discussion_category_name,
|
discussion_category_name,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { setFailed, setOutput } from '@actions/core';
|
import { setFailed, setOutput } from '@actions/core';
|
||||||
import { getOctokit } from '@actions/github';
|
import { getOctokit } from '@actions/github';
|
||||||
import { GitHubReleaser, release, upload } from './github';
|
import { GitHubReleaser, release, finalizeRelease, upload } from './github';
|
||||||
import { isTag, parseConfig, paths, unmatchedPatterns, uploadUrl } from './util';
|
import { isTag, parseConfig, paths, unmatchedPatterns, uploadUrl } from './util';
|
||||||
|
|
||||||
import { env } from 'process';
|
import { env } from 'process';
|
||||||
@@ -48,7 +48,8 @@ async function run() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
//);
|
//);
|
||||||
const rel = await release(config, new GitHubReleaser(gh));
|
const releaser = new GitHubReleaser(gh);
|
||||||
|
let rel = await release(config, releaser);
|
||||||
if (config.input_files && config.input_files.length > 0) {
|
if (config.input_files && config.input_files.length > 0) {
|
||||||
const files = paths(config.input_files, config.input_working_directory);
|
const files = paths(config.input_files, config.input_working_directory);
|
||||||
if (files.length == 0) {
|
if (files.length == 0) {
|
||||||
@@ -81,6 +82,10 @@ async function run() {
|
|||||||
const assets = results.filter(Boolean);
|
const assets = results.filter(Boolean);
|
||||||
setOutput('assets', assets);
|
setOutput('assets', assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Finalizing release...');
|
||||||
|
rel = await finalizeRelease(config, releaser, rel);
|
||||||
|
|
||||||
console.log(`🎉 Release ready at ${rel.html_url}`);
|
console.log(`🎉 Release ready at ${rel.html_url}`);
|
||||||
setOutput('url', rel.html_url);
|
setOutput('url', rel.html_url);
|
||||||
setOutput('id', rel.id.toString());
|
setOutput('id', rel.id.toString());
|
||||||
|
|||||||
54
src/util.ts
54
src/util.ts
@@ -35,23 +35,53 @@ export const uploadUrl = (url: string): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const releaseBody = (config: Config): string | undefined => {
|
export const releaseBody = (config: Config): string | undefined => {
|
||||||
return (
|
if (config.input_body_path) {
|
||||||
(config.input_body_path && readFileSync(config.input_body_path).toString('utf8')) ||
|
try {
|
||||||
config.input_body
|
const contents = readFileSync(config.input_body_path, 'utf8');
|
||||||
);
|
return contents;
|
||||||
|
} catch (err: any) {
|
||||||
|
console.warn(
|
||||||
|
`⚠️ Failed to read body_path "${config.input_body_path}" (${err?.code ?? 'ERR'}). Falling back to 'body' input.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config.input_body;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Env = { [key: string]: string | undefined };
|
type Env = { [key: string]: string | undefined };
|
||||||
|
|
||||||
|
const smartSplit = (input: string): string[] => {
|
||||||
|
const result: string[] = [];
|
||||||
|
let current = '';
|
||||||
|
let braceDepth = 0;
|
||||||
|
|
||||||
|
for (const ch of input) {
|
||||||
|
if (ch === '{') {
|
||||||
|
braceDepth++;
|
||||||
|
}
|
||||||
|
if (ch === '}') {
|
||||||
|
braceDepth--;
|
||||||
|
}
|
||||||
|
if (ch === ',' && braceDepth === 0) {
|
||||||
|
if (current.trim()) {
|
||||||
|
result.push(current.trim());
|
||||||
|
}
|
||||||
|
current = '';
|
||||||
|
} else {
|
||||||
|
current += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current.trim()) {
|
||||||
|
result.push(current.trim());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
export const parseInputFiles = (files: string): string[] => {
|
export const parseInputFiles = (files: string): string[] => {
|
||||||
return files.split(/\r?\n/).reduce<string[]>(
|
return files
|
||||||
(acc, line) =>
|
.split(/\r?\n/)
|
||||||
acc
|
.flatMap((line) => smartSplit(line))
|
||||||
.concat(line.split(','))
|
.filter((pat) => pat.trim() !== '');
|
||||||
.filter((pat) => pat)
|
|
||||||
.map((pat) => pat.trim()),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseConfig = (env: Env): Config => {
|
export const parseConfig = (env: Env): Config => {
|
||||||
|
|||||||
Reference in New Issue
Block a user