Compare commits

..

30 Commits

Author SHA1 Message Date
dependabot[bot]
4a195fd328 chore(deps): bump the npm group with 3 updates
Bumps the npm group with 3 updates: [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8), [prettier](https://github.com/prettier/prettier) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@vitest/coverage-v8` from 4.0.14 to 4.0.15
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.15/packages/coverage-v8)

Updates `prettier` from 3.7.3 to 3.7.4
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.3...3.7.4)

Updates `vitest` from 4.0.14 to 4.0.15
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.15/packages/vitest)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: prettier
  dependency-version: 3.7.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: vitest
  dependency-version: 4.0.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-08 22:02:01 +00:00
Andreas Deininger
60cfd9a691 chore(docs): bump versions in README and fix typos in the changelog (#702)
* README.md: bump versions

* fix two more typos in the changelog

Signed-off-by: Rui Chen <rui@chenrui.dev>

---------

Signed-off-by: Rui Chen <rui@chenrui.dev>
Co-authored-by: Rui Chen <rui@chenrui.dev>
2025-12-06 14:00:40 -05:00
dependabot[bot]
69bd94bb12 chore(deps): bump actions/checkout in the github-actions group (#699)
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 5.0.1 to 6.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](93cb6efe18...1af3b93b68)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 13:54:40 -05:00
dependabot[bot]
8dca0e43c6 chore(deps): bump the npm group with 3 updates (#700)
Bumps the npm group with 3 updates: [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8), [prettier](https://github.com/prettier/prettier) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@vitest/coverage-v8` from 4.0.13 to 4.0.14
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.14/packages/coverage-v8)

Updates `prettier` from 3.6.2 to 3.7.3
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.6.2...3.7.3)

Updates `vitest` from 4.0.13 to 4.0.14
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.14/packages/vitest)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: prettier
  dependency-version: 3.7.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: vitest
  dependency-version: 4.0.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 13:54:35 -05:00
Rui Chen
a06a81a03e release 2.5.0
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-12-01 01:02:34 -05:00
jj
7da8983734 feat: mark release as draft until all artifacts are uploaded (#692)
Previously, the releases were created and then artifacts (if any)
were added to them. This broke when GitHub released "immutable"
releases, which disallow changes after the release is published.

Make it so that releases are always marked as "draft" when being
worked on by the action, and unmarked as draft (if desired) once
the action is completed.

Fixes #653
2025-12-01 00:59:24 -05:00
dependabot[bot]
87973286a4 chore(deps): bump actions/checkout in the github-actions group (#689)
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 5.0.0 to 5.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](08c6903cd8...93cb6efe18)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 00:56:27 -05:00
dependabot[bot]
1bfc62a71b chore(deps): bump the npm group across 1 directory with 5 updates (#697)
Bumps the npm group with 4 updates in the / directory: [glob](https://github.com/isaacs/node-glob), [mime-types](https://github.com/jshttp/mime-types), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8).


Updates `glob` from 11.0.3 to 13.0.0
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v11.0.3...v13.0.0)

Updates `mime-types` from 3.0.1 to 3.0.2
- [Release notes](https://github.com/jshttp/mime-types/releases)
- [Changelog](https://github.com/jshttp/mime-types/blob/master/HISTORY.md)
- [Commits](https://github.com/jshttp/mime-types/compare/v3.0.1...v3.0.2)

Updates `@types/node` from 20.19.24 to 20.19.25
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitest/coverage-v8` from 4.0.6 to 4.0.13
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.13/packages/coverage-v8)

Updates `vitest` from 4.0.6 to 4.0.13
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.13/packages/vitest)

---
updated-dependencies:
- dependency-name: glob
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: mime-types
  dependency-version: 3.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 20.19.25
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: vitest
  dependency-version: 4.0.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 00:56:07 -05:00
Rui Chen
5be0e66d93 release 2.4.2
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-11-08 14:21:57 -05:00
Jens L.
af658b4d5d feat: Ensure generated release notes cannot be over 125000 characters (#684)
* Ensure generated release notes cannot be over 125000 characters

* simpler truncate, and always truncate even without generated
2025-11-08 14:20:00 -05:00
Rui Chen
237aaccf71 chore: bump node to 24.11.0
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-11-08 14:18:20 -05:00
dependabot[bot]
00362bea6f chore(deps): bump the npm group with 5 updates (#687)
Bumps the npm group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@octokit/plugin-retry](https://github.com/octokit/plugin-retry.js) | `8.0.2` | `8.0.3` |
| [@octokit/plugin-throttling](https://github.com/octokit/plugin-throttling.js) | `11.0.2` | `11.0.3` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `20.19.23` | `20.19.24` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.0.4` | `4.0.6` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.0.4` | `4.0.6` |


Updates `@octokit/plugin-retry` from 8.0.2 to 8.0.3
- [Release notes](https://github.com/octokit/plugin-retry.js/releases)
- [Commits](https://github.com/octokit/plugin-retry.js/compare/v8.0.2...v8.0.3)

Updates `@octokit/plugin-throttling` from 11.0.2 to 11.0.3
- [Release notes](https://github.com/octokit/plugin-throttling.js/releases)
- [Commits](https://github.com/octokit/plugin-throttling.js/compare/v11.0.2...v11.0.3)

Updates `@types/node` from 20.19.23 to 20.19.24
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitest/coverage-v8` from 4.0.4 to 4.0.6
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.6/packages/coverage-v8)

Updates `vitest` from 4.0.4 to 4.0.6
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.6/packages/vitest)

---
updated-dependencies:
- dependency-name: "@octokit/plugin-retry"
  dependency-version: 8.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@octokit/plugin-throttling"
  dependency-version: 11.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 20.19.24
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: vitest
  dependency-version: 4.0.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-07 21:47:12 -05:00
dependabot[bot]
0adea5aa98 chore(deps): bump the npm group with 3 updates (#686)
Bumps the npm group with 3 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@types/node` from 20.19.22 to 20.19.23
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitest/coverage-v8` from 3.2.4 to 4.0.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.4/packages/coverage-v8)

Updates `vitest` from 3.2.4 to 4.0.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.4/packages/vitest)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.23
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.0.4
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: npm
- dependency-name: vitest
  dependency-version: 4.0.4
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-30 14:36:32 -04:00
dependabot[bot]
aa05f9d779 chore(deps): bump actions/setup-node from 5.0.0 to 6.0.0 in the github-actions group (#683)
* chore(deps): bump actions/setup-node in the github-actions group

Bumps the github-actions group with 1 update: [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/setup-node` from 5.0.0 to 6.0.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](a0853c2454...2028fbc5c2)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>

* update comment

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Rui Chen <rui@chenrui.dev>
2025-10-23 22:23:58 -04:00
dependabot[bot]
bbaccb3a0c chore(deps): bump @types/node from 20.19.21 to 20.19.22 in the npm group (#682)
Bumps the npm group with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@types/node` from 20.19.21 to 20.19.22
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.22
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 22:22:08 -04:00
dependabot[bot]
50fda3f773 chore(deps): bump vite from 7.1.5 to 7.1.11 (#681)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.5 to 7.1.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.11
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-23 22:21:57 -04:00
dependabot[bot]
5434409c2b chore(deps): bump @types/node from 20.19.19 to 20.19.21 in the npm group (#679)
Bumps the npm group with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@types/node` from 20.19.19 to 20.19.21
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.21
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-16 18:49:13 -04:00
Rui Chen
6da8fa9354 release 2.4.1
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-10-11 11:40:52 -04:00
Copilot
f38efdea4c fix: gracefully fallback to body when body_path cannot be read (#671)
* Initial plan

* fix: gracefully fallback to body when body_path cannot be read

Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>
2025-10-06 23:50:32 -04:00
Copilot
cec1a1113b fix(util): support brace expansion globs containing commas in parseInputFiles (#672)
* Initial plan

* fix(util): support brace expansion globs containing commas in parseInputFiles

Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>

* test(util): add comprehensive edge case coverage for brace expansion parsing

Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: chenrui333 <1580956+chenrui333@users.noreply.github.com>
2025-10-06 23:50:00 -04:00
Rui Chen
aec2ec56f9 release 2.4.0
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-10-06 22:53:32 -04:00
Stephen Way
4db716b167 feat: respect working_directory for files globs; add input and tests (#667) 2025-10-06 22:51:45 -04:00
dependabot[bot]
14820f2cee chore(deps): bump the npm group with 2 updates (#668)
Bumps the npm group with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [typescript](https://github.com/microsoft/TypeScript).


Updates `@types/node` from 20.19.18 to 20.19.19
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `typescript` from 5.9.2 to 5.9.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release-publish.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.9.2...v5.9.3)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.19
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: typescript
  dependency-version: 5.9.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 22:48:36 -04:00
Rui Chen
62c96d0c4e release 2.3.4
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-10-03 14:45:26 -04:00
Stephen Way
7dc9b8ac0f fix(action): handle 422 already_exists race condition (#665)
- Add retry logic for 422 'already_exists' errors in race conditions
- Allow action to find and update existing releases instead of failing
- Add test to verify race condition handling works correctly
- Fixes regression that broke matrix workflows in v2.2.2+

closes #616
2025-10-03 14:34:31 -04:00
dependabot[bot]
0f0e0b98e9 chore(deps): bump the npm group with 3 updates (#666)
Bumps the npm group with 3 updates: [@octokit/plugin-retry](https://github.com/octokit/plugin-retry.js), [@octokit/plugin-throttling](https://github.com/octokit/plugin-throttling.js) and [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@octokit/plugin-retry` from 8.0.1 to 8.0.2
- [Release notes](https://github.com/octokit/plugin-retry.js/releases)
- [Commits](https://github.com/octokit/plugin-retry.js/compare/v8.0.1...v8.0.2)

Updates `@octokit/plugin-throttling` from 11.0.1 to 11.0.2
- [Release notes](https://github.com/octokit/plugin-throttling.js/releases)
- [Commits](https://github.com/octokit/plugin-throttling.js/compare/v11.0.1...v11.0.2)

Updates `@types/node` from 20.19.17 to 20.19.18
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@octokit/plugin-retry"
  dependency-version: 8.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@octokit/plugin-throttling"
  dependency-version: 11.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@types/node"
  dependency-version: 20.19.18
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-03 14:31:53 -04:00
dependabot[bot]
97d42c1b50 chore(deps): bump the npm group across 1 directory with 2 updates (#662)
Bumps the npm group with 2 updates in the / directory: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@vercel/ncc](https://github.com/vercel/ncc).


Updates `@types/node` from 20.19.13 to 20.19.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vercel/ncc` from 0.38.3 to 0.38.4
- [Release notes](https://github.com/vercel/ncc/releases)
- [Commits](https://github.com/vercel/ncc/compare/0.38.3...0.38.4)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: "@vercel/ncc"
  dependency-version: 0.38.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-18 23:26:39 -04:00
dependabot[bot]
19cd0bcd2b chore(deps): bump vite from 7.0.0 to 7.1.5 (#657)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.0.0 to 7.1.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-10 22:41:43 -04:00
dependabot[bot]
5d1b0b1164 chore(deps): bump @types/node from 20.19.11 to 20.19.13 in the npm group (#655)
Bumps the npm group with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node).


Updates `@types/node` from 20.19.11 to 20.19.13
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 23:36:06 -04:00
dependabot[bot]
f6021cf9a4 chore(deps): bump actions/setup-node in the github-actions group (#656)
Bumps the github-actions group with 1 update: [actions/setup-node](https://github.com/actions/setup-node).


Updates `actions/setup-node` from 4.4.0 to 5.0.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](49933ea528...a0853c2454)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 23:35:59 -04:00
13 changed files with 1069 additions and 1112 deletions

View File

@@ -8,9 +8,9 @@ jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v5
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
with:
node-version-file: ".tool-versions"
cache: "npm"

View File

@@ -1 +1 @@
nodejs 24.2.0
nodejs 24.11.0

View File

@@ -1,3 +1,56 @@
## 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
## What's Changed
### Exciting New Features 🎉
* feat(action): respect working_directory for files globs by @stephenway in https://github.com/softprops/action-gh-release/pull/667
## 2.3.4
## What's Changed
### Bug fixes 🐛
* fix(action): handle 422 already_exists race condition by @stephenway in https://github.com/softprops/action-gh-release/pull/665
### Other Changes 🔄
- dependency updates
## 2.3.3
## What's Changed
@@ -148,7 +201,7 @@
## 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
## 0.1.15
@@ -159,7 +212,7 @@
## 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
@@ -167,7 +220,7 @@
## 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
@@ -184,7 +237,7 @@
## 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)
- 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)
## 0.1.7
@@ -197,14 +250,14 @@
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 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)
- 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)
- 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
@@ -214,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)
- 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
@@ -229,7 +282,7 @@ This is now fixed.
- 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
- name: Release

View File

@@ -51,7 +51,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Release
uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
@@ -72,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Release
uses: softprops/action-gh-release@v2
```
@@ -99,7 +99,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
@@ -123,7 +123,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
@@ -157,7 +157,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Generate Changelog
run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt
- name: Release

View File

@@ -1,4 +1,11 @@
import { asset, findTagFromReleases, mimeOrDefault, Release, Releaser } from '../src/github';
import {
asset,
findTagFromReleases,
mimeOrDefault,
release,
Release,
Releaser,
} from '../src/github';
import { assert, describe, it } from 'vitest';
@@ -42,6 +49,7 @@ describe('github', () => {
getReleaseByTag: () => Promise.reject('Not implemented'),
createRelease: () => Promise.reject('Not implemented'),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
yield { data: [mockRelease] };
},
@@ -227,4 +235,76 @@ describe('github', () => {
});
});
});
describe('error handling', () => {
it('handles 422 already_exists error gracefully', async () => {
const mockReleaser: Releaser = {
getReleaseByTag: () => Promise.reject('Not implemented'),
createRelease: () =>
Promise.reject({
status: 422,
response: { data: { errors: [{ code: 'already_exists' }] } },
}),
updateRelease: () =>
Promise.resolve({
data: {
id: 1,
upload_url: 'test',
html_url: 'test',
tag_name: 'v1.0.0',
name: 'test',
body: 'test',
target_commitish: 'main',
draft: true,
prerelease: false,
assets: [],
},
}),
finalizeRelease: async () => {},
allReleases: async function* () {
yield {
data: [
{
id: 1,
upload_url: 'test',
html_url: 'test',
tag_name: 'v1.0.0',
name: 'test',
body: 'test',
target_commitish: 'main',
draft: false,
prerelease: false,
assets: [],
},
],
};
},
} as const;
const config = {
github_token: 'test-token',
github_ref: 'refs/tags/v1.0.0',
github_repository: 'owner/repo',
input_tag_name: undefined,
input_name: undefined,
input_body: undefined,
input_body_path: undefined,
input_files: [],
input_draft: undefined,
input_prerelease: undefined,
input_preserve_order: undefined,
input_overwrite_files: undefined,
input_fail_on_unmatched_files: false,
input_target_commitish: undefined,
input_discussion_category_name: undefined,
input_generate_release_notes: false,
input_append_body: false,
input_make_latest: undefined,
};
const result = await release(config, mockReleaser, 1);
assert.ok(result);
assert.equal(result.id, 1);
});
});
});

View File

@@ -39,6 +39,18 @@ describe('util', () => {
'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', () => {
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', () => {
it('parses basic config', () => {
@@ -128,6 +186,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -156,6 +215,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -183,6 +243,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -211,6 +272,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -243,6 +305,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: 'env-token',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -272,6 +335,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: 'input-token',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -300,6 +364,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -327,6 +392,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
@@ -354,6 +420,7 @@ describe('util', () => {
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: true,
input_body: undefined,
input_body_path: undefined,
@@ -388,6 +455,10 @@ describe('util', () => {
'tests/data/foo/bar.txt',
]);
});
it('resolves files relative to working_directory', async () => {
assert.deepStrictEqual(paths(['data/**/*'], 'tests'), ['tests/data/foo/bar.txt']);
});
});
describe('unmatchedPatterns', () => {
@@ -397,6 +468,12 @@ describe('util', () => {
['tests/data/does/not/exist/*'],
);
});
it('resolves unmatched relative to working_directory', async () => {
assert.deepStrictEqual(unmatchedPatterns(['data/does/not/exist/*'], 'tests'), [
'data/does/not/exist/*',
]);
});
});
describe('replaceSpacesWithDots', () => {
@@ -413,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',
]);
});
});

View File

@@ -27,6 +27,9 @@ inputs:
files:
description: "Newline-delimited list of path globs for asset files to upload"
required: false
working_directory:
description: "Base directory to resolve 'files' globs against (defaults to job working-directory)"
required: false
overwrite_files:
description: "Overwrite existing files with the same name. Defaults to true"
required: false

4
dist/index.js vendored

File diff suppressed because one or more lines are too long

1652
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "action-gh-release",
"version": "2.3.3",
"version": "2.5.0",
"private": true,
"description": "GitHub Action for creating GitHub Releases",
"main": "lib/main.js",
@@ -24,21 +24,21 @@
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1",
"@octokit/plugin-retry": "^8.0.1",
"@octokit/plugin-throttling": "^11.0.1",
"glob": "^11.0.3",
"mime-types": "^3.0.1"
"@octokit/plugin-retry": "^8.0.3",
"@octokit/plugin-throttling": "^11.0.3",
"glob": "^13.0.0",
"mime-types": "^3.0.2"
},
"devDependencies": {
"@types/glob": "^9.0.0",
"@types/mime-types": "^3.0.1",
"@types/node": "^20.19.11",
"@vercel/ncc": "^0.38.3",
"@vitest/coverage-v8": "^3.2.4",
"prettier": "3.6.2",
"@types/node": "^20.19.25",
"@vercel/ncc": "^0.38.4",
"@vitest/coverage-v8": "^4.0.15",
"prettier": "3.7.4",
"ts-node": "^10.9.2",
"typescript": "^5.9.2",
"typescript": "^5.9.3",
"typescript-formatter": "^7.2.2",
"vitest": "^3.1.4"
"vitest": "^4.0.4"
}
}

View File

@@ -58,6 +58,12 @@ export interface Releaser {
make_latest: 'true' | 'false' | 'legacy' | undefined;
}): Promise<{ data: Release }>;
finalizeRelease(params: {
owner: string;
repo: string;
release_id: number;
}): Promise<{ 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);
}
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;
repo: string;
tag_name: string;
@@ -94,11 +120,20 @@ export class GitHubReleaser implements Releaser {
) {
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);
}
updateRelease(params: {
async updateRelease(params: {
owner: string;
repo: string;
release_id: number;
@@ -118,10 +153,28 @@ export class GitHubReleaser implements Releaser {
) {
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);
}
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[] }> {
const updatedParams = { per_page: 100, ...params };
return this.github.paginate.iterator(
@@ -265,7 +318,6 @@ export const release = async (
body = workflowBody || existingReleaseBody;
}
const draft = config.input_draft !== undefined ? config.input_draft : existingRelease.draft;
const prerelease =
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
@@ -279,7 +331,7 @@ export const release = async (
target_commitish,
name,
body,
draft,
draft: existingRelease.draft,
prerelease,
discussion_category_name,
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.
*
@@ -347,7 +438,6 @@ async function createRelease(
const tag_name = tag;
const name = config.input_name || tag;
const body = releaseBody(config);
const draft = config.input_draft;
const prerelease = config.input_prerelease;
const target_commitish = config.input_target_commitish;
const make_latest = config.input_make_latest;
@@ -363,7 +453,7 @@ async function createRelease(
tag_name,
name,
body,
draft,
draft: true,
prerelease,
target_commitish,
discussion_category_name,
@@ -388,8 +478,18 @@ async function createRelease(
throw error;
case 422:
console.log('Skip retry - validation failed');
throw error;
// Check if this is a race condition with "already_exists" error
const errorData = error.response?.data;
if (errorData?.errors?.[0]?.code === 'already_exists') {
console.log(
'⚠️ Release already exists (race condition detected), retrying to find and update existing release...',
);
// Don't throw - allow retry to find existing release
} else {
console.log('Skip retry - validation failed');
throw error;
}
break;
}
console.log(`retrying... (${maxRetries - 1} retries remaining)`);

View File

@@ -1,6 +1,6 @@
import { setFailed, setOutput } from '@actions/core';
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 { env } from 'process';
@@ -12,7 +12,7 @@ async function run() {
throw new Error(`⚠️ GitHub Releases requires a tag`);
}
if (config.input_files) {
const patterns = unmatchedPatterns(config.input_files);
const patterns = unmatchedPatterns(config.input_files, config.input_working_directory);
patterns.forEach((pattern) => {
if (config.input_fail_on_unmatched_files) {
throw new Error(`⚠️ Pattern '${pattern}' does not match any files.`);
@@ -48,9 +48,10 @@ 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) {
const files = paths(config.input_files);
const files = paths(config.input_files, config.input_working_directory);
if (files.length == 0) {
if (config.input_fail_on_unmatched_files) {
throw new Error(`⚠️ ${config.input_files} does not include a valid file.`);
@@ -81,6 +82,10 @@ async function run() {
const assets = results.filter(Boolean);
setOutput('assets', assets);
}
console.log('Finalizing release...');
rel = await finalizeRelease(config, releaser, rel);
console.log(`🎉 Release ready at ${rel.html_url}`);
setOutput('url', rel.html_url);
setOutput('id', rel.id.toString());

View File

@@ -1,5 +1,6 @@
import * as glob from 'glob';
import { statSync, readFileSync } from 'fs';
import * as pathLib from 'path';
export interface Config {
github_token: string;
@@ -12,6 +13,7 @@ export interface Config {
input_body?: string;
input_body_path?: string;
input_files?: string[];
input_working_directory?: string;
input_overwrite_files?: boolean;
input_draft?: boolean;
input_preserve_order?: boolean;
@@ -33,23 +35,53 @@ export const uploadUrl = (url: string): string => {
};
export const releaseBody = (config: Config): string | undefined => {
return (
(config.input_body_path && readFileSync(config.input_body_path).toString('utf8')) ||
config.input_body
);
if (config.input_body_path) {
try {
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 };
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[] => {
return files.split(/\r?\n/).reduce<string[]>(
(acc, line) =>
acc
.concat(line.split(','))
.filter((pat) => pat)
.map((pat) => pat.trim()),
[],
);
return files
.split(/\r?\n/)
.flatMap((line) => smartSplit(line))
.filter((pat) => pat.trim() !== '');
};
export const parseConfig = (env: Env): Config => {
@@ -62,6 +94,7 @@ export const parseConfig = (env: Env): Config => {
input_body: env.INPUT_BODY,
input_body_path: env.INPUT_BODY_PATH,
input_files: parseInputFiles(env.INPUT_FILES || ''),
input_working_directory: env.INPUT_WORKING_DIRECTORY || undefined,
input_overwrite_files: env.INPUT_OVERWRITE_FILES
? env.INPUT_OVERWRITE_FILES == 'true'
: undefined,
@@ -84,17 +117,34 @@ const parseMakeLatest = (value: string | undefined): 'true' | 'false' | 'legacy'
return undefined;
};
export const paths = (patterns: string[]): string[] => {
export const paths = (patterns: string[], cwd?: string): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => {
return acc.concat(glob.sync(pattern).filter((path) => statSync(path).isFile()));
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
const resolved = matches
.map((p) => (cwd ? pathLib.join(cwd, p) : p))
.filter((p) => {
try {
return statSync(p).isFile();
} catch {
return false;
}
});
return acc.concat(resolved);
}, []);
};
export const unmatchedPatterns = (patterns: string[]): string[] => {
export const unmatchedPatterns = (patterns: string[], cwd?: string): string[] => {
return patterns.reduce((acc: string[], pattern: string): string[] => {
return acc.concat(
glob.sync(pattern).filter((path) => statSync(path).isFile()).length == 0 ? [pattern] : [],
);
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
const files = matches.filter((p) => {
try {
const full = cwd ? pathLib.join(cwd, p) : p;
return statSync(full).isFile();
} catch {
return false;
}
});
return acc.concat(files.length == 0 ? [pattern] : []);
}, []);
};