mirror of
https://github.com/softprops/action-gh-release.git
synced 2026-11-12 21:41:58 +08:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6268c631a | ||
|
|
8988630456 | ||
|
|
c1b107442c | ||
|
|
4c8c431191 | ||
|
|
1505034bb0 | ||
|
|
21e9098c3b | ||
|
|
26941a6e6b |
No files matched your search
@@ -1,29 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: npm
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
groups:
|
|
||||||
npm:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
||||||
ignore:
|
|
||||||
- dependency-name: node-fetch
|
|
||||||
versions:
|
|
||||||
- ">=3.0.0"
|
|
||||||
- dependency-name: "@types/node"
|
|
||||||
versions:
|
|
||||||
- ">=22.0.0"
|
|
||||||
commit-message:
|
|
||||||
prefix: "chore(deps)"
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: weekly
|
|
||||||
groups:
|
|
||||||
github-actions:
|
|
||||||
patterns:
|
|
||||||
- "*"
|
|
||||||
commit-message:
|
|
||||||
prefix: "chore(deps)"
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
changelog:
|
|
||||||
exclude:
|
|
||||||
labels:
|
|
||||||
- ignore-for-release
|
|
||||||
- github-actions
|
|
||||||
authors:
|
|
||||||
- octocat
|
|
||||||
- renovate[bot]
|
|
||||||
categories:
|
|
||||||
- title: Breaking Changes 🛠
|
|
||||||
labels:
|
|
||||||
- breaking-change
|
|
||||||
- title: Exciting New Features 🎉
|
|
||||||
labels:
|
|
||||||
- enhancement
|
|
||||||
- feature
|
|
||||||
- title: Bug fixes 🐛
|
|
||||||
labels:
|
|
||||||
- bug
|
|
||||||
- title: Other Changes 🔄
|
|
||||||
labels:
|
|
||||||
- "*"
|
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
name: main
|
name: Main
|
||||||
|
|
||||||
on:
|
on: [pull_request, push]
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
|
# https://github.com/actions/checkout
|
||||||
|
- name: Checkout
|
||||||
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
|
uses: actions/checkout@v2
|
||||||
with:
|
|
||||||
node-version-file: ".tool-versions"
|
|
||||||
cache: "npm"
|
|
||||||
|
|
||||||
- name: Install
|
- name: Install
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -29,4 +23,4 @@ jobs:
|
|||||||
# git diff --exit-code --stat -- . ':!node_modules' \
|
# git diff --exit-code --stat -- . ':!node_modules' \
|
||||||
# || (echo "##[error] found changed files after build. please 'npm run build && npm run fmt'" \
|
# || (echo "##[error] found changed files after build. please 'npm run build && npm run fmt'" \
|
||||||
# "and check in all changes" \
|
# "and check in all changes" \
|
||||||
# && exit 1)
|
# && exit 1)
|
||||||
@@ -2,4 +2,3 @@ __tests__/runner/*
|
|||||||
# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
|
# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
|
||||||
# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
|
# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Build outputs
|
|
||||||
dist/
|
|
||||||
lib/
|
|
||||||
coverage/
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Misc
|
|
||||||
.github/
|
|
||||||
*.log
|
|
||||||
.DS_Store
|
|
||||||
__tests__/release.txt
|
|
||||||
|
|
||||||
# Package files
|
|
||||||
package-lock.json
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* @type {import('prettier').Config}
|
|
||||||
*/
|
|
||||||
module.exports = {
|
|
||||||
trailingComma: 'all',
|
|
||||||
tabWidth: 2,
|
|
||||||
semi: true,
|
|
||||||
singleQuote: true,
|
|
||||||
printWidth: 100,
|
|
||||||
bracketSpacing: true,
|
|
||||||
};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
nodejs 24.11.0
|
|
||||||
+7
-253
@@ -1,249 +1,3 @@
|
|||||||
## 2.5.1
|
|
||||||
|
|
||||||
`2.5.1` is a patch release focused on regressions introduced in `2.5.0` and on release lookup reliability.
|
|
||||||
It fixes `#713`, addresses `#703`, and fixes `#724`. Regression testing shows that
|
|
||||||
current `master` no longer reproduces the finalize-race behavior reported in `#704` and `#709`.
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* fix: fetch correct asset URL after finalization; test; some refactoring by @pzhlkj6612 in https://github.com/softprops/action-gh-release/pull/738
|
|
||||||
* fix: release marked as 'latest' despite make_latest: false by @Boshen in https://github.com/softprops/action-gh-release/pull/715
|
|
||||||
* fix: use getReleaseByTag API instead of iterating all releases by @kim-em in https://github.com/softprops/action-gh-release/pull/725
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
|
|
||||||
* dependency updates, including the ESM/runtime compatibility refresh in https://github.com/softprops/action-gh-release/pull/731
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
### Exciting New Features 🎉
|
|
||||||
|
|
||||||
* feat: add input option `overwrite_files` by @asfernandes in https://github.com/softprops/action-gh-release/pull/343
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
|
|
||||||
- dependency updates
|
|
||||||
|
|
||||||
## 2.3.2
|
|
||||||
|
|
||||||
* fix: revert fs `readableWebStream` change
|
|
||||||
|
|
||||||
## 2.3.1
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* fix: fix file closing issue by @WailGree in https://github.com/softprops/action-gh-release/pull/629
|
|
||||||
|
|
||||||
## 2.3.0
|
|
||||||
|
|
||||||
* Migrate from jest to vitest
|
|
||||||
* Replace `mime` with `mime-types`
|
|
||||||
* Bump to use node 24
|
|
||||||
* Dependency updates
|
|
||||||
|
|
||||||
## 2.2.2
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* fix: updating release draft status from true to false by @galargh in https://github.com/softprops/action-gh-release/pull/316
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
|
|
||||||
* chore: simplify ref_type test by @steinybot in https://github.com/softprops/action-gh-release/pull/598
|
|
||||||
* fix(docs): clarify the default for tag_name by @muzimuzhi in https://github.com/softprops/action-gh-release/pull/599
|
|
||||||
* test(release): add unit tests when searching for a release by @rwaskiewicz in https://github.com/softprops/action-gh-release/pull/603
|
|
||||||
* dependency updates
|
|
||||||
|
|
||||||
## 2.2.1
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* fix: big file uploads by @xen0n in https://github.com/softprops/action-gh-release/pull/562
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
* chore(deps): bump @types/node from 22.10.1 to 22.10.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/559
|
|
||||||
* chore(deps): bump @types/node from 22.10.2 to 22.10.5 by @dependabot in https://github.com/softprops/action-gh-release/pull/569
|
|
||||||
* chore: update error and warning messages for not matching files in files field by @ytimocin in https://github.com/softprops/action-gh-release/pull/568
|
|
||||||
|
|
||||||
## 2.2.0
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
### Exciting New Features 🎉
|
|
||||||
|
|
||||||
* feat: read the release assets asynchronously by @xen0n in https://github.com/softprops/action-gh-release/pull/552
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* fix(docs): clarify the default for tag_name by @alexeagle in https://github.com/softprops/action-gh-release/pull/544
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
|
|
||||||
* chore(deps): bump typescript from 5.6.3 to 5.7.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/548
|
|
||||||
* chore(deps): bump @types/node from 22.9.0 to 22.9.4 by @dependabot in https://github.com/softprops/action-gh-release/pull/547
|
|
||||||
* chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 by @dependabot in https://github.com/softprops/action-gh-release/pull/545
|
|
||||||
* chore(deps): bump @vercel/ncc from 0.38.2 to 0.38.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/543
|
|
||||||
* chore(deps): bump prettier from 3.3.3 to 3.4.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/550
|
|
||||||
* chore(deps): bump @types/node from 22.9.4 to 22.10.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/551
|
|
||||||
* chore(deps): bump prettier from 3.4.1 to 3.4.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/554
|
|
||||||
|
|
||||||
## 2.1.0
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
### Exciting New Features 🎉
|
|
||||||
* feat: add support for release assets with multiple spaces within the name by @dukhine in https://github.com/softprops/action-gh-release/pull/518
|
|
||||||
* feat: preserve upload order by @richarddd in https://github.com/softprops/action-gh-release/pull/500
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
* chore(deps): bump @types/node from 22.8.2 to 22.8.7 by @dependabot in https://github.com/softprops/action-gh-release/pull/539
|
|
||||||
|
|
||||||
## 2.0.9
|
|
||||||
|
|
||||||
- maintenance release with updated dependencies
|
|
||||||
|
|
||||||
## 2.0.8
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
* chore(deps): bump prettier from 2.8.0 to 3.3.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/480
|
|
||||||
* chore(deps): bump @types/node from 20.14.9 to 20.14.11 by @dependabot in https://github.com/softprops/action-gh-release/pull/483
|
|
||||||
* chore(deps): bump @octokit/plugin-throttling from 9.3.0 to 9.3.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/484
|
|
||||||
* chore(deps): bump glob from 10.4.2 to 11.0.0 by @dependabot in https://github.com/softprops/action-gh-release/pull/477
|
|
||||||
* refactor: write jest config in ts by @chenrui333 in https://github.com/softprops/action-gh-release/pull/485
|
|
||||||
* chore(deps): bump @actions/github from 5.1.1 to 6.0.0 by @dependabot in https://github.com/softprops/action-gh-release/pull/470
|
|
||||||
|
|
||||||
## 2.0.7
|
|
||||||
|
|
||||||
### Bug fixes 🐛
|
|
||||||
|
|
||||||
* Fix missing update release body by @FirelightFlagboy in https://github.com/softprops/action-gh-release/pull/365
|
|
||||||
|
|
||||||
### Other Changes 🔄
|
|
||||||
|
|
||||||
* Bump @octokit/plugin-retry from 4.0.3 to 7.1.1 by @dependabot in https://github.com/softprops/action-gh-release/pull/443
|
|
||||||
* Bump typescript from 4.9.5 to 5.5.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/467
|
|
||||||
* Bump @types/node from 20.14.6 to 20.14.8 by @dependabot in https://github.com/softprops/action-gh-release/pull/469
|
|
||||||
* Bump @types/node from 20.14.8 to 20.14.9 by @dependabot in https://github.com/softprops/action-gh-release/pull/473
|
|
||||||
* Bump typescript from 5.5.2 to 5.5.3 by @dependabot in https://github.com/softprops/action-gh-release/pull/472
|
|
||||||
* Bump ts-jest from 29.1.5 to 29.2.2 by @dependabot in https://github.com/softprops/action-gh-release/pull/479
|
|
||||||
* docs: document that existing releases are updated by @jvanbruegge in https://github.com/softprops/action-gh-release/pull/474
|
|
||||||
|
|
||||||
## 2.0.6
|
|
||||||
|
|
||||||
- maintenance release with updated dependencies
|
|
||||||
|
|
||||||
## 2.0.5
|
|
||||||
|
|
||||||
- Factor in file names with spaces when upserting files [#446](https://github.com/softprops/action-gh-release/pull/446) via [@MystiPanda](https://github.com/MystiPanda)
|
|
||||||
- Improvements to error handling [#449](https://github.com/softprops/action-gh-release/pull/449) via [@till](https://github.com/till)
|
|
||||||
|
|
||||||
## 2.0.4
|
|
||||||
|
|
||||||
- Minor follow up to [#417](https://github.com/softprops/action-gh-release/pull/417). [#425](https://github.com/softprops/action-gh-release/pull/425)
|
|
||||||
|
|
||||||
## 2.0.3
|
|
||||||
|
|
||||||
- Declare `make_latest` as an input field in `action.yml` [#419](https://github.com/softprops/action-gh-release/pull/419)
|
|
||||||
|
|
||||||
## 2.0.2
|
|
||||||
|
|
||||||
- Revisit approach to [#384](https://github.com/softprops/action-gh-release/pull/384) making unresolved pattern failures opt-in [#417](https://github.com/softprops/action-gh-release/pull/417)
|
|
||||||
|
|
||||||
## 2.0.1
|
|
||||||
|
|
||||||
- Add support for make_latest property [#304](https://github.com/softprops/action-gh-release/pull/304) via [@samueljseay](https://github.com/samueljseay)
|
|
||||||
- Fail run if files setting contains invalid patterns [#384](https://github.com/softprops/action-gh-release/pull/384) via [@rpdelaney](https://github.com/rpdelaney)
|
|
||||||
- Add support for proxy env variables (don't use node-fetch) [#386](https://github.com/softprops/action-gh-release/pull/386/) via [@timor-raiman](https://github.com/timor-raiman)
|
|
||||||
- Suppress confusing warning when input_files is empty [#389](https://github.com/softprops/action-gh-release/pull/389) via [@Drowze](https://github.com/Drowze)
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
- `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
|
|
||||||
|
|
||||||
- Upgrade to action.yml declaration to node16 to address deprecations
|
|
||||||
- Upgrade dependencies
|
|
||||||
- Add `asset` output as a JSON array containing information about the uploaded assets
|
|
||||||
|
|
||||||
## 0.1.14
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
- fix issue with multiple runs concatenating release bodies [#145](https://github.com/softprops/action-gh-release/pull/145)
|
|
||||||
|
|
||||||
## 0.1.12
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
- better error message on release create failed [#143](https://github.com/softprops/action-gh-release/pull/143)
|
|
||||||
|
|
||||||
## 0.1.10
|
## 0.1.10
|
||||||
|
|
||||||
- fixed error message formatting for file uploads
|
- fixed error message formatting for file uploads
|
||||||
@@ -255,7 +9,7 @@ current `master` no longer reproduces the finalize-race behavior reported in `#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 now resolved first from an env variable and then from an input [#133](https://github.com/softprops/action-gh-release/pull/133)
|
- 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)
|
||||||
- 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
|
||||||
@@ -268,14 +22,14 @@ current `master` no longer reproduces the finalize-race behavior reported in `#7
|
|||||||
|
|
||||||
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 where 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 were 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 referring 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 refering 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 implemented in 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 implemened the 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 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)
|
- 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)
|
||||||
|
|
||||||
## 0.1.5
|
## 0.1.5
|
||||||
|
|
||||||
@@ -285,7 +39,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 turbulence [#26](https://github.com/softprops/action-gh-release/pull/26)
|
- Added basic GitHub API retry support to manage API turbulance [#26](https://github.com/softprops/action-gh-release/pull/26)
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
@@ -300,7 +54,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 delimited 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 delimieted list for better readability
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Release
|
- name: Release
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2019-current Doug Tangren
|
Copyright (c) 2019 Doug Tangren
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
@@ -21,16 +21,6 @@
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
- [🤸 Usage](#-usage)
|
|
||||||
- [🚥 Limit releases to pushes to tags](#-limit-releases-to-pushes-to-tags)
|
|
||||||
- [⬆️ Uploading release assets](#️-uploading-release-assets)
|
|
||||||
- [📝 External release notes](#-external-release-notes)
|
|
||||||
- [💅 Customizing](#-customizing)
|
|
||||||
- [inputs](#inputs)
|
|
||||||
- [outputs](#outputs)
|
|
||||||
- [environment variables](#environment-variables)
|
|
||||||
- [Permissions](#permissions)
|
|
||||||
|
|
||||||
## 🤸 Usage
|
## 🤸 Usage
|
||||||
|
|
||||||
### 🚥 Limit releases to pushes to tags
|
### 🚥 Limit releases to pushes to tags
|
||||||
@@ -51,10 +41,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
if: github.ref_type == 'tag'
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use push config tag filter
|
You can also use push config tag filter
|
||||||
@@ -72,9 +62,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
```
|
```
|
||||||
|
|
||||||
### ⬆️ Uploading release assets
|
### ⬆️ Uploading release assets
|
||||||
@@ -85,7 +75,6 @@ GitHub release and all are optional.
|
|||||||
A common case for GitHub releases is to upload your binary after its been validated and packaged.
|
A common case for GitHub releases is to upload your binary after its been validated and packaged.
|
||||||
Use the `with.files` input to declare a newline-delimited list of glob expressions matching the files
|
Use the `with.files` input to declare a newline-delimited list of glob expressions matching the files
|
||||||
you wish to upload to GitHub releases. If you'd like you can just list the files by name directly.
|
you wish to upload to GitHub releases. If you'd like you can just list the files by name directly.
|
||||||
If a tag already has a GitHub release, the existing release will be updated with the release assets.
|
|
||||||
|
|
||||||
Below is an example of uploading a single asset named `Release.txt`
|
Below is an example of uploading a single asset named `Release.txt`
|
||||||
|
|
||||||
@@ -99,14 +88,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
run: echo ${{ github.sha }} > Release.txt
|
run: echo ${{ github.sha }} > Release.txt
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cat Release.txt
|
run: cat Release.txt
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
if: github.ref_type == 'tag'
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
files: Release.txt
|
files: Release.txt
|
||||||
```
|
```
|
||||||
@@ -123,23 +112,21 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
run: echo ${{ github.sha }} > Release.txt
|
run: echo ${{ github.sha }} > Release.txt
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cat Release.txt
|
run: cat Release.txt
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
if: github.ref_type == 'tag'
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
Release.txt
|
Release.txt
|
||||||
LICENSE
|
LICENSE
|
||||||
```
|
```
|
||||||
|
|
||||||
> **⚠️ Note:** Notice the `|` in the yaml syntax above ☝️. That lets you effectively declare a multi-line yaml string. You can learn more about multi-line yaml syntax [here](https://yaml-multiline.info)
|
> **⚠️ Note:** Notice the `|` in the yaml syntax above ☝️. That let's you effectively declare a multi-line yaml string. You can learn more about multi-line yaml syntax [here](https://yaml-multiline.info)
|
||||||
|
|
||||||
> **⚠️ Note for Windows:** Paths must use `/` as a separator, not `\`, as `\` is used to escape characters with special meaning in the pattern; for example, instead of specifying `D:\Foo.txt`, you must specify `D:/Foo.txt`. If you're using PowerShell, you can do this with `$Path = $Path -replace '\\','/'`
|
|
||||||
|
|
||||||
### 📝 External release notes
|
### 📝 External release notes
|
||||||
|
|
||||||
@@ -157,18 +144,19 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
- 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
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v1
|
||||||
if: github.ref_type == 'tag'
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
body_path: ${{ github.workspace }}-CHANGELOG.txt
|
body_path: ${{ github.workspace }}-CHANGELOG.txt
|
||||||
repository: my_gh_org/my_gh_repo
|
|
||||||
# note you'll typically need to create a personal access token
|
# note you'll typically need to create a personal access token
|
||||||
# with permissions to create releases in the other repo
|
# with permissions to create releases in the other repo
|
||||||
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||||
|
env:
|
||||||
|
GITHUB_REPOSITORY: my_gh_org/my_gh_repo
|
||||||
```
|
```
|
||||||
|
|
||||||
### 💅 Customizing
|
### 💅 Customizing
|
||||||
@@ -177,25 +165,20 @@ jobs:
|
|||||||
|
|
||||||
The following are optional as `step.with` keys
|
The following are optional as `step.with` keys
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| -------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `body` | String | Text communicating notable changes in this release |
|
| `body` | String | Text communicating notable changes in this release |
|
||||||
| `body_path` | String | Path to load text communicating notable changes in this release |
|
| `body_path` | String | Path to load text communicating notable changes in this release |
|
||||||
| `draft` | Boolean | Indicator of whether or not this release is a draft |
|
| `draft` | Boolean | Indicator of whether or not this release is a draft |
|
||||||
| `prerelease` | Boolean | Indicator of whether or not is a prerelease |
|
| `prerelease` | Boolean | Indicator of whether or not is a prerelease |
|
||||||
| `preserve_order` | Boolean | Indicator of whether order of files should be preserved when uploading assets |
|
| `files` | String | Newline-delimited globs of paths to assets to upload for release |
|
||||||
| `files` | String | Newline-delimited globs of paths to assets to upload for release |
|
| `name` | String | Name of the release. defaults to tag name |
|
||||||
| `overwrite_files` | Boolean | Indicator of whether files should be overwritten when they already exist. Defaults to true |
|
| `tag_name` | String | Name of a tag. defaults to `github.ref` |
|
||||||
| `name` | String | Name of the release. defaults to tag name |
|
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
|
||||||
| `tag_name` | String | Name of a tag. defaults to `github.ref_name` |
|
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
|
||||||
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
|
| `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. |
|
||||||
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
|
| `token` | String | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}` |
|
||||||
| `target_commitish` | String | Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA. Defaults to repository default branch. |
|
| `discussion_category_name` | String | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository) |
|
||||||
| `token` | String | Secret GitHub Personal Access Token. Defaults to `${{ github.token }}` |
|
|
||||||
| `discussion_category_name` | String | If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. For more information, see ["Managing categories for discussions in your repository."](https://docs.github.com/en/discussions/managing-discussions-for-your-community/managing-categories-for-discussions-in-your-repository) |
|
|
||||||
| `generate_release_notes` | Boolean | Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise, a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes. See the [GitHub docs for this feature](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes) for more information |
|
|
||||||
| `append_body` | Boolean | Append to existing body instead of overwriting it |
|
|
||||||
| `make_latest` | String | Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest. Can be `true`, `false`, or `legacy`. Uses GitHub api defaults if not provided |
|
|
||||||
|
|
||||||
💡 When providing a `body` and `body_path` at the same time, `body_path` will be
|
💡 When providing a `body` and `body_path` at the same time, `body_path` will be
|
||||||
attempted first, then falling back on `body` if the path can not be read from.
|
attempted first, then falling back on `body` if the path can not be read from.
|
||||||
@@ -208,14 +191,11 @@ release will retain its original info.
|
|||||||
|
|
||||||
The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
|
The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------ | ------ | --------------------------------------- |
|
||||||
| `url` | String | Github.com URL for the release |
|
| `url` | String | Github.com URL for the release |
|
||||||
| `id` | String | Release ID |
|
| `id` | String | Release ID |
|
||||||
| `upload_url` | String | URL for uploading assets to the release |
|
| `upload_url` | String | URL for uploading assets to the release |
|
||||||
| `assets` | String | JSON array containing information about each updated (newly uploaded or overwritten) asset, in the format given [here](https://docs.github.com/en/rest/releases/assets#get-a-release-asset) (minus the `uploader` field) |
|
|
||||||
|
|
||||||
As an example, you can use `${{ fromJSON(steps.<step-id>.outputs.assets)[0].browser_download_url }}` to get the download URL of the first asset.
|
|
||||||
|
|
||||||
#### environment variables
|
#### environment variables
|
||||||
|
|
||||||
@@ -228,26 +208,4 @@ The following `step.env` keys are allowed as a fallback but deprecated in favor
|
|||||||
|
|
||||||
> **⚠️ Note:** This action was previously implemented as a Docker container, limiting its use to GitHub Actions Linux virtual environments only. With recent releases, we now support cross platform usage. You'll need to remove the `docker://` prefix in these versions
|
> **⚠️ Note:** This action was previously implemented as a Docker container, limiting its use to GitHub Actions Linux virtual environments only. With recent releases, we now support cross platform usage. You'll need to remove the `docker://` prefix in these versions
|
||||||
|
|
||||||
### Permissions
|
|
||||||
|
|
||||||
This Action requires the following permissions on the GitHub integration token:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
```
|
|
||||||
|
|
||||||
When used with `discussion_category_name`, additional permission is needed:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
discussions: write
|
|
||||||
```
|
|
||||||
|
|
||||||
[GitHub token permissions](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) can be set for an individual job, workflow, or for Actions as a whole.
|
|
||||||
|
|
||||||
Note that if you intend to run workflows on the release event (`on: { release: { types: [published] } }`), you need to use
|
|
||||||
a personal access token for this action, as the [default `secrets.GITHUB_TOKEN` does not trigger another workflow](https://github.com/actions/create-release/issues/71).
|
|
||||||
|
|
||||||
Doug Tangren (softprops) 2019
|
Doug Tangren (softprops) 2019
|
||||||
+16
-264
@@ -1,273 +1,25 @@
|
|||||||
import {
|
//import * as assert from "assert";
|
||||||
asset,
|
//const assert = require('assert');
|
||||||
findTagFromReleases,
|
import * as assert from "assert";
|
||||||
finalizeRelease,
|
import { mimeOrDefault, asset } from "../src/github";
|
||||||
mimeOrDefault,
|
|
||||||
release,
|
|
||||||
Release,
|
|
||||||
Releaser,
|
|
||||||
} from '../src/github';
|
|
||||||
|
|
||||||
import { assert, describe, expect, it, vi } from 'vitest';
|
describe("github", () => {
|
||||||
|
describe("mimeOrDefault", () => {
|
||||||
describe('github', () => {
|
it("returns a specific mime for common path", async () => {
|
||||||
const config = {
|
assert.equal(mimeOrDefault("foo.tar.gz"), "application/gzip");
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('mimeOrDefault', () => {
|
|
||||||
it('returns a specific mime for common path', async () => {
|
|
||||||
assert.equal(mimeOrDefault('foo.tar.gz'), 'application/gzip');
|
|
||||||
});
|
});
|
||||||
it('returns default mime for uncommon path', async () => {
|
it("returns default mime for uncommon path", async () => {
|
||||||
assert.equal(mimeOrDefault('foo.uncommon'), 'application/octet-stream');
|
assert.equal(mimeOrDefault("foo.uncommon"), "application/octet-stream");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('asset', () => {
|
describe("asset", () => {
|
||||||
it('derives asset info from a path', async () => {
|
it("derives asset info from a path", async () => {
|
||||||
const { name, mime, size } = asset('tests/data/foo/bar.txt');
|
const { name, mime, size, data } = asset("tests/data/foo/bar.txt");
|
||||||
assert.equal(name, 'bar.txt');
|
assert.equal(name, "bar.txt");
|
||||||
assert.equal(mime, 'text/plain');
|
assert.equal(mime, "text/plain");
|
||||||
assert.equal(size, 10);
|
assert.equal(size, 10);
|
||||||
});
|
assert.equal(data.toString(), "release me");
|
||||||
});
|
|
||||||
|
|
||||||
describe('findTagFromReleases', () => {
|
|
||||||
const owner = 'owner';
|
|
||||||
const repo = 'repo';
|
|
||||||
|
|
||||||
const mockRelease: Release = {
|
|
||||||
id: 1,
|
|
||||||
upload_url: `https://api.github.com/repos/${owner}/${repo}/releases/1/assets`,
|
|
||||||
html_url: `https://github.com/${owner}/${repo}/releases/tag/v1.0.0`,
|
|
||||||
tag_name: 'v1.0.0',
|
|
||||||
name: 'Test Release',
|
|
||||||
body: 'Test body',
|
|
||||||
target_commitish: 'main',
|
|
||||||
draft: false,
|
|
||||||
prerelease: false,
|
|
||||||
assets: [],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const mockReleaser: Releaser = {
|
|
||||||
getReleaseByTag: () => Promise.reject({ status: 404 }),
|
|
||||||
createRelease: () => Promise.reject('Not implemented'),
|
|
||||||
updateRelease: () => Promise.reject('Not implemented'),
|
|
||||||
finalizeRelease: () => Promise.reject('Not implemented'),
|
|
||||||
allReleases: async function* () {
|
|
||||||
yield { data: [mockRelease] };
|
|
||||||
},
|
|
||||||
listReleaseAssets: () => Promise.reject('Not implemented'),
|
|
||||||
deleteReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
uploadReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
it('finds a release by tag using direct API lookup', async () => {
|
|
||||||
const targetTag = 'v1.0.0';
|
|
||||||
const targetRelease = {
|
|
||||||
...mockRelease,
|
|
||||||
tag_name: targetTag,
|
|
||||||
};
|
|
||||||
|
|
||||||
const releaser = {
|
|
||||||
...mockReleaser,
|
|
||||||
getReleaseByTag: () => Promise.resolve({ data: targetRelease }),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await findTagFromReleases(releaser, owner, repo, targetTag);
|
|
||||||
|
|
||||||
assert.deepStrictEqual(result, targetRelease);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns undefined when release is not found (404)', async () => {
|
|
||||||
const releaser = {
|
|
||||||
...mockReleaser,
|
|
||||||
getReleaseByTag: () => Promise.reject({ status: 404 }),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await findTagFromReleases(releaser, owner, repo, 'nonexistent');
|
|
||||||
|
|
||||||
assert.strictEqual(result, undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('re-throws non-404 errors', async () => {
|
|
||||||
const releaser = {
|
|
||||||
...mockReleaser,
|
|
||||||
getReleaseByTag: () => Promise.reject({ status: 500, message: 'Server error' }),
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
await findTagFromReleases(releaser, owner, repo, 'v1.0.0');
|
|
||||||
assert.fail('Expected an error to be thrown');
|
|
||||||
} catch (error) {
|
|
||||||
assert.strictEqual(error.status, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('finds a release with empty tag name', async () => {
|
|
||||||
const emptyTag = '';
|
|
||||||
const targetRelease = {
|
|
||||||
...mockRelease,
|
|
||||||
tag_name: emptyTag,
|
|
||||||
};
|
|
||||||
|
|
||||||
const releaser = {
|
|
||||||
...mockReleaser,
|
|
||||||
getReleaseByTag: () => Promise.resolve({ data: targetRelease }),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await findTagFromReleases(releaser, owner, repo, emptyTag);
|
|
||||||
|
|
||||||
assert.deepStrictEqual(result, targetRelease);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('finalizeRelease input_draft behavior', () => {
|
|
||||||
const draftRelease: Release = {
|
|
||||||
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: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
const finalizedRelease: Release = {
|
|
||||||
...draftRelease,
|
|
||||||
draft: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
{
|
|
||||||
name: 'returns early when input_draft is true',
|
|
||||||
input_draft: true,
|
|
||||||
expectedCalls: 0,
|
|
||||||
expectedResult: draftRelease,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'finalizes release when input_draft is false',
|
|
||||||
input_draft: false,
|
|
||||||
expectedCalls: 1,
|
|
||||||
expectedResult: finalizedRelease,
|
|
||||||
},
|
|
||||||
])('$name', async ({ input_draft, expectedCalls, expectedResult }) => {
|
|
||||||
const finalizeReleaseSpy = vi.fn(async () => ({ data: finalizedRelease }));
|
|
||||||
|
|
||||||
const releaser: Releaser = {
|
|
||||||
getReleaseByTag: () => Promise.reject('Not implemented'),
|
|
||||||
createRelease: () => Promise.reject('Not implemented'),
|
|
||||||
updateRelease: () => Promise.reject('Not implemented'),
|
|
||||||
finalizeRelease: finalizeReleaseSpy,
|
|
||||||
allReleases: async function* () {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
},
|
|
||||||
listReleaseAssets: () => Promise.reject('Not implemented'),
|
|
||||||
deleteReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
uploadReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await finalizeRelease(
|
|
||||||
{
|
|
||||||
...config,
|
|
||||||
input_draft,
|
|
||||||
},
|
|
||||||
releaser,
|
|
||||||
draftRelease,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(finalizeReleaseSpy).toHaveBeenCalledTimes(expectedCalls);
|
|
||||||
assert.strictEqual(result, expectedResult);
|
|
||||||
|
|
||||||
if (expectedCalls === 1) {
|
|
||||||
expect(finalizeReleaseSpy).toHaveBeenCalledWith({
|
|
||||||
owner: 'owner',
|
|
||||||
repo: 'repo',
|
|
||||||
release_id: draftRelease.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('error handling', () => {
|
|
||||||
it('handles 422 already_exists error gracefully', async () => {
|
|
||||||
const existingRelease = {
|
|
||||||
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: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
let createAttempts = 0;
|
|
||||||
const mockReleaser: Releaser = {
|
|
||||||
getReleaseByTag: ({ tag }) => {
|
|
||||||
// First call returns 404 (release doesn't exist yet), subsequent calls find it
|
|
||||||
if (createAttempts === 0) {
|
|
||||||
return Promise.reject({ status: 404 });
|
|
||||||
}
|
|
||||||
return Promise.resolve({ data: existingRelease });
|
|
||||||
},
|
|
||||||
createRelease: () => {
|
|
||||||
createAttempts++;
|
|
||||||
return 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: () => Promise.reject('Not implemented'),
|
|
||||||
allReleases: async function* () {
|
|
||||||
yield { data: [existingRelease] };
|
|
||||||
},
|
|
||||||
listReleaseAssets: () => Promise.reject('Not implemented'),
|
|
||||||
deleteReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
uploadReleaseAsset: () => Promise.reject('Not implemented'),
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const result = await release(config, mockReleaser, 2);
|
|
||||||
assert.ok(result);
|
|
||||||
assert.equal(result.id, 1);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+170
-437
@@ -1,525 +1,258 @@
|
|||||||
import {
|
import {
|
||||||
alignAssetName,
|
releaseBody,
|
||||||
isTag,
|
isTag,
|
||||||
|
paths,
|
||||||
parseConfig,
|
parseConfig,
|
||||||
parseInputFiles,
|
parseInputFiles,
|
||||||
paths,
|
|
||||||
releaseBody,
|
|
||||||
unmatchedPatterns,
|
unmatchedPatterns,
|
||||||
uploadUrl,
|
uploadUrl
|
||||||
} from '../src/util';
|
} from "../src/util";
|
||||||
|
import * as assert from "assert";
|
||||||
|
|
||||||
import { assert, describe, expect, it } from 'vitest';
|
describe("util", () => {
|
||||||
|
describe("uploadUrl", () => {
|
||||||
describe('util', () => {
|
it("stripts template", () => {
|
||||||
describe('uploadUrl', () => {
|
|
||||||
it('strips template', () => {
|
|
||||||
assert.equal(
|
assert.equal(
|
||||||
uploadUrl(
|
uploadUrl(
|
||||||
'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}',
|
"https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}"
|
||||||
),
|
),
|
||||||
'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets',
|
"https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('parseInputFiles', () => {
|
describe("parseInputFiles", () => {
|
||||||
it('parses empty strings', () => {
|
it("parses empty strings", () => {
|
||||||
assert.deepStrictEqual(parseInputFiles(''), []);
|
assert.deepStrictEqual(parseInputFiles(""), []);
|
||||||
});
|
});
|
||||||
it('parses comma-delimited strings', () => {
|
it("parses comma-delimited strings", () => {
|
||||||
assert.deepStrictEqual(parseInputFiles('foo,bar'), ['foo', 'bar']);
|
assert.deepStrictEqual(parseInputFiles("foo,bar"), ["foo", "bar"]);
|
||||||
});
|
});
|
||||||
it('parses newline and comma-delimited (and then some)', () => {
|
it("parses newline and comma-delimited (and then some)", () => {
|
||||||
assert.deepStrictEqual(parseInputFiles('foo,bar\nbaz,boom,\n\ndoom,loom '), [
|
assert.deepStrictEqual(
|
||||||
'foo',
|
parseInputFiles("foo,bar\nbaz,boom,\n\ndoom,loom "),
|
||||||
'bar',
|
["foo", "bar", "baz", "boom", "doom", "loom"]
|
||||||
'baz',
|
|
||||||
'boom',
|
|
||||||
'doom',
|
|
||||||
'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', () => {
|
|
||||||
assert.equal(
|
|
||||||
'foo',
|
|
||||||
releaseBody({
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_body: 'foo',
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: false,
|
|
||||||
input_prerelease: false,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: 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,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('uses input body path', () => {
|
|
||||||
assert.equal(
|
|
||||||
'bar',
|
|
||||||
releaseBody({
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: '__tests__/release.txt',
|
|
||||||
input_draft: false,
|
|
||||||
input_prerelease: false,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: 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,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('defaults to body path when both body and body path are provided', () => {
|
|
||||||
assert.equal(
|
|
||||||
'bar',
|
|
||||||
releaseBody({
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_body: 'foo',
|
|
||||||
input_body_path: '__tests__/release.txt',
|
|
||||||
input_draft: false,
|
|
||||||
input_prerelease: false,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: 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,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
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("releaseBody", () => {
|
||||||
it('parses basic config', () => {
|
it("uses input body", () => {
|
||||||
|
assert.equal(
|
||||||
|
"foo",
|
||||||
|
releaseBody({
|
||||||
|
github_ref: "",
|
||||||
|
github_repository: "",
|
||||||
|
github_token: "",
|
||||||
|
input_body: "foo",
|
||||||
|
input_body_path: undefined,
|
||||||
|
input_draft: false,
|
||||||
|
input_prerelease: false,
|
||||||
|
input_files: [],
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("uses input body path", () => {
|
||||||
|
assert.equal(
|
||||||
|
"bar",
|
||||||
|
releaseBody({
|
||||||
|
github_ref: "",
|
||||||
|
github_repository: "",
|
||||||
|
github_token: "",
|
||||||
|
input_body: undefined,
|
||||||
|
input_body_path: "__tests__/release.txt",
|
||||||
|
input_draft: false,
|
||||||
|
input_prerelease: false,
|
||||||
|
input_files: [],
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("defaults to body path when both body and body path are provided", () => {
|
||||||
|
assert.equal(
|
||||||
|
"bar",
|
||||||
|
releaseBody({
|
||||||
|
github_ref: "",
|
||||||
|
github_repository: "",
|
||||||
|
github_token: "",
|
||||||
|
input_body: "foo",
|
||||||
|
input_body_path: "__tests__/release.txt",
|
||||||
|
input_draft: false,
|
||||||
|
input_prerelease: false,
|
||||||
|
input_files: [],
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe("parseConfig", () => {
|
||||||
|
it("parses basic config", () => {
|
||||||
|
assert.deepStrictEqual(parseConfig({}), {
|
||||||
|
github_ref: "",
|
||||||
|
github_repository: "",
|
||||||
|
github_token: "",
|
||||||
|
input_body: undefined,
|
||||||
|
input_body_path: undefined,
|
||||||
|
input_draft: undefined,
|
||||||
|
input_prerelease: undefined,
|
||||||
|
input_files: [],
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_fail_on_unmatched_files: false,
|
||||||
|
input_target_commitish: undefined,
|
||||||
|
input_discussion_category_name: undefined
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("parses basic config with commitish", () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
parseConfig({
|
parseConfig({
|
||||||
// note: inputs declared in actions.yml, even when declared not required,
|
INPUT_TARGET_COMMITISH: "affa18ef97bc9db20076945705aba8c516139abd"
|
||||||
// are still provided by the actions runtime env as empty strings instead of
|
|
||||||
// the normal absent env value one would expect. this breaks things
|
|
||||||
// as an empty string !== undefined in terms of what we pass to the api
|
|
||||||
// so we cover that in a test case here to ensure undefined values are actually
|
|
||||||
// resolved as undefined and not empty strings
|
|
||||||
INPUT_TARGET_COMMITISH: '',
|
|
||||||
INPUT_DISCUSSION_CATEGORY_NAME: '',
|
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
github_ref: '',
|
github_ref: "",
|
||||||
github_repository: '',
|
github_repository: "",
|
||||||
github_token: '',
|
github_token: "",
|
||||||
input_working_directory: undefined,
|
input_body: undefined,
|
||||||
input_append_body: false,
|
input_body_path: undefined,
|
||||||
|
input_draft: undefined,
|
||||||
|
input_prerelease: undefined,
|
||||||
|
input_files: [],
|
||||||
|
input_name: undefined,
|
||||||
|
input_tag_name: undefined,
|
||||||
|
input_fail_on_unmatched_files: false,
|
||||||
|
input_target_commitish: "affa18ef97bc9db20076945705aba8c516139abd",
|
||||||
|
input_discussion_category_name: undefined
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it("supports discussion category names", () => {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
parseConfig({
|
||||||
|
INPUT_DISCUSSION_CATEGORY_NAME: "releases"
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
github_ref: "",
|
||||||
|
github_repository: "",
|
||||||
|
github_token: "",
|
||||||
input_body: undefined,
|
input_body: undefined,
|
||||||
input_body_path: undefined,
|
input_body_path: undefined,
|
||||||
input_draft: undefined,
|
input_draft: undefined,
|
||||||
input_prerelease: undefined,
|
input_prerelease: undefined,
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
input_files: [],
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
input_name: undefined,
|
||||||
input_tag_name: undefined,
|
input_tag_name: undefined,
|
||||||
input_fail_on_unmatched_files: false,
|
input_fail_on_unmatched_files: false,
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: "releases"
|
||||||
input_generate_release_notes: false,
|
}
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it("prefers GITHUB_TOKEN over token input for backwards compatibility", () => {
|
||||||
it('parses basic config with commitish', () => {
|
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
parseConfig({
|
parseConfig({
|
||||||
INPUT_TARGET_COMMITISH: 'affa18ef97bc9db20076945705aba8c516139abd',
|
INPUT_DRAFT: "false",
|
||||||
|
INPUT_PRERELEASE: "true",
|
||||||
|
GITHUB_TOKEN: "env-token",
|
||||||
|
INPUT_TOKEN: "input-token"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
github_ref: '',
|
github_ref: "",
|
||||||
github_repository: '',
|
github_repository: "",
|
||||||
github_token: '',
|
github_token: "env-token",
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: undefined,
|
|
||||||
input_prerelease: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_name: undefined,
|
|
||||||
input_tag_name: undefined,
|
|
||||||
input_fail_on_unmatched_files: false,
|
|
||||||
input_target_commitish: 'affa18ef97bc9db20076945705aba8c516139abd',
|
|
||||||
input_discussion_category_name: undefined,
|
|
||||||
input_generate_release_notes: false,
|
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('supports discussion category names', () => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
parseConfig({
|
|
||||||
INPUT_DISCUSSION_CATEGORY_NAME: 'releases',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: undefined,
|
|
||||||
input_prerelease: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_name: undefined,
|
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_tag_name: undefined,
|
|
||||||
input_fail_on_unmatched_files: false,
|
|
||||||
input_target_commitish: undefined,
|
|
||||||
input_discussion_category_name: 'releases',
|
|
||||||
input_generate_release_notes: false,
|
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('supports generating release notes', () => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
parseConfig({
|
|
||||||
INPUT_GENERATE_RELEASE_NOTES: 'true',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: undefined,
|
|
||||||
input_prerelease: undefined,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
|
||||||
input_tag_name: undefined,
|
|
||||||
input_fail_on_unmatched_files: false,
|
|
||||||
input_target_commitish: undefined,
|
|
||||||
input_discussion_category_name: undefined,
|
|
||||||
input_generate_release_notes: true,
|
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('prefers GITHUB_TOKEN over token input for backwards compatibility', () => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
parseConfig({
|
|
||||||
INPUT_DRAFT: 'false',
|
|
||||||
INPUT_PRERELEASE: 'true',
|
|
||||||
INPUT_PRESERVE_ORDER: 'true',
|
|
||||||
GITHUB_TOKEN: 'env-token',
|
|
||||||
INPUT_TOKEN: 'input-token',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: 'env-token',
|
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
input_body: undefined,
|
||||||
input_body_path: undefined,
|
input_body_path: undefined,
|
||||||
input_draft: false,
|
input_draft: false,
|
||||||
input_prerelease: true,
|
input_prerelease: true,
|
||||||
input_preserve_order: true,
|
|
||||||
input_files: [],
|
input_files: [],
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
input_name: undefined,
|
||||||
input_tag_name: undefined,
|
input_tag_name: undefined,
|
||||||
input_fail_on_unmatched_files: false,
|
input_fail_on_unmatched_files: false,
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined
|
||||||
input_generate_release_notes: false,
|
}
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('uses input token as the source of GITHUB_TOKEN by default', () => {
|
it("uses input token as the source of GITHUB_TOKEN by default", () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
parseConfig({
|
parseConfig({
|
||||||
INPUT_DRAFT: 'false',
|
INPUT_DRAFT: "false",
|
||||||
INPUT_PRERELEASE: 'true',
|
INPUT_PRERELEASE: "true",
|
||||||
INPUT_TOKEN: 'input-token',
|
INPUT_TOKEN: "input-token"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
github_ref: '',
|
github_ref: "",
|
||||||
github_repository: '',
|
github_repository: "",
|
||||||
github_token: 'input-token',
|
github_token: "input-token",
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
input_body: undefined,
|
||||||
input_body_path: undefined,
|
input_body_path: undefined,
|
||||||
input_draft: false,
|
input_draft: false,
|
||||||
input_prerelease: true,
|
input_prerelease: true,
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
input_files: [],
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
input_name: undefined,
|
||||||
input_tag_name: undefined,
|
input_tag_name: undefined,
|
||||||
input_fail_on_unmatched_files: false,
|
input_fail_on_unmatched_files: false,
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined
|
||||||
input_generate_release_notes: false,
|
}
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('parses basic config with draft and prerelease', () => {
|
it("parses basic config with draft and prerelease", () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
parseConfig({
|
parseConfig({
|
||||||
INPUT_DRAFT: 'false',
|
INPUT_DRAFT: "false",
|
||||||
INPUT_PRERELEASE: 'true',
|
INPUT_PRERELEASE: "true"
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
github_ref: '',
|
github_ref: "",
|
||||||
github_repository: '',
|
github_repository: "",
|
||||||
github_token: '',
|
github_token: "",
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
input_body: undefined,
|
||||||
input_body_path: undefined,
|
input_body_path: undefined,
|
||||||
input_draft: false,
|
input_draft: false,
|
||||||
input_prerelease: true,
|
input_prerelease: true,
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
input_files: [],
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
input_name: undefined,
|
||||||
input_tag_name: undefined,
|
input_tag_name: undefined,
|
||||||
input_fail_on_unmatched_files: false,
|
input_fail_on_unmatched_files: false,
|
||||||
input_target_commitish: undefined,
|
input_target_commitish: undefined,
|
||||||
input_discussion_category_name: undefined,
|
input_discussion_category_name: undefined
|
||||||
input_generate_release_notes: false,
|
}
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('parses basic config where make_latest is passed', () => {
|
});
|
||||||
|
describe("isTag", () => {
|
||||||
|
it("returns true for tags", async () => {
|
||||||
|
assert.equal(isTag("refs/tags/foo"), true);
|
||||||
|
});
|
||||||
|
it("returns false for other kinds of refs", async () => {
|
||||||
|
assert.equal(isTag("refs/heads/master"), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("paths", () => {
|
||||||
|
it("resolves files given a set of paths", async () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
parseConfig({
|
paths(["tests/data/**/*", "tests/data/does/not/exist/*"]),
|
||||||
INPUT_MAKE_LATEST: 'false',
|
["tests/data/foo/bar.txt"]
|
||||||
}),
|
|
||||||
{
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: false,
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: undefined,
|
|
||||||
input_prerelease: undefined,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_name: undefined,
|
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_tag_name: undefined,
|
|
||||||
input_fail_on_unmatched_files: false,
|
|
||||||
input_target_commitish: undefined,
|
|
||||||
input_discussion_category_name: undefined,
|
|
||||||
input_generate_release_notes: false,
|
|
||||||
input_make_latest: 'false',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
it('parses basic config with append_body', () => {
|
|
||||||
assert.deepStrictEqual(
|
|
||||||
parseConfig({
|
|
||||||
INPUT_APPEND_BODY: 'true',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
github_ref: '',
|
|
||||||
github_repository: '',
|
|
||||||
github_token: '',
|
|
||||||
input_working_directory: undefined,
|
|
||||||
input_append_body: true,
|
|
||||||
input_body: undefined,
|
|
||||||
input_body_path: undefined,
|
|
||||||
input_draft: undefined,
|
|
||||||
input_prerelease: undefined,
|
|
||||||
input_preserve_order: undefined,
|
|
||||||
input_files: [],
|
|
||||||
input_overwrite_files: undefined,
|
|
||||||
input_name: undefined,
|
|
||||||
input_tag_name: undefined,
|
|
||||||
input_fail_on_unmatched_files: false,
|
|
||||||
input_target_commitish: undefined,
|
|
||||||
input_discussion_category_name: undefined,
|
|
||||||
input_generate_release_notes: false,
|
|
||||||
input_make_latest: undefined,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('isTag', () => {
|
|
||||||
it('returns true for tags', async () => {
|
|
||||||
assert.equal(isTag('refs/tags/foo'), true);
|
|
||||||
});
|
|
||||||
it('returns false for other kinds of refs', async () => {
|
|
||||||
assert.equal(isTag('refs/heads/master'), false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('paths', () => {
|
describe("unmatchedPatterns", () => {
|
||||||
it('resolves files given a set of paths', async () => {
|
|
||||||
assert.deepStrictEqual(paths(['tests/data/**/*', 'tests/data/does/not/exist/*']), [
|
|
||||||
'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', () => {
|
|
||||||
it("returns the patterns that don't match any files", async () => {
|
it("returns the patterns that don't match any files", async () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
unmatchedPatterns(['tests/data/**/*', 'tests/data/does/not/exist/*']),
|
unmatchedPatterns(["tests/data/**/*", "tests/data/does/not/exist/*"]),
|
||||||
['tests/data/does/not/exist/*'],
|
["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', () => {
|
|
||||||
it('replaces all spaces with dots', () => {
|
|
||||||
expect(alignAssetName('John Doe.bla')).toBe('John.Doe.bla');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('handles names with multiple spaces', () => {
|
|
||||||
expect(alignAssetName('John William Doe.bla')).toBe('John.William.Doe.bla');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns the same string if there are no spaces', () => {
|
|
||||||
expect(alignAssetName('JohnDoe')).toBe('JohnDoe');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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',
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
+3
-24
@@ -13,7 +13,7 @@ inputs:
|
|||||||
description: "Gives the release a custom name. Defaults to tag name"
|
description: "Gives the release a custom name. Defaults to tag name"
|
||||||
required: false
|
required: false
|
||||||
tag_name:
|
tag_name:
|
||||||
description: "Gives a tag name. Defaults to github.ref_name"
|
description: "Gives a tag name. Defaults to github.GITHUB_REF"
|
||||||
required: false
|
required: false
|
||||||
draft:
|
draft:
|
||||||
description: "Creates a draft release. Defaults to false"
|
description: "Creates a draft release. Defaults to false"
|
||||||
@@ -21,19 +21,9 @@ inputs:
|
|||||||
prerelease:
|
prerelease:
|
||||||
description: "Identify the release as a prerelease. Defaults to false"
|
description: "Identify the release as a prerelease. Defaults to false"
|
||||||
required: false
|
required: false
|
||||||
preserve_order:
|
|
||||||
description: "Preserver the order of the artifacts when uploading"
|
|
||||||
required: false
|
|
||||||
files:
|
files:
|
||||||
description: "Newline-delimited list of path globs for asset files to upload"
|
description: "Newline-delimited list of path globs for asset files to upload"
|
||||||
required: false
|
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
|
|
||||||
default: 'true'
|
|
||||||
fail_on_unmatched_files:
|
fail_on_unmatched_files:
|
||||||
description: "Fails if any of the `files` globs match nothing. Defaults to false"
|
description: "Fails if any of the `files` globs match nothing. Defaults to false"
|
||||||
required: false
|
required: false
|
||||||
@@ -50,17 +40,8 @@ inputs:
|
|||||||
discussion_category_name:
|
discussion_category_name:
|
||||||
description: "If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. If there is already a discussion linked to the release, this parameter is ignored."
|
description: "If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository. If there is already a discussion linked to the release, this parameter is ignored."
|
||||||
required: false
|
required: false
|
||||||
generate_release_notes:
|
|
||||||
description: "Whether to automatically generate the name and body for this release. If name is specified, the specified name will be used; otherwise, a name will be automatically generated. If body is specified, the body will be pre-pended to the automatically generated notes."
|
|
||||||
required: false
|
|
||||||
append_body:
|
|
||||||
description: "Append to existing body instead of overwriting it. Default is false."
|
|
||||||
required: false
|
|
||||||
make_latest:
|
|
||||||
description: "Specifies whether this release should be set as the latest release for the repository. Drafts and prereleases cannot be set as latest. Can be `true`, `false`, or `legacy`. Uses GitHub api default if not provided"
|
|
||||||
required: false
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: "As provided by Github Actions"
|
"GITHUB_TOKEN": "As provided by Github Actions"
|
||||||
outputs:
|
outputs:
|
||||||
url:
|
url:
|
||||||
description: "URL to the Release HTML Page"
|
description: "URL to the Release HTML Page"
|
||||||
@@ -68,10 +49,8 @@ outputs:
|
|||||||
description: "Release ID"
|
description: "Release ID"
|
||||||
upload_url:
|
upload_url:
|
||||||
description: "URL for uploading assets to the release"
|
description: "URL for uploading assets to the release"
|
||||||
assets:
|
|
||||||
description: "JSON array containing information about each uploaded asset, in the format given [here](https://docs.github.com/en/rest/reference/repos#upload-a-release-asset--code-samples) (minus the `uploader` field)"
|
|
||||||
runs:
|
runs:
|
||||||
using: "node20"
|
using: "node12"
|
||||||
main: "dist/index.js"
|
main: "dist/index.js"
|
||||||
branding:
|
branding:
|
||||||
color: "green"
|
color: "green"
|
||||||
|
|||||||
Vendored
+1
-88
@@ -1,88 +1 @@
|
|||||||
"use strict";var Dw=Object.create;var up=Object.defineProperty;var Rw=Object.getOwnPropertyDescriptor;var Tw=Object.getOwnPropertyNames;var Fw=Object.getPrototypeOf,Sw=Object.prototype.hasOwnProperty;var Q=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Uw=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Tw(t))!Sw.call(e,i)&&i!==s&&up(e,i,{get:()=>t[i],enumerable:!(r=Rw(t,i))||r.enumerable});return e};var de=(e,t,s)=>(s=e!=null?Dw(Fw(e)):{},Uw(t||!e||!e.__esModule?up(s,"default",{value:e,enumerable:!0}):s,e));var Cp=Q(Zs=>{"use strict";var M_=require("net"),Lw=require("tls"),$a=require("http"),fp=require("https"),_w=require("events"),L_=require("assert"),Yw=require("util");Zs.httpOverHttp=Ow;Zs.httpsOverHttp=Jw;Zs.httpOverHttps=Pw;Zs.httpsOverHttps=Hw;function Ow(e){var t=new Rt(e);return t.request=$a.request,t}function Jw(e){var t=new Rt(e);return t.request=$a.request,t.createSocket=Qp,t.defaultPort=443,t}function Pw(e){var t=new Rt(e);return t.request=fp.request,t}function Hw(e){var t=new Rt(e);return t.request=fp.request,t.createSocket=Qp,t.defaultPort=443,t}function Rt(e){var t=this;t.options=e||{},t.proxyOptions=t.options.proxy||{},t.maxSockets=t.options.maxSockets||$a.Agent.defaultMaxSockets,t.requests=[],t.sockets=[],t.on("free",function(r,i,o,n){for(var a=Bp(i,o,n),A=0,c=t.requests.length;A<c;++A){var u=t.requests[A];if(u.host===a.host&&u.port===a.port){t.requests.splice(A,1),u.request.onSocket(r);return}}r.destroy(),t.removeSocket(r)})}Yw.inherits(Rt,_w.EventEmitter);Rt.prototype.addRequest=function(t,s,r,i){var o=this,n=eA({request:t},o.options,Bp(s,r,i));if(o.sockets.length>=this.maxSockets){o.requests.push(n);return}o.createSocket(n,function(a){a.on("free",A),a.on("close",c),a.on("agentRemove",c),t.onSocket(a);function A(){o.emit("free",a,n)}function c(u){o.removeSocket(a),a.removeListener("free",A),a.removeListener("close",c),a.removeListener("agentRemove",c)}})};Rt.prototype.createSocket=function(t,s){var r=this,i={};r.sockets.push(i);var o=eA({},r.proxyOptions,{method:"CONNECT",path:t.host+":"+t.port,agent:!1,headers:{host:t.host+":"+t.port}});t.localAddress&&(o.localAddress=t.localAddress),o.proxyAuth&&(o.headers=o.headers||{},o.headers["Proxy-Authorization"]="Basic "+new Buffer(o.proxyAuth).toString("base64")),Zt("making CONNECT request");var n=r.request(o);n.useChunkedEncodingByDefault=!1,n.once("response",a),n.once("upgrade",A),n.once("connect",c),n.once("error",u),n.end();function a(l){l.upgrade=!0}function A(l,p,g){process.nextTick(function(){c(l,p,g)})}function c(l,p,g){if(n.removeAllListeners(),p.removeAllListeners(),l.statusCode!==200){Zt("tunneling socket could not be established, statusCode=%d",l.statusCode),p.destroy();var h=new Error("tunneling socket could not be established, statusCode="+l.statusCode);h.code="ECONNRESET",t.request.emit("error",h),r.removeSocket(i);return}if(g.length>0){Zt("got illegal response body from proxy"),p.destroy();var h=new Error("got illegal response body from proxy");h.code="ECONNRESET",t.request.emit("error",h),r.removeSocket(i);return}return Zt("tunneling connection has established"),r.sockets[r.sockets.indexOf(i)]=p,s(p)}function u(l){n.removeAllListeners(),Zt(`tunneling socket could not be established, cause=%s
|
module.exports=function(e,t){"use strict";var r={};function __webpack_require__(t){if(r[t]){return r[t].exports}var i=r[t]={i:t,l:false,exports:{}};e[t].call(i.exports,i,i.exports,__webpack_require__);i.l=true;return i.exports}__webpack_require__.ab=__dirname+"/";function startup(){return __webpack_require__(131)}return startup()}({3:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:true});function isObject(e){return Object.prototype.toString.call(e)==="[object Object]"}function isPlainObject(e){var t,r;if(isObject(e)===false)return false;t=e.constructor;if(t===undefined)return true;r=t.prototype;if(isObject(r)===false)return false;if(r.hasOwnProperty("isPrototypeOf")===false){return false}return true}t.isPlainObject=isPlainObject},4:function(e,t){"use strict";var r="\ufeff";t.PrependBOM=PrependBOMWrapper;function PrependBOMWrapper(e,t){this.encoder=e;this.addBOM=true}PrependBOMWrapper.prototype.write=function(e){if(this.addBOM){e=r+e;this.addBOM=false}return this.encoder.write(e)};PrependBOMWrapper.prototype.end=function(){return this.encoder.end()};t.StripBOM=StripBOMWrapper;function StripBOMWrapper(e,t){this.decoder=e;this.pass=false;this.options=t||{}}StripBOMWrapper.prototype.write=function(e){var t=this.decoder.write(e);if(this.pass||!t)return t;if(t[0]===r){t=t.slice(1);if(typeof this.options.stripBOM==="function")this.options.stripBOM()}this.pass=true;return t};StripBOMWrapper.prototype.end=function(){return this.decoder.end()}},11:function(e){e.exports=wrappy;function wrappy(e,t){if(e&&t)return wrappy(e)(t);if(typeof e!=="function")throw new TypeError("need wrapper function");Object.keys(e).forEach(function(t){wrapper[t]=e[t]});return wrapper;function wrapper(){var t=new Array(arguments.length);for(var r=0;r<t.length;r++){t[r]=arguments[r]}var i=e.apply(this,t);var n=t[t.length-1];if(typeof i==="function"&&i!==n){Object.keys(n).forEach(function(e){i[e]=n[e]})}return i}}},16:function(e){e.exports=require("tls")},21:function(e){"use strict";e.exports={437:"cp437",737:"cp737",775:"cp775",850:"cp850",852:"cp852",855:"cp855",856:"cp856",857:"cp857",858:"cp858",860:"cp860",861:"cp861",862:"cp862",863:"cp863",864:"cp864",865:"cp865",866:"cp866",869:"cp869",874:"windows874",922:"cp922",1046:"cp1046",1124:"cp1124",1125:"cp1125",1129:"cp1129",1133:"cp1133",1161:"cp1161",1162:"cp1162",1163:"cp1163",1250:"windows1250",1251:"windows1251",1252:"windows1252",1253:"windows1253",1254:"windows1254",1255:"windows1255",1256:"windows1256",1257:"windows1257",1258:"windows1258",28591:"iso88591",28592:"iso88592",28593:"iso88593",28594:"iso88594",28595:"iso88595",28596:"iso88596",28597:"iso88597",28598:"iso88598",28599:"iso88599",28600:"iso885910",28601:"iso885911",28603:"iso885913",28604:"iso885914",28605:"iso885915",28606:"iso885916",windows874:{type:"_sbcs",chars:"€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛����"},win874:"windows874",cp874:"windows874",windows1250:{type:"_sbcs",chars:"€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙"},win1250:"windows1250",cp1250:"windows1250",windows1251:{type:"_sbcs",chars:"ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя"},win1251:"windows1251",cp1251:"windows1251",windows1252:{type:"_sbcs",chars:"€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"},win1252:"windows1252",cp1252:"windows1252",windows1253:{type:"_sbcs",chars:"€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�"},win1253:"windows1253",cp1253:"windows1253",windows1254:{type:"_sbcs",chars:"€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖרÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿLine truncated
|
||||||
`,l.message,l.stack);var p=new Error("tunneling socket could not be established, cause="+l.message);p.code="ECONNRESET",t.request.emit("error",p),r.removeSocket(i)}};Rt.prototype.removeSocket=function(t){var s=this.sockets.indexOf(t);if(s!==-1){this.sockets.splice(s,1);var r=this.requests.shift();r&&this.createSocket(r,function(i){r.request.onSocket(i)})}};function Qp(e,t){var s=this;Rt.prototype.createSocket.call(s,e,function(r){var i=e.request.getHeader("host"),o=eA({},s.options,{socket:r,servername:i?i.replace(/:.*$/,""):e.host}),n=Lw.connect(0,o);s.sockets[s.sockets.indexOf(r)]=n,t(n)})}function Bp(e,t,s){return typeof e=="string"?{host:e,port:t,localAddress:s}:e}function eA(e){for(var t=1,s=arguments.length;t<s;++t){var r=arguments[t];if(typeof r=="object")for(var i=Object.keys(r),o=0,n=i.length;o<n;++o){var a=i[o];r[a]!==void 0&&(e[a]=r[a])}}return e}var Zt;process.env.NODE_DEBUG&&/\btunnel\b/.test(process.env.NODE_DEBUG)?Zt=function(){var e=Array.prototype.slice.call(arguments);typeof e[0]=="string"?e[0]="TUNNEL: "+e[0]:e.unshift("TUNNEL:"),console.error.apply(console,e)}:Zt=function(){};Zs.debug=Zt});var tA=Q((Y_,Ip)=>{Ip.exports=Cp()});var j=Q((O_,wp)=>{wp.exports={kClose:Symbol("close"),kDestroy:Symbol("destroy"),kDispatch:Symbol("dispatch"),kUrl:Symbol("url"),kWriting:Symbol("writing"),kResuming:Symbol("resuming"),kQueue:Symbol("queue"),kConnect:Symbol("connect"),kConnecting:Symbol("connecting"),kKeepAliveDefaultTimeout:Symbol("default keep alive timeout"),kKeepAliveMaxTimeout:Symbol("max keep alive timeout"),kKeepAliveTimeoutThreshold:Symbol("keep alive timeout threshold"),kKeepAliveTimeoutValue:Symbol("keep alive timeout"),kKeepAlive:Symbol("keep alive"),kHeadersTimeout:Symbol("headers timeout"),kBodyTimeout:Symbol("body timeout"),kServerName:Symbol("server name"),kLocalAddress:Symbol("local address"),kHost:Symbol("host"),kNoRef:Symbol("no ref"),kBodyUsed:Symbol("used"),kBody:Symbol("abstracted request body"),kRunning:Symbol("running"),kBlocking:Symbol("blocking"),kPending:Symbol("pending"),kSize:Symbol("size"),kBusy:Symbol("busy"),kQueued:Symbol("queued"),kFree:Symbol("free"),kConnected:Symbol("connected"),kClosed:Symbol("closed"),kNeedDrain:Symbol("need drain"),kReset:Symbol("reset"),kDestroyed:Symbol.for("nodejs.stream.destroyed"),kResume:Symbol("resume"),kOnError:Symbol("on error"),kMaxHeadersSize:Symbol("max headers size"),kRunningIdx:Symbol("running index"),kPendingIdx:Symbol("pending index"),kError:Symbol("error"),kClients:Symbol("clients"),kClient:Symbol("client"),kParser:Symbol("parser"),kOnDestroyed:Symbol("destroy callbacks"),kPipelining:Symbol("pipelining"),kSocket:Symbol("socket"),kHostHeader:Symbol("host header"),kConnector:Symbol("connector"),kStrictContentLength:Symbol("strict content length"),kMaxRedirections:Symbol("maxRedirections"),kMaxRequests:Symbol("maxRequestsPerClient"),kProxy:Symbol("proxy agent options"),kCounter:Symbol("socket request counter"),kInterceptors:Symbol("dispatch interceptors"),kMaxResponseSize:Symbol("max response size"),kHTTP2Session:Symbol("http2Session"),kHTTP2SessionState:Symbol("http2Session state"),kRetryHandlerDefaultRetry:Symbol("retry agent default retry"),kConstruct:Symbol("constructable"),kListeners:Symbol("listeners"),kHTTPContext:Symbol("http context"),kMaxConcurrentStreams:Symbol("max concurrent streams"),kNoProxyAgent:Symbol("no proxy agent"),kHttpProxyAgent:Symbol("http proxy agent"),kHttpsProxyAgent:Symbol("https proxy agent")}});var L=Q((J_,jp)=>{"use strict";var bp=Symbol.for("undici.error.UND_ERR"),z=class extends Error{constructor(t){super(t),this.name="UndiciError",this.code="UND_ERR"}static[Symbol.hasInstance](t){return t&&t[bp]===!0}[bp]=!0},yp=Symbol.for("undici.error.UND_ERR_CONNECT_TIMEOUT"),sA=class extends z{constructor(t){super(t),this.name="ConnectTimeoutError",this.message=t||"Connect Timeout Error",this.code="UND_ERR_CONNECT_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[yp]===!0}[yp]=!0},xp=Symbol.for("undici.error.UND_ERR_HEADERS_TIMEOUT"),rA=class extends z{constructor(t){super(t),this.name="HeadersTimeoutError",this.message=t||"Headers Timeout Error",this.code="UND_ERR_HEADERS_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[xp]===!0}[xp]=!0},vp=Symbol.for("undici.error.UND_ERR_HEADERS_OVERFLOW"),iA=class extends z{constructor(t){super(t),this.name="HeadersOverflowError",this.message=t||"Headers Overflow Error",this.code="UND_ERR_HEADERS_OVERFLOW"}static[Symbol.hasInstance](t){return t&&t[vp]===!0}[vp]=!0},kp=Symbol.for("undici.error.UND_ERR_BODY_TIMEOUT"),oA=class extends z{constructor(t){super(t),this.name="BodyTimeoutError",this.message=t||"Body Timeout Error",this.code="UND_ERR_BODY_TIMEOUT"}static[Symbol.hasInstance](t){return t&&t[kp]===!0}[kp]=!0},Dp=Symbol.for("undici.error.UND_ERR_RESPONSE_STATUS_CODE"),nA=class extends z{constructor(t,s,r,i){super(t),this.name="ResponseStatusCodeError",this.message=t||"Response Status Code Error",this.code="UND_ERR_RESPONSE_STATUS_CODE",this.body=i,this.status=s,this.
Line truncated
|
|
||||||
`)||e.includes("\r")||e.includes("\0"))===!1}function nx(e,t){let{headersList:s}=t,r=(s.get("referrer-policy",!0)??"").split(","),i="";if(r.length>0)for(let o=r.length;o!==0;o--){let n=r[o-1].trim();if(Hy.has(n)){i=n;break}}i!==""&&(e.referrerPolicy=i)}function ax(){return"allowed"}function Ax(){return"success"}function cx(){return"success"}function lx(e){let t=null;t=e.mode,e.headersList.set("sec-fetch-mode",t,!0)}function ux(e){let t=e.origin;if(!(t==="client"||t===void 0)){if(e.responseTainting==="cors"||e.mode==="websocket")e.headersList.append("origin",t,!0);else if(e.method!=="GET"&&e.method!=="HEAD"){switch(e.referrerPolicy){case"no-referrer":t=null;break;case"no-referrer-when-downgrade":case"strict-origin":case"strict-origin-when-cross-origin":e.origin&&KA(e.origin)&&!KA(ai(e))&&(t=null);break;case"same-origin":Yo(e,ai(e))||(t=null);break;default:}e.headersList.append("origin",t,!0)}}}function nr(e,t){return e}function px(e,t,s){return!e?.startTime||e.startTime<t?{domainLookupStartTime:t,domainLookupEndTime:t,connectionStartTime:t,connectionEndTime:t,secureConnectionStartTime:t,ALPNNegotiatedProtocol:e?.ALPNNegotiatedProtocol}:{domainLookupStartTime:nr(e.domainLookupStartTime,s),domainLookupEndTime:nr(e.domainLookupEndTime,s),connectionStartTime:nr(e.connectionStartTime,s),connectionEndTime:nr(e.connectionEndTime,s),secureConnectionStartTime:nr(e.secureConnectionStartTime,s),ALPNNegotiatedProtocol:e.ALPNNegotiatedProtocol}}function gx(e){return nr(zy.now(),e)}function hx(e){return{startTime:e.startTime??0,redirectStartTime:0,redirectEndTime:0,postRedirectStartTime:e.startTime??0,finalServiceWorkerStartTime:0,finalNetworkResponseStartTime:0,finalNetworkRequestStartTime:0,endTime:0,encodedBodySize:0,decodedBodySize:0,finalConnectionTimingInfo:null}}function Ah(){return{referrerPolicy:"strict-origin-when-cross-origin"}}function dx(e){return{referrerPolicy:e.referrerPolicy}}function Ex(e){let t=e.referrerPolicy;ws(t);let s=null;if(e.referrer==="client"){let a=sh();if(!a||a.origin==="null")return"no-referrer";s=new URL(a)}else e.referrer instanceof URL&&(s=e.referrer);let r=ZA(s),i=ZA(s,!0);r.toString().length>4096&&(r=i);let o=Yo(e,r),n=ni(r)&&!ni(e.url);switch(t){case"origin":return i??ZA(s,!0);case"unsafe-url":return r;case"same-origin":return o?i:"no-referrer";case"origin-when-cross-origin":return o?r:i;case"strict-origin-when-cross-origin":{let a=ai(e);return Yo(r,a)?r:ni(r)&&!ni(a)?"no-referrer":i}default:return n?"no-referrer":i}}function ZA(e,t){return ws(e instanceof URL),e=new URL(e),e.protocol==="file:"||e.protocol==="about:"||e.protocol==="blank:"?"no-referrer":(e.username="",e.password="",e.hash="",t&&(e.pathname="",e.search=""),e)}function ni(e){if(!(e instanceof URL))return!1;if(e.href==="about:blank"||e.href==="about:srcdoc"||e.protocol==="data:"||e.protocol==="file:")return!0;return t(e.origin);function t(s){if(s==null||s==="null")return!1;let r=new URL(s);return!!(r.protocol==="https:"||r.protocol==="wss:"||/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(r.hostname)||r.hostname==="localhost"||r.hostname.includes("localhost.")||r.hostname.endsWith(".localhost"))}}function mx(e,t){if(_o===void 0)return!0;let s=ch(t);if(s==="no metadata"||s.length===0)return!0;let r=Qx(s),i=Bx(s,r);for(let o of i){let n=o.algo,a=o.hash,A=_o.createHash(n).update(e).digest("base64");if(A[A.length-1]==="="&&(A[A.length-2]==="="?A=A.slice(0,-2):A=A.slice(0,-1)),Cx(A,a))return!0}return!1}var fx=/(?<algo>sha256|sha384|sha512)-((?<hash>[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i;function ch(e){let t=[],s=!0;for(let r of e.split(" ")){s=!1;let i=fx.exec(r);if(i===null||i.groups===void 0||i.groups.algo===void 0)continue;let o=i.groups.algo.toLowerCase();ih.includes(o)&&t.push(i.groups)}return s===!0?"no metadata":t}function Qx(e){let t=e[0].algo;if(t[3]==="5")return t;for(let s=1;s<e.length;++s){let r=e[s];if(r.algo[3]==="5"){t="sha512";break}else{if(t[3]==="3")continue;r.algo[3]==="3"&&(t="sha384")}}return t}function Bx(e,t){if(e.length===1)return e;let s=0;for(let r=0;r<e.length;++r)e[r].algo===t&&(e[s++]=e[r]);return e.length=s,e}function Cx(e,t){if(e.length!==t.length)return!1;for(let s=0;s<e.length;++s)if(e[s]!==t[s]){if(e[s]==="+"&&t[s]==="-"||e[s]==="/"&&t[s]==="_")continue;return!1}return!0}function Ix(e){}function Yo(e,t){return e.origin===t.origin&&e.origin==="null"||e.protocol===t.protocol&&e.hostname===t.hostname&&e.port===t.port}function wx(){let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}}function bx(e){return e.controller.state==="aborted"}function yx(e){return e.controller.state==="aborted"||e.controller.state==="terminated"}function xx(e){return Xy[e.toLowerCase()]??e}function vx(e){let t=JSON.stringify(e);if(t===void 0)throw new TypeError("Value is not JSON serializable");return ws(typeof t=="string"),t}var kx=Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));function lh(e,t,s=0,r=1){class i{#e;#t;#i;constructor(n,a){this.#e=n,
Line truncated
|
|
||||||
`);function iv(e){for(let t=0;t<e.length;++t)if((e.charCodeAt(t)&-128)!==0)return!1;return!0}function ov(e){let t=e.length;if(t<27||t>70)return!1;for(let s=0;s<t;++s){let r=e.charCodeAt(s);if(!(r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||r===39||r===45||r===95))return!1}return!0}function nv(e,t){Jo(t!=="failure"&&t.essence==="multipart/form-data");let s=t.parameters.get("boundary");if(s===void 0)return"failure";let r=Buffer.from(`--${s}`,"utf8"),i=[],o={position:0};for(;e[o.position]===13&&e[o.position+1]===10;)o.position+=2;let n=e.length;for(;e[n-1]===10&&e[n-2]===13;)n-=2;for(n!==e.length&&(e=e.subarray(0,n));;){if(e.subarray(o.position,o.position+r.length).equals(r))o.position+=r.length;else return"failure";if(o.position===e.length-2&&Po(e,sv,o)||o.position===e.length-4&&Po(e,rv,o))return i;if(e[o.position]!==13||e[o.position+1]!==10)return"failure";o.position+=2;let a=av(e,o);if(a==="failure")return"failure";let{name:A,filename:c,contentType:u,encoding:l}=a;o.position+=2;let p;{let h=e.indexOf(r.subarray(2),o.position);if(h===-1)return"failure";p=e.subarray(o.position,h-4),o.position+=p.length,l==="base64"&&(p=Buffer.from(p.toString(),"base64"))}if(e[o.position]!==13||e[o.position+1]!==10)return"failure";o.position+=2;let g;c!==null?(u??="text/plain",iv(u)||(u=""),g=new ev([p],c,{type:u})):g=zx(Buffer.from(p)),Jo(Ih(A)),Jo(typeof g=="string"&&Ih(g)||Kx(g)),i.push(Xx(A,g,c))}}function av(e,t){let s=null,r=null,i=null,o=null;for(;;){if(e[t.position]===13&&e[t.position+1]===10)return s===null?"failure":{name:s,filename:r,contentType:i,encoding:o};let n=Ar(a=>a!==10&&a!==13&&a!==58,e,t);if(n=ic(n,!0,!0,a=>a===9||a===32),!Zx.test(n.toString())||e[t.position]!==58)return"failure";switch(t.position++,Ar(a=>a===32||a===9,e,t),jx(n)){case"content-disposition":{if(s=r=null,!Po(e,tv,t)||(t.position+=17,s=yh(e,t),s===null))return"failure";if(Po(e,bh,t)){let a=t.position+bh.length;if(e[a]===42&&(t.position+=1,a+=1),e[a]!==61||e[a+1]!==34||(t.position+=12,r=yh(e,t),r===null))return"failure"}break}case"content-type":{let a=Ar(A=>A!==10&&A!==13,e,t);a=ic(a,!1,!0,A=>A===9||A===32),i=wh(a);break}case"content-transfer-encoding":{let a=Ar(A=>A!==10&&A!==13,e,t);a=ic(a,!1,!0,A=>A===9||A===32),o=wh(a);break}default:Ar(a=>a!==10&&a!==13,e,t)}if(e[t.position]!==13&&e[t.position+1]!==10)return"failure";t.position+=2}}function yh(e,t){Jo(e[t.position-1]===34);let s=Ar(r=>r!==10&&r!==13&&r!==34,e,t);return e[t.position]!==34?null:(t.position++,s=new TextDecoder().decode(s).replace(/%0A/ig,`
|
|
||||||
`).replace(/%0D/ig,"\r").replace(/%22/g,'"'),s)}function Ar(e,t,s){let r=s.position;for(;r<t.length&&e(t[r]);)++r;return t.subarray(s.position,s.position=r)}function ic(e,t,s,r){let i=0,o=e.length-1;if(t)for(;i<e.length&&r(e[i]);)i++;if(s)for(;o>0&&r(e[o]);)o--;return i===0&&o===e.length-1?e:e.subarray(i,o+1)}function Po(e,t,s){if(e.length<t.length)return!1;for(let r=0;r<t.length;r++)if(t[r]!==e[s.position+r])return!1;return!0}xh.exports={multipartFormDataParser:nv,validateBoundary:ov}});var ur=Q((g2,Mh)=>{"use strict";var li=U(),{ReadableStreamFrom:Av,isBlobLike:kh,isReadableStreamLike:cv,readableStreamClose:lv,createDeferredPromise:uv,fullyReadBody:pv,extractMimeType:gv,utf8DecodeBytes:Th}=Ue(),{FormData:Dh}=ci(),{kState:lr}=Kt(),{webidl:hv}=ge(),{Blob:dv}=require("node:buffer"),oc=require("node:assert"),{isErrored:Fh,isDisturbed:Ev}=require("node:stream"),{isArrayBuffer:mv}=require("node:util/types"),{serializeAMimeType:fv}=ve(),{multipartFormDataParser:Qv}=vh(),nc;try{let e=require("node:crypto");nc=t=>e.randomInt(0,t)}catch{nc=e=>Math.floor(Math.random(e))}var Ho=new TextEncoder;function Bv(){}var Sh=globalThis.FinalizationRegistry&&process.version.indexOf("v18")!==0,Uh;Sh&&(Uh=new FinalizationRegistry(e=>{let t=e.deref();t&&!t.locked&&!Ev(t)&&!Fh(t)&&t.cancel("Response object has been garbage collected").catch(Bv)}));function Nh(e,t=!1){let s=null;e instanceof ReadableStream?s=e:kh(e)?s=e.stream():s=new ReadableStream({async pull(A){let c=typeof i=="string"?Ho.encode(i):i;c.byteLength&&A.enqueue(c),queueMicrotask(()=>lv(A))},start(){},type:"bytes"}),oc(cv(s));let r=null,i=null,o=null,n=null;if(typeof e=="string")i=e,n="text/plain;charset=UTF-8";else if(e instanceof URLSearchParams)i=e.toString(),n="application/x-www-form-urlencoded;charset=UTF-8";else if(mv(e))i=new Uint8Array(e.slice());else if(ArrayBuffer.isView(e))i=new Uint8Array(e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength));else if(li.isFormDataLike(e)){let A=`----formdata-undici-0${`${nc(1e11)}`.padStart(11,"0")}`,c=`--${A}\r
|
|
||||||
Content-Disposition: form-data`;let u=m=>m.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22"),l=m=>m.replace(/\r?\n|\r/g,`\r
|
|
||||||
`),p=[],g=new Uint8Array([13,10]);o=0;let h=!1;for(let[m,E]of e)if(typeof E=="string"){let f=Ho.encode(c+`; name="${u(l(m))}"\r
|
|
||||||
\r
|
|
||||||
${l(E)}\r
|
|
||||||
`);p.push(f),o+=f.byteLength}else{let f=Ho.encode(`${c}; name="${u(l(m))}"`+(E.name?`; filename="${u(E.name)}"`:"")+`\r
|
|
||||||
Content-Type: ${E.type||"application/octet-stream"}\r
|
|
||||||
\r
|
|
||||||
`);p.push(f,E,g),typeof E.size=="number"?o+=f.byteLength+E.size+g.byteLength:h=!0}let d=Ho.encode(`--${A}--\r
|
|
||||||
`);p.push(d),o+=d.byteLength,h&&(o=null),i=e,r=async function*(){for(let m of p)m.stream?yield*m.stream():yield m},n=`multipart/form-data; boundary=${A}`}else if(kh(e))i=e,o=e.size,e.type&&(n=e.type);else if(typeof e[Symbol.asyncIterator]=="function"){if(t)throw new TypeError("keepalive");if(li.isDisturbed(e)||e.locked)throw new TypeError("Response body object should not be disturbed or locked");s=e instanceof ReadableStream?e:Av(e)}if((typeof i=="string"||li.isBuffer(i))&&(o=Buffer.byteLength(i)),r!=null){let A;s=new ReadableStream({async start(){A=r(e)[Symbol.asyncIterator]()},async pull(c){let{value:u,done:l}=await A.next();if(l)queueMicrotask(()=>{c.close(),c.byobRequest?.respond(0)});else if(!Fh(s)){let p=new Uint8Array(u);p.byteLength&&c.enqueue(p)}return c.desiredSize>0},async cancel(c){await A.return()},type:"bytes"})}return[{stream:s,source:i,length:o},n]}function Cv(e,t=!1){return e instanceof ReadableStream&&(oc(!li.isDisturbed(e),"The body has already been consumed."),oc(!e.locked,"The stream is locked.")),Nh(e,t)}function Iv(e,t){let[s,r]=t.stream.tee();return t.stream=s,{stream:r,length:t.length,source:t.source}}function wv(e){if(e.aborted)throw new DOMException("The operation was aborted.","AbortError")}function bv(e){return{blob(){return cr(this,s=>{let r=Rh(this);return r===null?r="":r&&(r=fv(r)),new dv([s],{type:r})},e)},arrayBuffer(){return cr(this,s=>new Uint8Array(s).buffer,e)},text(){return cr(this,Th,e)},json(){return cr(this,xv,e)},formData(){return cr(this,s=>{let r=Rh(this);if(r!==null)switch(r.essence){case"multipart/form-data":{let i=Qv(s,r);if(i==="failure")throw new TypeError("Failed to parse body as FormData.");let o=new Dh;return o[lr]=i,o}case"application/x-www-form-urlencoded":{let i=new URLSearchParams(s.toString()),o=new Dh;for(let[n,a]of i)o.append(n,a);return o}}throw new TypeError('Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".')},e)},bytes(){return cr(this,s=>new Uint8Array(s),e)}}}function yv(e){Object.assign(e.prototype,bv(e))}async function cr(e,t,s){if(hv.brandCheck(e,s),Gh(e))throw new TypeError("Body is unusable: Body has already been read");wv(e[lr]);let r=uv(),i=n=>r.reject(n),o=n=>{try{r.resolve(t(n))}catch(a){i(a)}};return e[lr].body==null?(o(Buffer.allocUnsafe(0)),r.promise):(await pv(e[lr].body,o,i),r.promise)}function Gh(e){let t=e[lr].body;return t!=null&&(t.stream.locked||li.isDisturbed(t.stream))}function xv(e){return JSON.parse(Th(e))}function Rh(e){let t=e[lr].headersList,s=gv(t);return s==="failure"?null:s}Mh.exports={extractBody:Nh,safelyExtractBody:Cv,cloneBody:Iv,mixinBody:yv,streamRegistry:Uh,hasFinalizationRegistry:Sh,bodyUnusable:Gh}});var jh=Q((h2,Wh)=>{"use strict";var k=require("node:assert"),F=U(),{channels:Lh}=Xs(),ac=JA(),{RequestContentLengthMismatchError:bs,ResponseContentLengthMismatchError:vv,RequestAbortedError:Hh,HeadersTimeoutError:kv,HeadersOverflowError:Dv,SocketError:Zo,InformationalError:pr,BodyTimeoutError:Rv,HTTPParserError:Tv,ResponseExceededMaxSizeError:Fv}=L(),{kUrl:Vh,kReset:ke,kClient:uc,kParser:X,kBlocking:gi,kRunning:Ee,kPending:Sv,kSize:_h,kWriting:$t,kQueue:st,kNoRef:ui,kKeepAliveDefaultTimeout:Uv,kHostHeader:Nv,kPendingIdx:Gv,kRunningIdx:qe,kError:We,kPipelining:jo,kSocket:gr,kKeepAliveTimeoutValue:Ko,kMaxHeadersSize:Ac,kKeepAliveMaxTimeout:Mv,kKeepAliveTimeoutThreshold:Lv,kHeadersTimeout:_v,kBodyTimeout:Yv,kStrictContentLength:pc,kMaxRequests:Yh,kCounter:Ov,kMaxResponseSize:Jv,kOnError:Pv,kResume:Xt,kHTTPContext:qh}=j(),ft=Ug(),Hv=Buffer.alloc(0),Vo=Buffer[Symbol.species],qo=F.addListener,Vv=F.removeAllListeners,cc;async function qv(){let e=process.env.JEST_WORKER_ID?VA():void 0,t;try{t=await WebAssembly.compile(Mg())}catch{t=await WebAssembly.compile(e||VA())}return await WebAssembly.instantiate(t,{env:{wasm_on_url:(s,r,i)=>0,wasm_on_status:(s,r,i)=>{k(oe.ptr===s);let o=r-Bt+Qt.byteOffset;return oe.onStatus(new Vo(Qt.buffer,o,i))||0},wasm_on_message_begin:s=>(k(oe.ptr===s),oe.onMessageBegin()||0),wasm_on_header_field:(s,r,i)=>{k(oe.ptr===s);let o=r-Bt+Qt.byteOffset;return oe.onHeaderField(new Vo(Qt.buffer,o,i))||0},wasm_on_header_value:(s,r,i)=>{k(oe.ptr===s);let o=r-Bt+Qt.byteOffset;return oe.onHeaderValue(new Vo(Qt.buffer,o,i))||0},wasm_on_headers_complete:(s,r,i,o)=>(k(oe.ptr===s),oe.onHeadersComplete(r,!!i,!!o)||0),wasm_on_body:(s,r,i)=>{k(oe.ptr===s);let o=r-Bt+Qt.byteOffset;return oe.onBody(new Vo(Qt.buffer,o,i))||0},wasm_on_message_complete:s=>(k(oe.ptr===s),oe.onMessageComplete()||0)}})}var lc=null,gc=qv();gc.catch();var oe=null,Qt=null,Wo=0,Bt=null,Wv=0,pi=1,hr=2|pi,zo=4|pi,hc=8|Wv,dc=class{constructor(t,s,{exports:r}){k(Number.isFinite(t[Ac])&&t[Ac]>0),this.llhttp=r,this.ptr=this.llhttp.llhttp_alloc(ft.TYPE.RESPONSE),this.client=t,this.socket=s,this.timeout=null,this.timeoutValue=null,this.timeoutType=null,this.statusCode=null,this.statusText="",this.upgrade=!1,this.headers=[],this.headersSize=0,this.headersMaxSize=t[Ac],this.shouldKeepAlive=!1,this.paused=!1,
Line truncated
|
|
||||||
`;if(typeof i=="string"?d+=`host: ${i}\r
|
|
||||||
`:d+=e[Nv],o?d+=`connection: upgrade\r
|
|
||||||
upgrade: ${o}\r
|
|
||||||
`:e[jo]&&!g[ke]?d+=`connection: keep-alive\r
|
|
||||||
`:d+=`connection: close\r
|
|
||||||
`,Array.isArray(c))for(let m=0;m<c.length;m+=2){let E=c[m+0],f=c[m+1];if(Array.isArray(f))for(let C=0;C<f.length;C++)d+=`${E}: ${f[C]}\r
|
|
||||||
`;else d+=`${E}: ${f}\r
|
|
||||||
`}return Lh.sendHeaders.hasSubscribers&&Lh.sendHeaders.publish({request:t,headers:d,socket:g}),!A||p===0?Jh(h,null,e,t,g,u,d,l):F.isBuffer(A)?Jh(h,A,e,t,g,u,d,l):F.isBlobLike(A)?typeof A.stream=="function"?Ph(h,A.stream(),e,t,g,u,d,l):$v(h,A,e,t,g,u,d,l):F.isStream(A)?Xv(h,A,e,t,g,u,d,l):F.isIterable(A)?Ph(h,A,e,t,g,u,d,l):k(!1),!0}function Xv(e,t,s,r,i,o,n,a){k(o!==0||s[Ee]===0,"stream body cannot be pipelined");let A=!1,c=new Xo({abort:e,socket:i,request:r,contentLength:o,client:s,expectsPayload:a,header:n}),u=function(h){if(!A)try{!c.write(h)&&this.pause&&this.pause()}catch(d){F.destroy(this,d)}},l=function(){A||t.resume&&t.resume()},p=function(){if(queueMicrotask(()=>{t.removeListener("error",g)}),!A){let h=new Hh;queueMicrotask(()=>g(h))}},g=function(h){if(!A){if(A=!0,k(i.destroyed||i[$t]&&s[Ee]<=1),i.off("drain",l).off("error",g),t.removeListener("data",u).removeListener("end",g).removeListener("close",p),!h)try{c.end()}catch(d){h=d}c.destroy(h),h&&(h.code!=="UND_ERR_INFO"||h.message!=="reset")?F.destroy(t,h):F.destroy(t)}};t.on("data",u).on("end",g).on("error",g).on("close",p),t.resume&&t.resume(),i.on("drain",l).on("error",g),t.errorEmitted??t.errored?setImmediate(()=>g(t.errored)):(t.endEmitted??t.readableEnded)&&setImmediate(()=>g(null)),(t.closeEmitted??t.closed)&&setImmediate(p)}function Jh(e,t,s,r,i,o,n,a){try{t?F.isBuffer(t)&&(k(o===t.byteLength,"buffer body must have content length"),i.cork(),i.write(`${n}content-length: ${o}\r
|
|
||||||
\r
|
|
||||||
`,"latin1"),i.write(t),i.uncork(),r.onBodySent(t),!a&&r.reset!==!1&&(i[ke]=!0)):o===0?i.write(`${n}content-length: 0\r
|
|
||||||
\r
|
|
||||||
`,"latin1"):(k(o===null,"no body must not have content length"),i.write(`${n}\r
|
|
||||||
`,"latin1")),r.onRequestSent(),s[Xt]()}catch(A){e(A)}}async function $v(e,t,s,r,i,o,n,a){k(o===t.size,"blob body must have content length");try{if(o!=null&&o!==t.size)throw new bs;let A=Buffer.from(await t.arrayBuffer());i.cork(),i.write(`${n}content-length: ${o}\r
|
|
||||||
\r
|
|
||||||
`,"latin1"),i.write(A),i.uncork(),r.onBodySent(A),r.onRequestSent(),!a&&r.reset!==!1&&(i[ke]=!0),s[Xt]()}catch(A){e(A)}}async function Ph(e,t,s,r,i,o,n,a){k(o!==0||s[Ee]===0,"iterator body cannot be pipelined");let A=null;function c(){if(A){let p=A;A=null,p()}}let u=()=>new Promise((p,g)=>{k(A===null),i[We]?g(i[We]):A=p});i.on("close",c).on("drain",c);let l=new Xo({abort:e,socket:i,request:r,contentLength:o,client:s,expectsPayload:a,header:n});try{for await(let p of t){if(i[We])throw i[We];l.write(p)||await u()}l.end()}catch(p){l.destroy(p)}finally{i.off("close",c).off("drain",c)}}var Xo=class{constructor({abort:t,socket:s,request:r,contentLength:i,client:o,expectsPayload:n,header:a}){this.socket=s,this.request=r,this.contentLength=i,this.client=o,this.bytesWritten=0,this.expectsPayload=n,this.header=a,this.abort=t,s[$t]=!0}write(t){let{socket:s,request:r,contentLength:i,client:o,bytesWritten:n,expectsPayload:a,header:A}=this;if(s[We])throw s[We];if(s.destroyed)return!1;let c=Buffer.byteLength(t);if(!c)return!0;if(i!==null&&n+c>i){if(o[pc])throw new bs;process.emitWarning(new bs)}s.cork(),n===0&&(!a&&r.reset!==!1&&(s[ke]=!0),i===null?s.write(`${A}transfer-encoding: chunked\r
|
|
||||||
`,"latin1"):s.write(`${A}content-length: ${i}\r
|
|
||||||
\r
|
|
||||||
`,"latin1")),i===null&&s.write(`\r
|
|
||||||
${c.toString(16)}\r
|
|
||||||
`,"latin1"),this.bytesWritten+=c;let u=s.write(t);return s.uncork(),r.onBodySent(t),u||s[X].timeout&&s[X].timeoutType===hr&&s[X].timeout.refresh&&s[X].timeout.refresh(),u}end(){let{socket:t,contentLength:s,client:r,bytesWritten:i,expectsPayload:o,header:n,request:a}=this;if(a.onRequestSent(),t[$t]=!1,t[We])throw t[We];if(!t.destroyed){if(i===0?o?t.write(`${n}content-length: 0\r
|
|
||||||
\r
|
|
||||||
`,"latin1"):t.write(`${n}\r
|
|
||||||
`,"latin1"):s===null&&t.write(`\r
|
|
||||||
0\r
|
|
||||||
\r
|
|
||||||
`,"latin1"),s!==null&&i!==s){if(r[pc])throw new bs;process.emitWarning(new bs)}t[X].timeout&&t[X].timeoutType===hr&&t[X].timeout.refresh&&t[X].timeout.refresh(),r[Xt]()}}destroy(t){let{socket:s,client:r,abort:i}=this;s[$t]=!1,t&&(k(r[Ee]<=1,"pipeline should only contain this request"),i(t))}};Wh.exports=jv});var sd=Q((d2,td)=>{"use strict";var je=require("node:assert"),{pipeline:ek}=require("node:stream"),N=U(),{RequestContentLengthMismatchError:Ec,RequestAbortedError:zh,SocketError:hi,InformationalError:mc}=L(),{kUrl:$o,kReset:tn,kClient:dr,kRunning:sn,kPending:tk,kQueue:es,kPendingIdx:fc,kRunningIdx:rt,kError:ot,kSocket:ae,kStrictContentLength:sk,kOnError:Qc,kMaxConcurrentStreams:ed,kHTTP2Session:it,kResume:ts,kSize:rk,kHTTPContext:ik}=j(),Gt=Symbol("open streams"),Zh,Kh=!1,en;try{en=require("node:http2")}catch{en={constants:{}}}var{constants:{HTTP2_HEADER_AUTHORITY:ok,HTTP2_HEADER_METHOD:nk,HTTP2_HEADER_PATH:ak,HTTP2_HEADER_SCHEME:Ak,HTTP2_HEADER_CONTENT_LENGTH:ck,HTTP2_HEADER_EXPECT:lk,HTTP2_HEADER_STATUS:uk}}=en;function pk(e){let t=[];for(let[s,r]of Object.entries(e))if(Array.isArray(r))for(let i of r)t.push(Buffer.from(s),Buffer.from(i));else t.push(Buffer.from(s),Buffer.from(r));return t}async function gk(e,t){e[ae]=t,Kh||(Kh=!0,process.emitWarning("H2 support is experimental, expect them to change at any time.",{code:"UNDICI-H2"}));let s=en.connect(e[$o],{createConnection:()=>t,peerMaxConcurrentStreams:e[ed]});s[Gt]=0,s[dr]=e,s[ae]=t,N.addListener(s,"error",dk),N.addListener(s,"frameError",Ek),N.addListener(s,"end",mk),N.addListener(s,"goaway",fk),N.addListener(s,"close",function(){let{[dr]:i}=this,{[ae]:o}=i,n=this[ae][ot]||this[ot]||new hi("closed",N.getSocketInfo(o));if(i[it]=null,i.destroyed){je(i[tk]===0);let a=i[es].splice(i[rt]);for(let A=0;A<a.length;A++){let c=a[A];N.errorRequest(i,c,n)}}}),s.unref(),e[it]=s,t[it]=s,N.addListener(t,"error",function(i){je(i.code!=="ERR_TLS_CERT_ALTNAME_INVALID"),this[ot]=i,this[dr][Qc](i)}),N.addListener(t,"end",function(){N.destroy(this,new hi("other side closed",N.getSocketInfo(this)))}),N.addListener(t,"close",function(){let i=this[ot]||new hi("closed",N.getSocketInfo(this));e[ae]=null,this[it]!=null&&this[it].destroy(i),e[fc]=e[rt],je(e[sn]===0),e.emit("disconnect",e[$o],[e],i),e[ts]()});let r=!1;return t.on("close",()=>{r=!0}),{version:"h2",defaultPipelining:1/0,write(...i){return Bk(e,...i)},resume(){hk(e)},destroy(i,o){r?queueMicrotask(o):t.destroy(i).on("close",o)},get destroyed(){return t.destroyed},busy(){return!1}}}function hk(e){let t=e[ae];t?.destroyed===!1&&(e[rk]===0&&e[ed]===0?(t.unref(),e[it].unref()):(t.ref(),e[it].ref()))}function dk(e){je(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID"),this[ae][ot]=e,this[dr][Qc](e)}function Ek(e,t,s){if(s===0){let r=new mc(`HTTP/2: "frameError" received - type ${e}, code ${t}`);this[ae][ot]=r,this[dr][Qc](r)}}function mk(){let e=new hi("other side closed",N.getSocketInfo(this[ae]));this.destroy(e),N.destroy(this[ae],e)}function fk(e){let t=this[ot]||new hi(`HTTP/2: "GOAWAY" frame received with code ${e}`,N.getSocketInfo(this)),s=this[dr];if(s[ae]=null,s[ik]=null,this[it]!=null&&(this[it].destroy(t),this[it]=null),N.destroy(this[ae],t),s[rt]<s[es].length){let r=s[es][s[rt]];s[es][s[rt]++]=null,N.errorRequest(s,r,t),s[fc]=s[rt]}je(s[sn]===0),s.emit("disconnect",s[$o],[s],t),s[ts]()}function Qk(e){return e!=="GET"&&e!=="HEAD"&&e!=="OPTIONS"&&e!=="TRACE"&&e!=="CONNECT"}function Bk(e,t){let s=e[it],{method:r,path:i,host:o,upgrade:n,expectContinue:a,signal:A,headers:c}=t,{body:u}=t;if(n)return N.errorRequest(e,t,new Error("Upgrade not supported for H2")),!1;let l={};for(let I=0;I<c.length;I+=2){let x=c[I+0],Y=c[I+1];if(Array.isArray(Y))for(let O=0;O<Y.length;O++)l[x]?l[x]+=`,${Y[O]}`:l[x]=Y[O];else l[x]=Y}let p,{hostname:g,port:h}=e[$o];l[ok]=o||`${g}${h?`:${h}`:""}`,l[nk]=r;let d=I=>{t.aborted||t.completed||(I=I||new zh,N.errorRequest(e,t,I),p!=null&&N.destroy(p,I),N.destroy(u,I),e[es][e[rt]++]=null,e[ts]())};try{t.onConnect(d)}catch(I){N.errorRequest(e,t,I)}if(t.aborted)return!1;if(r==="CONNECT")return s.ref(),p=s.request(l,{endStream:!1,signal:A}),p.id&&!p.pending?(t.onUpgrade(null,null,p),++s[Gt],e[es][e[rt]++]=null):p.once("ready",()=>{t.onUpgrade(null,null,p),++s[Gt],e[es][e[rt]++]=null}),p.once("close",()=>{s[Gt]-=1,s[Gt]===0&&s.unref()}),!0;l[ak]=i,l[Ak]="https";let m=r==="PUT"||r==="POST"||r==="PATCH";u&&typeof u.read=="function"&&u.read(0);let E=N.bodyLength(u);if(N.isFormDataLike(u)){Zh??=ur().extractBody;let[I,x]=Zh(u);l["content-type"]=x,u=I.stream,E=I.length}if(E==null&&(E=t.contentLength),(E===0||!m)&&(E=null),Qk(r)&&E>0&&t.contentLength!=null&&t.contentLength!==E){if(e[sk])return N.errorRequest(e,t,new Ec),!1;process.emitWarning(new Ec)}E!=null&&(je(u,"no body must not have content length"),l[ck]=`${E}`),s.ref();let f=r==="GET"||r==="HEAD"||u===null;return a?(l[lk]="100-continue",p=s.request(l,{endStream:f,signal:A}),p.once("continue",C)):(p=s.request(l,{endStream:f,signal:A}),C()),++s[Gt],p.once("r
Line truncated
|
|
||||||
`,this[qk]=A??3e5,this[Vk]=i??3e5,this[Wk]=f??!0,this[jk]=I,this[wc]=Y,this[rs]=null,this[$k]=pe>-1?pe:-1,this[t0]=Wt??100,this[ee]=null,this[nt]=[],this[Lt]=0,this[at]=0,this[fi]=jt=>yc(this,jt),this[e0]=jt=>hd(this,jt)}get pipelining(){return this[an]}set pipelining(t){this[an]=t,this[fi](!0)}get[Ci](){return this[nt].length-this[at]}get[Bi](){return this[at]-this[Lt]}get[Qi](){return this[nt].length-this[Lt]}get[Lk](){return!!this[ee]&&!this[mr]&&!this[ee].destroyed}get[Ic](){return!!(this[ee]?.busy(null)||this[Qi]>=(gd(this)||1)||this[Ci]>0)}[Mk](t){dd(this),this.once("connect",t)}[Xk](t,s){let r=t.origin||this[It].origin,i=new Tk(r,t,s);return this[nt].push(i),this[xs]||(ys.bodyLength(i.body)==null&&ys.isIterable(i.body)?(this[xs]=1,queueMicrotask(()=>yc(this))):this[fi](!0)),this[xs]&&this[is]!==2&&this[Ic]&&(this[is]=2),this[is]<2}async[Zk](){return new Promise(t=>{this[Qi]?this[rs]=t:t(null)})}async[Kk](t){return new Promise(s=>{let r=this[nt].splice(this[at]);for(let o=0;o<r.length;o++){let n=r[o];ys.errorRequest(this,n,t)}let i=()=>{this[rs]&&(this[rs](),this[rs]=null),s(null)};this[ee]?(this[ee].destroy(t,i),this[ee]=null):queueMicrotask(i),this[fi]()})}},i0=nn();function hd(e,t){if(e[Bi]===0&&t.code!=="UND_ERR_INFO"&&t.code!=="UND_ERR_SOCKET"){Mt(e[at]===e[Lt]);let s=e[nt].splice(e[Lt]);for(let r=0;r<s.length;r++){let i=s[r];ys.errorRequest(e,i,t)}Mt(e[Qi]===0)}}async function dd(e){Mt(!e[mr]),Mt(!e[ee]);let{host:t,hostname:s,protocol:r,port:i}=e[It];if(s[0]==="["){let o=s.indexOf("]");Mt(o!==-1);let n=s.substring(1,o);Mt(pd.isIP(n)),s=n}e[mr]=!0,Er.beforeConnect.hasSubscribers&&Er.beforeConnect.publish({connectParams:{host:t,hostname:s,protocol:r,port:i,version:e[ee]?.version,servername:e[ss],localAddress:e[mi]},connector:e[Ei]});try{let o=await new Promise((n,a)=>{e[Ei]({host:t,hostname:s,protocol:r,port:i,servername:e[ss],localAddress:e[mi]},(A,c)=>{A?a(A):n(c)})});if(e.destroyed){ys.destroy(o.on("error",ld),new Uk);return}Mt(o);try{e[ee]=o.alpnProtocol==="h2"?await r0(e,o):await s0(e,o)}catch(n){throw o.destroy().on("error",ld),n}e[mr]=!1,o[zk]=0,o[wc]=e[wc],o[Gk]=e,o[Yk]=null,Er.connected.hasSubscribers&&Er.connected.publish({connectParams:{host:t,hostname:s,protocol:r,port:i,version:e[ee]?.version,servername:e[ss],localAddress:e[mi]},connector:e[Ei],socket:o}),e.emit("connect",e[It],[e])}catch(o){if(e.destroyed)return;if(e[mr]=!1,Er.connectError.hasSubscribers&&Er.connectError.publish({connectParams:{host:t,hostname:s,protocol:r,port:i,version:e[ee]?.version,servername:e[ss],localAddress:e[mi]},connector:e[Ei],error:o}),o.code==="ERR_TLS_CERT_ALTNAME_INVALID")for(Mt(e[Bi]===0);e[Ci]>0&&e[nt][e[at]].servername===e[ss];){let n=e[nt][e[at]++];ys.errorRequest(e,n,o)}else hd(e,o);e.emit("connectionError",e[It],[e],o)}e[fi]()}function ud(e){e[is]=0,e.emit("drain",e[It],[e])}function yc(e,t){e[xs]!==2&&(e[xs]=2,o0(e,t),e[xs]=0,e[Lt]>256&&(e[nt].splice(0,e[Lt]),e[at]-=e[Lt],e[Lt]=0))}function o0(e,t){for(;;){if(e.destroyed){Mt(e[Ci]===0);return}if(e[rs]&&!e[Qi]){e[rs](),e[rs]=null;return}if(e[ee]&&e[ee].resume(),e[Ic])e[is]=2;else if(e[is]===2){t?(e[is]=1,queueMicrotask(()=>ud(e))):ud(e);continue}if(e[Ci]===0||e[Bi]>=(gd(e)||1))return;let s=e[nt][e[at]];if(e[It].protocol==="https:"&&e[ss]!==s.servername){if(e[Bi]>0)return;e[ss]=s.servername,e[ee]?.destroy(new Sk("servername changed"),()=>{e[ee]=null,yc(e)})}if(e[mr])return;if(!e[ee]){dd(e);return}if(e[ee].destroyed||e[ee].busy(s))return;!s.aborted&&e[ee].write(s)?e[at]++:e[nt].splice(e[at],1)}}Ed.exports=bc});var xc=Q((B2,md)=>{"use strict";var An=class{constructor(){this.bottom=0,this.top=0,this.list=new Array(2048),this.next=null}isEmpty(){return this.top===this.bottom}isFull(){return(this.top+1&2047)===this.bottom}push(t){this.list[this.top]=t,this.top=this.top+1&2047}shift(){let t=this.list[this.bottom];return t===void 0?null:(this.list[this.bottom]=void 0,this.bottom=this.bottom+1&2047,t)}};md.exports=class{constructor(){this.head=this.tail=new An}isEmpty(){return this.head.isEmpty()}push(t){this.head.isFull()&&(this.head=this.head.next=new An),this.head.push(t)}shift(){let t=this.tail,s=t.shift();return t.isEmpty()&&t.next!==null&&(this.tail=t.next),s}}});var Qd=Q((C2,fd)=>{var{kFree:n0,kConnected:a0,kPending:A0,kQueued:c0,kRunning:l0,kSize:u0}=j(),vs=Symbol("pool"),vc=class{constructor(t){this[vs]=t}get connected(){return this[vs][a0]}get free(){return this[vs][n0]}get pending(){return this[vs][A0]}get queued(){return this[vs][c0]}get running(){return this[vs][l0]}get size(){return this[vs][u0]}};fd.exports=vc});var Sc=Q((I2,Dd)=>{"use strict";var p0=sr(),g0=xc(),{kConnected:kc,kSize:Bd,kRunning:Cd,kPending:Id,kQueued:Ii,kBusy:h0,kFree:d0,kUrl:E0,kClose:m0,kDestroy:f0,kDispatch:Q0}=j(),B0=Qd(),De=Symbol("clients"),Ce=Symbol("needDrain"),wi=Symbol("queue"),Dc=Symbol("closed resolve"),Rc=Symbol("onDrain"),wd=Symbol("onConnect"),bd=Symbol("onDisconnect"),yd=Symbol("onConnectionError"),Tc=Symbol("get dispatcher"),vd=Symbol("add client"),kd=Sym
Line truncated
|
|
||||||
${r.count} ${r.noun} ${r.is} pending:
|
|
||||||
|
|
||||||
${t.format(s)}
|
|
||||||
`.trim())}};Nm.exports=Sl});var xn=Q((Z2,Ym)=>{"use strict";var Mm=Symbol.for("undici.globalDispatcher.1"),{InvalidArgumentError:qR}=L(),WR=Br();_m()===void 0&&Lm(new WR);function Lm(e){if(!e||typeof e.dispatch!="function")throw new qR("Argument agent must implement Agent");Object.defineProperty(globalThis,Mm,{value:e,writable:!0,enumerable:!1,configurable:!1})}function _m(){return globalThis[Mm]}Ym.exports={setGlobalDispatcher:Lm,getGlobalDispatcher:_m}});var vn=Q((X2,Om)=>{"use strict";Om.exports=class{#e;constructor(t){if(typeof t!="object"||t===null)throw new TypeError("handler must be an object");this.#e=t}onConnect(...t){return this.#e.onConnect?.(...t)}onError(...t){return this.#e.onError?.(...t)}onUpgrade(...t){return this.#e.onUpgrade?.(...t)}onResponseStarted(...t){return this.#e.onResponseStarted?.(...t)}onHeaders(...t){return this.#e.onHeaders?.(...t)}onData(...t){return this.#e.onData?.(...t)}onComplete(...t){return this.#e.onComplete?.(...t)}onBodySent(...t){return this.#e.onBodySent?.(...t)}}});var Pm=Q(($2,Jm)=>{"use strict";var jR=on();Jm.exports=e=>{let t=e?.maxRedirections;return s=>function(i,o){let{maxRedirections:n=t,...a}=i;if(!n)return s(i,o);let A=new jR(s,n,i,o);return s(a,A)}}});var Vm=Q((eY,Hm)=>{"use strict";var zR=En();Hm.exports=e=>t=>function(r,i){return t(r,new zR({...r,retryOptions:{...e,...r.retryOptions}},{handler:i,dispatch:t}))}});var Wm=Q((tY,qm)=>{"use strict";var ZR=U(),{InvalidArgumentError:KR,RequestAbortedError:XR}=L(),$R=vn(),Ul=class extends $R{#e=1024*1024;#t=null;#i=!1;#s=!1;#r=0;#A=null;#a=null;constructor({maxSize:t},s){if(super(s),t!=null&&(!Number.isFinite(t)||t<1))throw new KR("maxSize must be a number greater than 0");this.#e=t??this.#e,this.#a=s}onConnect(t){this.#t=t,this.#a.onConnect(this.#c.bind(this))}#c(t){this.#s=!0,this.#A=t}onHeaders(t,s,r,i){let n=ZR.parseHeaders(s)["content-length"];if(n!=null&&n>this.#e)throw new XR(`Response size (${n}) larger than maxSize (${this.#e})`);return this.#s?!0:this.#a.onHeaders(t,s,r,i)}onError(t){this.#i||(t=this.#A??t,this.#a.onError(t))}onData(t){return this.#r=this.#r+t.length,this.#r>=this.#e&&(this.#i=!0,this.#s?this.#a.onError(this.#A):this.#a.onComplete([])),!0}onComplete(t){if(!this.#i){if(this.#s){this.#a.onError(this.reason);return}this.#a.onComplete(t)}}};function eT({maxSize:e}={maxSize:1024*1024}){return t=>function(r,i){let{dumpMaxSize:o=e}=r,n=new Ul({maxSize:o},i);return t(r,n)}}qm.exports=eT});var Zm=Q((sY,zm)=>{"use strict";var{isIP:tT}=require("node:net"),{lookup:sT}=require("node:dns"),rT=vn(),{InvalidArgumentError:Rr,InformationalError:iT}=L(),jm=Math.pow(2,31)-1,Nl=class{#e=0;#t=0;#i=new Map;dualStack=!0;affinity=null;lookup=null;pick=null;constructor(t){this.#e=t.maxTTL,this.#t=t.maxItems,this.dualStack=t.dualStack,this.affinity=t.affinity,this.lookup=t.lookup??this.#s,this.pick=t.pick??this.#r}get full(){return this.#i.size===this.#t}runLookup(t,s,r){let i=this.#i.get(t.hostname);if(i==null&&this.full){r(null,t.origin);return}let o={affinity:this.affinity,dualStack:this.dualStack,lookup:this.lookup,pick:this.pick,...s.dns,maxTTL:this.#e,maxItems:this.#t};if(i==null)this.lookup(t,o,(n,a)=>{if(n||a==null||a.length===0){r(n??new iT("No DNS entries found"));return}this.setRecords(t,a);let A=this.#i.get(t.hostname),c=this.pick(t,A,o.affinity),u;typeof c.port=="number"?u=`:${c.port}`:t.port!==""?u=`:${t.port}`:u="",r(null,`${t.protocol}//${c.family===6?`[${c.address}]`:c.address}${u}`)});else{let n=this.pick(t,i,o.affinity);if(n==null){this.#i.delete(t.hostname),this.runLookup(t,s,r);return}let a;typeof n.port=="number"?a=`:${n.port}`:t.port!==""?a=`:${t.port}`:a="",r(null,`${t.protocol}//${n.family===6?`[${n.address}]`:n.address}${a}`)}}#s(t,s,r){sT(t.hostname,{all:!0,family:this.dualStack===!1?this.affinity:0,order:"ipv4first"},(i,o)=>{if(i)return r(i);let n=new Map;for(let a of o)n.set(`${a.address}:${a.family}`,a);r(null,n.values())})}#r(t,s,r){let i=null,{records:o,offset:n}=s,a;if(this.dualStack?(r==null&&(n==null||n===jm?(s.offset=0,r=4):(s.offset++,r=(s.offset&1)===1?6:4)),o[r]!=null&&o[r].ips.length>0?a=o[r]:a=o[r===4?6:4]):a=o[r],a==null||a.ips.length===0)return i;a.offset==null||a.offset===jm?a.offset=0:a.offset++;let A=a.offset%a.ips.length;return i=a.ips[A]??null,i==null?i:Date.now()-i.timestamp>i.ttl?(a.ips.splice(A,1),this.pick(t,s,r)):i}setRecords(t,s){let r=Date.now(),i={records:{4:null,6:null}};for(let o of s){o.timestamp=r,typeof o.ttl=="number"?o.ttl=Math.min(o.ttl,this.#e):o.ttl=this.#e;let n=i.records[o.family]??{ips:[]};n.ips.push(o),i.records[o.family]=n}this.#i.set(t.hostname,i)}getHandler(t,s){return new Gl(this,t,s)}},Gl=class extends rT{#e=null;#t=null;#i=null;#s=null;#r=null;constructor(t,{origin:s,handler:r,dispatch:i},o){super(r),this.#r=s,this.#s=r,this.#t={...o},this.#e=t,this.#i=i}onError(t){switch(t.code){case"ETIMEDOUT":case"ECONNREFUSED":{if(this.#e.dualStack){this.#e.runLookup(this.#r,this.#t,(s,r)=>{if(s)return this.#s.onError(s);let i={...this.#t,origin:
Line truncated
|
|
||||||
${o}`;break;case"retry":RB(o)&&(s[i]=o);break;case"id":TB(o)&&(s[i]=o);break;case"event":o.length>0&&(s[i]=o);break}}processEvent(t){t.retry&&RB(t.retry)&&(this.state.reconnectionTime=parseInt(t.retry,10)),t.id&&TB(t.id)&&(this.state.lastEventId=t.id),t.data!==void 0&&this.push({type:t.event||"message",options:{data:t.data,lastEventId:this.state.lastEventId,origin:this.state.origin}})}clearEvent(){this.event={data:void 0,event:void 0,id:void 0,retry:void 0}}};FB.exports={EventSourceStream:Cu}});var OB=Q((SY,YB)=>{"use strict";var{pipeline:hN}=require("node:stream"),{fetching:dN}=Gi(),{makeRequest:EN}=Sr(),{webidl:Pt}=ge(),{EventSourceStream:mN}=SB(),{parseMIMEType:fN}=ve(),{createFastMessageEvent:QN}=_r(),{isNetworkError:UB}=Ui(),{delay:BN}=Qu(),{kEnumerableProperty:Js}=U(),{environmentSettingsObject:NB}=Ue(),GB=!1,MB=3e3,zi=0,LB=1,Zi=2,CN="anonymous",IN="use-credentials",Hr=class e extends EventTarget{#e={open:null,error:null,message:null};#t=null;#i=!1;#s=zi;#r=null;#A=null;#a;#c;constructor(t,s={}){super(),Pt.util.markAsUncloneable(this);let r="EventSource constructor";Pt.argumentLengthCheck(arguments,1,r),GB||(GB=!0,process.emitWarning("EventSource is experimental, expect them to change at any time.",{code:"UNDICI-ES"})),t=Pt.converters.USVString(t,r,"url"),s=Pt.converters.EventSourceInitDict(s,r,"eventSourceInitDict"),this.#a=s.dispatcher,this.#c={lastEventId:"",reconnectionTime:MB};let i=NB,o;try{o=new URL(t,i.settingsObject.baseUrl),this.#c.origin=o.origin}catch(A){throw new DOMException(A,"SyntaxError")}this.#t=o.href;let n=CN;s.withCredentials&&(n=IN,this.#i=!0);let a={redirect:"follow",keepalive:!0,mode:"cors",credentials:n==="anonymous"?"same-origin":"omit",referrer:"no-referrer"};a.client=NB.settingsObject,a.headersList=[["accept",{name:"accept",value:"text/event-stream"}]],a.cache="no-store",a.initiator="other",a.urlList=[new URL(this.#t)],this.#r=EN(a),this.#l()}get readyState(){return this.#s}get url(){return this.#t}get withCredentials(){return this.#i}#l(){if(this.#s===Zi)return;this.#s=zi;let t={request:this.#r,dispatcher:this.#a},s=r=>{UB(r)&&(this.dispatchEvent(new Event("error")),this.close()),this.#g()};t.processResponseEndOfBody=s,t.processResponse=r=>{if(UB(r))if(r.aborted){this.close(),this.dispatchEvent(new Event("error"));return}else{this.#g();return}let i=r.headersList.get("content-type",!0),o=i!==null?fN(i):"failure",n=o!=="failure"&&o.essence==="text/event-stream";if(r.status!==200||n===!1){this.close(),this.dispatchEvent(new Event("error"));return}this.#s=LB,this.dispatchEvent(new Event("open")),this.#c.origin=r.urlList[r.urlList.length-1].origin;let a=new mN({eventSourceSettings:this.#c,push:A=>{this.dispatchEvent(QN(A.type,A.options))}});hN(r.body.stream,a,A=>{A?.aborted===!1&&(this.close(),this.dispatchEvent(new Event("error")))})},this.#A=dN(t)}async#g(){this.#s!==Zi&&(this.#s=zi,this.dispatchEvent(new Event("error")),await BN(this.#c.reconnectionTime),this.#s===zi&&(this.#c.lastEventId.length&&this.#r.headersList.set("last-event-id",this.#c.lastEventId,!0),this.#l()))}close(){Pt.brandCheck(this,e),this.#s!==Zi&&(this.#s=Zi,this.#A.abort(),this.#r=null)}get onopen(){return this.#e.open}set onopen(t){this.#e.open&&this.removeEventListener("open",this.#e.open),typeof t=="function"?(this.#e.open=t,this.addEventListener("open",t)):this.#e.open=null}get onmessage(){return this.#e.message}set onmessage(t){this.#e.message&&this.removeEventListener("message",this.#e.message),typeof t=="function"?(this.#e.message=t,this.addEventListener("message",t)):this.#e.message=null}get onerror(){return this.#e.error}set onerror(t){this.#e.error&&this.removeEventListener("error",this.#e.error),typeof t=="function"?(this.#e.error=t,this.addEventListener("error",t)):this.#e.error=null}},_B={CONNECTING:{__proto__:null,configurable:!1,enumerable:!0,value:zi,writable:!1},OPEN:{__proto__:null,configurable:!1,enumerable:!0,value:LB,writable:!1},CLOSED:{__proto__:null,configurable:!1,enumerable:!0,value:Zi,writable:!1}};Object.defineProperties(Hr,_B);Object.defineProperties(Hr.prototype,_B);Object.defineProperties(Hr.prototype,{close:Js,onerror:Js,onmessage:Js,onopen:Js,readyState:Js,url:Js,withCredentials:Js});Pt.converters.EventSourceInitDict=Pt.dictionaryConverter([{key:"withCredentials",converter:Pt.converters.boolean,defaultValue:()=>!1},{key:"dispatcher",converter:Pt.converters.any}]);YB.exports={EventSource:Hr,defaultReconnectionTime:MB}});var da=Q((UY,R)=>{"use strict";var wN=fr(),JB=ei(),bN=Qr(),yN=Ld(),xN=Br(),vN=qc(),kN=AE(),DN=hE(),PB=L(),ha=U(),{InvalidArgumentError:ga}=PB,Vr=em(),RN=si(),TN=vl(),FN=Gm(),SN=Rl(),UN=hl(),NN=En(),{getGlobalDispatcher:HB,setGlobalDispatcher:GN}=xn(),MN=vn(),LN=on(),_N=nn();Object.assign(JB.prototype,Vr);R.exports.Dispatcher=JB;R.exports.Client=wN;R.exports.Pool=bN;R.exports.BalancedPool=yN;R.exports.Agent=xN;R.exports.ProxyAgent=vN;R.exports.EnvHttpProxyAgent=kN;R.exports.RetryAgent=DN;R.exports.RetryHandler=NN;R.exports.DecoratorHandler=MN;R.exports.Redire
Line truncated
|
|
||||||
`+e.errors.map(t=>` - ${t.message}`).join(`
|
|
||||||
`)}var dM=class extends Error{constructor(e,t,s){super(hM(s)),this.request=e,this.headers=t,this.response=s,this.errors=s.errors,this.data=s.data,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}name="GraphqlResponseError";errors;data},EM=["method","baseUrl","url","headers","request","query","mediaType","operationName"],mM=["query","method","url"],NC=/\/api\/v3\/?$/;function fM(e,t,s){if(s){if(typeof t=="string"&&"query"in s)return Promise.reject(new Error('[@octokit/graphql] "query" cannot be used as variable name'));for(let n in s)if(mM.includes(n))return Promise.reject(new Error(`[@octokit/graphql] "${n}" cannot be used as variable name`))}let r=typeof t=="string"?Object.assign({query:t},s):t,i=Object.keys(r).reduce((n,a)=>EM.includes(a)?(n[a]=r[a],n):(n.variables||(n.variables={}),n.variables[a]=r[a],n),{}),o=r.baseUrl||e.endpoint.DEFAULTS.baseUrl;return NC.test(o)&&(i.url=o.replace(NC,"/api/graphql")),e(i).then(n=>{if(n.data.errors){let a={};for(let A of Object.keys(n.headers))a[A]=n.headers[A];throw new dM(i,a,n.data)}return n.data.data})}function Nu(e,t){let s=e.defaults(t);return Object.assign((i,o)=>fM(s,i,o),{defaults:Nu.bind(null,s),endpoint:s.endpoint})}var WO=Nu(ro,{headers:{"user-agent":`octokit-graphql.js/${gM} ${ds()}`},method:"POST",url:"/graphql"});function GC(e){return Nu(e,{method:"POST",url:"/graphql"})}var Gu="(?:[a-zA-Z0-9_-]+)",MC="\\.",LC=new RegExp(`^${Gu}${MC}${Gu}${MC}${Gu}$`),QM=LC.test.bind(LC);async function BM(e){let t=QM(e),s=e.startsWith("v1.")||e.startsWith("ghs_"),r=e.startsWith("ghu_");return{type:"token",token:e,tokenType:t?"app":s?"installation":r?"user-to-server":"oauth"}}function CM(e){return e.split(/\./).length===3?`bearer ${e}`:`token ${e}`}async function IM(e,t,s,r){let i=t.endpoint.merge(s,r);return i.headers.authorization=CM(e),t(i)}var _C=function(t){if(!t)throw new Error("[@octokit/auth-token] No token passed to createTokenAuth");if(typeof t!="string")throw new Error("[@octokit/auth-token] Token passed to createTokenAuth is not a string");return t=t.replace(/^(token|bearer) +/i,""),Object.assign(BM.bind(null,t),{hook:IM.bind(null,t)})};var Mu="7.0.6";var YC=()=>{},wM=console.warn.bind(console),bM=console.error.bind(console);function yM(e={}){return typeof e.debug!="function"&&(e.debug=YC),typeof e.info!="function"&&(e.info=YC),typeof e.warn!="function"&&(e.warn=wM),typeof e.error!="function"&&(e.error=bM),e}var OC=`octokit-core.js/${Mu} ${ds()}`,Da=class{static VERSION=Mu;static defaults(t){return class extends this{constructor(...r){let i=r[0]||{};if(typeof t=="function"){super(t(i));return}super(Object.assign({},t,i,i.userAgent&&t.userAgent?{userAgent:`${i.userAgent} ${t.userAgent}`}:null))}}}static plugins=[];static plugin(...t){let s=this.plugins;return class extends this{static plugins=s.concat(t.filter(i=>!s.includes(i)))}}constructor(t={}){let s=new hC.Collection,r={baseUrl:ro.endpoint.DEFAULTS.baseUrl,headers:{},request:Object.assign({},t.request,{hook:s.bind(null,"request")}),mediaType:{previews:[],format:""}};if(r.headers["user-agent"]=t.userAgent?`${t.userAgent} ${OC}`:OC,t.baseUrl&&(r.baseUrl=t.baseUrl),t.previews&&(r.mediaType.previews=t.previews),t.timeZone&&(r.headers["time-zone"]=t.timeZone),this.request=ro.defaults(r),this.graphql=GC(this.request).defaults(r),this.log=yM(t.log),this.hook=s,t.authStrategy){let{authStrategy:o,...n}=t,a=o(Object.assign({request:this.request,log:this.log,octokit:this,octokitOptions:n},t.auth));s.wrap("request",a.hook),this.auth=a}else if(!t.auth)this.auth=async()=>({type:"unauthenticated"});else{let o=_C(t.auth);s.wrap("request",o.hook),this.auth=o}let i=this.constructor;for(let o=0;o<i.plugins.length;++o)Object.assign(this,i.plugins[o](this,t))}request;graphql;log;hook;auth};var Lu="17.0.0";var xM={actions:{addCustomLabelsToSelfHostedRunnerForOrg:["POST /orgs/{org}/actions/runners/{runner_id}/labels"],addCustomLabelsToSelfHostedRunnerForRepo:["POST /repos/{owner}/{repo}/actions/runners/{runner_id}/labels"],addRepoAccessToSelfHostedRunnerGroupInOrg:["PUT /orgs/{org}/actions/runner-groups/{runner_group_id}/repositories/{repository_id}"],addSelectedRepoToOrgSecret:["PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}"],addSelectedRepoToOrgVariable:["PUT /orgs/{org}/actions/variables/{name}/repositories/{repository_id}"],approveWorkflowRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/approve"],cancelWorkflowRun:["POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel"],createEnvironmentVariable:["POST /repos/{owner}/{repo}/environments/{environment_name}/variables"],createHostedRunnerForOrg:["POST /orgs/{org}/actions/hosted-runners"],createOrUpdateEnvironmentSecret:["PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name}"],createOrUpdateOrgSecret:["PUT /orgs/{org}/actions/secrets/{secret_name}"],createOrUpdateRepoSecret:["PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}"],createOrgVariable:["POST /orgs/{org}/actions/variables"],cre
Line truncated
|
|
||||||
globstar while`,e,l,t,p,g),this.matchOne(e.slice(l),t.slice(p),s))return this.debug("globstar found match!",l,a,g),!0;if(g==="."||g===".."||!r.dot&&g.charAt(0)==="."){this.debug("dot detected!",e,l,t,p);break}this.debug("globstar swallow a segment, and continue"),l++}return!!(s&&(this.debug(`
|
|
||||||
>>> no match, partial?`,e,l,t,p),l===a))}let h;if(typeof c=="string"?(h=u===c,this.debug("string match",c,u,h)):(h=c.test(u),this.debug("pattern match",c,u,h)),!h)return!1}if(o===a&&n===A)return!0;if(o===a)return s;if(n===A)return o===a-1&&e[o]==="";throw new Error("wtf?")}braceExpand(){return YI(this.pattern,this.options)}parse(e){Ya(e);let t=this.options;if(e==="**")return be;if(e==="")return"";let s,r=null;(s=e.match(yL))?r=t.dot?vL:xL:(s=e.match(dL))?r=(t.nocase?t.dot?QL:fL:t.dot?mL:EL)(s[1]):(s=e.match(kL))?r=(t.nocase?t.dot?RL:DL:t.dot?TL:FL)(s):(s=e.match(BL))?r=t.dot?IL:CL:(s=e.match(wL))&&(r=bL);let i=NI.fromGlob(e,this.options).toMMPattern();return r&&typeof i=="object"&&Reflect.defineProperty(i,"test",{value:r}),i}makeRe(){if(this.regexp||this.regexp===!1)return this.regexp;let e=this.set;if(!e.length)return this.regexp=!1,this.regexp;let t=this.options,s=t.noglobstar?NL:t.dot?GL:ML,r=new Set(t.nocase?["i"]:[]),i=e.map(a=>{let A=a.map(u=>{if(u instanceof RegExp)for(let l of u.flags.split(""))r.add(l);return typeof u=="string"?JL(u):u===be?be:u._src});A.forEach((u,l)=>{let p=A[l+1],g=A[l-1];u!==be||g===be||(g===void 0?p!==void 0&&p!==be?A[l+1]="(?:\\/|"+s+"\\/)?"+p:A[l]=s:p===void 0?A[l-1]=g+"(?:\\/|\\/"+s+")?":p!==be&&(A[l-1]=g+"(?:\\/|\\/"+s+"\\/)"+p,A[l+1]=be))});let c=A.filter(u=>u!==be);if(this.partial&&c.length>=1){let u=[];for(let l=1;l<=c.length;l++)u.push(c.slice(0,l).join("/"));return"(?:"+u.join("|")+")"}return c.join("/")}).join("|"),[o,n]=e.length>1?["(?:",")"]:["",""];i="^"+o+i+n+"$",this.partial&&(i="^(?:\\/|"+o+i.slice(1,-1)+n+")$"),this.negate&&(i="^(?!"+i+").+$");try{this.regexp=new RegExp(i,[...r].join(""))}catch{this.regexp=!1}return this.regexp}slashSplit(e){return this.preserveMultipleSlashes?e.split("/"):this.isWindows&&/^\/\/[^\/]+/.test(e)?["",...e.split(/\/+/)]:e.split(/\/+/)}match(e,t=this.partial){if(this.debug("match",e,this.pattern),this.comment)return!1;if(this.empty)return e==="";if(e==="/"&&t)return!0;let s=this.options;this.isWindows&&(e=e.split("\\").join("/"));let r=this.slashSplit(e);this.debug(this.pattern,"split",r);let i=this.set;this.debug(this.pattern,"set",i);let o=r[r.length-1];if(!o)for(let n=r.length-2;!o&&n>=0;n--)o=r[n];for(let n=0;n<i.length;n++){let a=i[n],A=r;if(s.matchBase&&a.length===1&&(A=[o]),this.matchOne(A,a,t))return s.flipNegate?!0:!this.negate}return s.flipNegate?!1:this.negate}static defaults(e){return ye.defaults(e).Minimatch}};ye.AST=NI;ye.Minimatch=fs;ye.escape=GI;ye.unescape=Kr;var PL=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,JI=new Set,$u=typeof process=="object"&&process?process:{},PI=(e,t,s,r)=>{typeof $u.emitWarning=="function"?$u.emitWarning(e,t,s,r):console.error(`[${s}] ${t}: ${e}`)},Oa=globalThis.AbortController,gI=globalThis.AbortSignal;if(typeof Oa>"u"){gI=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(s,r){this._onabort.push(r)}},Oa=class{constructor(){t()}signal=new gI;abort(s){if(!this.signal.aborted){this.signal.reason=s,this.signal.aborted=!0;for(let r of this.signal._onabort)r(s);this.signal.onabort?.(s)}}};let e=$u.env?.LRU_CACHE_IGNORE_AC_WARNING!=="1",t=()=>{e&&(e=!1,PI("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.","NO_ABORT_CONTROLLER","ENOTSUP",t))}}var HL=e=>!JI.has(e),ms=e=>e&&e===Math.floor(e)&&e>0&&isFinite(e),HI=e=>ms(e)?e<=Math.pow(2,8)?Uint8Array:e<=Math.pow(2,16)?Uint16Array:e<=Math.pow(2,32)?Uint32Array:e<=Number.MAX_SAFE_INTEGER?La:null:null,La=class extends Array{constructor(e){super(e),this.fill(0)}},VL=class uo{heap;length;static#e=!1;static create(t){let s=HI(t);if(!s)return[];uo.#e=!0;let r=new uo(t,s);return uo.#e=!1,r}constructor(t,s){if(!uo.#e)throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new s(t),this.length=0}push(t){this.heap[this.length++]=t}pop(){return this.heap[--this.length]}},Pa=class VI{#e;#t;#i;#s;#r;#A;#a;#c;get perf(){return this.#c}ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#l;#g;#h;#u;#n;#d;#C;#B;#E;#k;#m;#b;#y;#f;#Q;#I;#x;#o;#U;static unsafeExposeInternals(t){return{starts:t.#y,ttls:t.#f,autopurgeTimers:t.#Q,sizes:t.#b,keyMap:t.#h,keyList:t.#u,valList:t.#n,next:t.#d,prev:t.#C,get head(){return t.#B},get tail(){return t.#E},free:t.#k,isBackgroundFetch:s=>t.#p(s),backgroundFetch:(s,r,i,o)=>t.#J(s,r,i,o),moveToTail:s=>t.#G(s),indexes:s=>t.#R(s),rindexes:s=>t.#T(s),isStale:s=>t.#w(s)}}get max(){return this.#e}get maxSize(){return th
Line truncated
|
|
||||||
|
|
||||||
${s.data.body}`:t.body=s.data.body}return t.body=t.body?this.truncateReleaseNotes(t.body):void 0,this.github.rest.repos.createRelease(t)}async updateRelease(t){if(typeof t.make_latest=="string"&&!["true","false","legacy"].includes(t.make_latest)&&(t.make_latest=void 0),t.generate_release_notes){let s=await this.getReleaseNotes(t);t.generate_release_notes=!1,t.body?t.body=`${t.body}
|
|
||||||
|
|
||||||
${s.data.body}`:t.body=s.data.body}return t.body=t.body?this.truncateReleaseNotes(t.body):void 0,this.github.rest.repos.updateRelease(t)}async finalizeRelease(t){return await this.github.rest.repos.updateRelease({owner:t.owner,repo:t.repo,release_id:t.release_id,draft:!1,make_latest:t.make_latest})}allReleases(t){let s={per_page:100,...t};return this.github.paginate.iterator(this.github.rest.repos.listReleases.endpoint.merge(s))}async listReleaseAssets(t){return this.github.paginate(this.github.rest.repos.listReleaseAssets,{...t,per_page:100})}async deleteReleaseAsset(t){await this.github.rest.repos.deleteReleaseAsset(t)}async uploadReleaseAsset(t){return this.github.request({method:"POST",url:t.url,headers:{"content-length":`${t.size}`,"content-type":t.mime,authorization:`token ${t.token}`},data:t.data})}},v_=e=>({name:(0,xw.basename)(e),mime:k_(e),size:(0,ww.statSync)(e).size}),k_=e=>(0,yw.lookup)(e)||"application/octet-stream",vw=async(e,t,s,r,i)=>{let[o,n]=e.github_repository.split("/"),{name:a,mime:A,size:c}=v_(r),u=i.find(({name:g})=>g==Cw(a));if(u){if(e.input_overwrite_files===!1)return console.log(`Asset ${a} already exists and overwrite_files is false...`),null;console.log(`\u267B\uFE0F Deleting previously uploaded asset ${a}...`),await t.deleteReleaseAsset({asset_id:u.id||1,owner:o,repo:n})}console.log(`\u2B06\uFE0F Uploading ${a}...`);let l=new URL(s);l.searchParams.append("name",a);let p=await(0,bw.open)(r);try{let g=await t.uploadReleaseAsset({url:l.toString(),size:c,mime:A,token:e.github_token,data:p.readableWebStream({type:"bytes"})}),h=g.data;if(g.status!==201)throw new Error(`Failed to upload release asset ${a}. received status code ${g.status}
|
|
||||||
${h.message}
|
|
||||||
${JSON.stringify(h.errors)}`);return console.log(`\u2705 Uploaded ${a}`),h}finally{await p.close()}},ap=async(e,t,s=3)=>{if(s<=0)throw console.log("\u274C Too many retries. Aborting..."),new Error("Too many retries.");let[r,i]=e.github_repository.split("/"),o=e.input_tag_name||(ja(e.github_ref)?e.github_ref.replace("refs/tags/",""):""),n=e.input_discussion_category_name,a=e.input_generate_release_notes;try{let A=await D_(t,r,i,o);if(A===void 0)return await Iw(o,e,t,r,i,n,a,s);let c=A;console.log(`Found release ${c.name} (with id=${c.id})`);let u=c.id,l;e.input_target_commitish&&e.input_target_commitish!==c.target_commitish?(console.log(`Updating commit from "${c.target_commitish}" to "${e.input_target_commitish}"`),l=e.input_target_commitish):l=c.target_commitish;let p=o,g=e.input_name||c.name||o,h=np(e)||"",d=c.body||"",m;e.input_append_body&&h&&d?m=d+`
|
|
||||||
`+h:m=h||d;let E=e.input_prerelease!==void 0?e.input_prerelease:c.prerelease,f=e.input_make_latest;return(await t.updateRelease({owner:r,repo:i,release_id:u,tag_name:p,target_commitish:l,name:g,body:m,draft:c.draft,prerelease:E,discussion_category_name:n,generate_release_notes:a,make_latest:f})).data}catch(A){if(A.status!==404)throw console.log(`\u26A0\uFE0F Unexpected error fetching GitHub release for tag ${e.github_ref}: ${A}`),A;return await Iw(o,e,t,r,i,n,a,s)}},Ap=async(e,t,s,r=3)=>{if(e.input_draft===!0)return s;if(r<=0)throw console.log("\u274C Too many retries. Aborting..."),new Error("Too many retries.");let[i,o]=e.github_repository.split("/");try{let{data:n}=await t.finalizeRelease({owner:i,repo:o,release_id:s.id,make_latest:e.input_make_latest});return n}catch(n){return console.warn(`error finalizing release: ${n}`),console.log(`retrying... (${r-1} retries remaining)`),Ap(e,t,s,r-1)}},cp=async(e,t,s,r=3)=>{if(r<=0)throw console.log("\u274C Too many retries. Aborting..."),new Error("Too many retries.");let[i,o]=e.github_repository.split("/");try{return await t.listReleaseAssets({owner:i,repo:o,release_id:s.id})}catch(n){return console.warn(`error listing assets of release: ${n}`),console.log(`retrying... (${r-1} retries remaining)`),cp(e,t,s,r-1)}};async function D_(e,t,s,r){try{let{data:i}=await e.getReleaseByTag({owner:t,repo:s,tag:r});return i}catch(i){if(i.status===404)return;throw i}}async function Iw(e,t,s,r,i,o,n,a){let A=e,c=t.input_name||e,u=np(t),l=t.input_prerelease,p=t.input_target_commitish,g=t.input_make_latest,h="";p&&(h=` using commit "${p}"`),console.log(`\u{1F469}\u200D\u{1F3ED} Creating new GitHub release for tag ${A}${h}...`);try{return(await s.createRelease({owner:r,repo:i,tag_name:A,name:c,body:u,draft:!0,prerelease:l,target_commitish:p,discussion_category_name:o,generate_release_notes:n,make_latest:g})).data}catch(d){switch(console.log(`\u26A0\uFE0F GitHub release failed with status: ${d.status}`),console.log(`${JSON.stringify(d.response.data)}`),d.status){case 403:throw console.log("Skip retry \u2014 your GitHub token/PAT does not have the required permission to create a release"),d;case 404:throw console.log("Skip retry - discussion category mismatch"),d;case 422:if(d.response?.data?.errors?.[0]?.code==="already_exists")console.log("\u26A0\uFE0F Release already exists (race condition detected), retrying to find and update existing release...");else throw console.log("Skip retry - validation failed"),d;break}return console.log(`retrying... (${a-1} retries remaining)`),ap(t,s,a-1)}}var kw=require("process");async function R_(){try{let e=fw(kw.env);if(!e.input_tag_name&&!ja(e.github_ref)&&!e.input_draft)throw new Error("\u26A0\uFE0F GitHub Releases requires a tag");if(e.input_files){let o=Bw(e.input_files,e.input_working_directory);if(o.forEach(n=>{if(e.input_fail_on_unmatched_files)throw new Error(`\u26A0\uFE0F Pattern '${n}' does not match any files.`);console.warn(`\u{1F914} Pattern '${n}' does not match any files.`)}),o.length>0&&e.input_fail_on_unmatched_files)throw new Error("\u26A0\uFE0F There were unmatched files")}let t=WC(e.github_token,{throttle:{onRateLimit:(o,n)=>{if(console.warn(`Request quota exhausted for request ${n.method} ${n.url}`),n.request.retryCount===0)return console.log(`Retrying after ${o} seconds!`),!0},onAbuseLimit:(o,n)=>{console.warn(`Abuse detected for request ${n.method} ${n.url}`)}}}),s=new za(t),r=await ap(e,s),i=new Set;if(e.input_files&&e.input_files.length>0){let o=Qw(e.input_files,e.input_working_directory);if(o.length==0){if(e.input_fail_on_unmatched_files)throw new Error(`\u26A0\uFE0F ${e.input_files} does not include a valid file.`);console.warn(`\u{1F914} ${e.input_files} does not include a valid file.`)}let n=r.assets,a=async c=>{let u=await vw(e,s,mw(r.upload_url),c,n);return u?u.id:void 0},A;if(!e.input_preserve_order)A=await Promise.all(o.map(a));else{A=[];for(let c of o)A.push(await a(c))}i=new Set(A.filter(c=>c!==void 0))}console.log("Finalizing release..."),r=await Ap(e,s,r),console.log("Getting assets list...");{let o=[];i.size>0&&(o=(await cp(e,s,r)).filter(a=>i.has(a.id)).map(a=>{let{uploader:A,...c}=a;return c})),$i("assets",o)}console.log(`\u{1F389} Release ready at ${r.html_url}`),$i("url",r.html_url),$i("id",r.id.toString()),$i("upload_url",r.upload_url)}catch(e){KB(e.message)}}R_();
|
|
||||||
/*! Bundled license information:
|
|
||||||
|
|
||||||
undici/lib/web/fetch/body.js:
|
|
||||||
(*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> *)
|
|
||||||
|
|
||||||
undici/lib/web/websocket/frame.js:
|
|
||||||
(*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
|
|
||||||
|
|
||||||
mime-db/index.js:
|
|
||||||
(*!
|
|
||||||
* mime-db
|
|
||||||
* Copyright(c) 2014 Jonathan Ong
|
|
||||||
* Copyright(c) 2015-2022 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*)
|
|
||||||
|
|
||||||
mime-types/index.js:
|
|
||||||
(*!
|
|
||||||
* mime-types
|
|
||||||
* Copyright(c) 2014 Jonathan Ong
|
|
||||||
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
||||||
* MIT Licensed
|
|
||||||
*)
|
|
||||||
|
|
||||||
@octokit/request-error/dist-src/index.js:
|
|
||||||
(* v8 ignore else -- @preserve -- Bug with vitest coverage where it sees an else branch that doesn't exist *)
|
|
||||||
|
|
||||||
@octokit/request/dist-bundle/index.js:
|
|
||||||
(* v8 ignore next -- @preserve *)
|
|
||||||
(* v8 ignore else -- @preserve *)
|
|
||||||
*/
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
clearMocks: true,
|
||||||
|
moduleFileExtensions: ['js', 'ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/*.test.ts'],
|
||||||
|
testRunner: 'jest-circus/runner',
|
||||||
|
transform: {
|
||||||
|
'^.+\\.ts$': 'ts-jest'
|
||||||
|
},
|
||||||
|
verbose: true
|
||||||
|
}
|
||||||
Generated
+5084
-2561
File diff suppressed because it is too large.
Load diff
+25
-24
@@ -1,44 +1,45 @@
|
|||||||
{
|
{
|
||||||
"name": "action-gh-release",
|
"name": "action-gh-release",
|
||||||
"version": "2.5.1",
|
"version": "0.1.10",
|
||||||
"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",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "esbuild src/main.ts --bundle --platform=node --format=cjs --target=node20 --outfile=dist/index.js --minify",
|
"build": "ncc build src/main.ts --minify",
|
||||||
"build-debug": "esbuild src/main.ts --bundle --platform=node --format=cjs --target=node20 --outfile=dist/index.js --sourcemap --keep-names",
|
"test": "jest",
|
||||||
"typecheck": "tsc --noEmit",
|
|
||||||
"test": "vitest --coverage",
|
|
||||||
"fmt": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\"",
|
"fmt": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\"",
|
||||||
"fmtcheck": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\"",
|
"fmtcheck": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\""
|
||||||
"updatetag": "git tag -d v2 && git push origin :v2 && git tag -a v2 -m '' && git push origin v2"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/softprops/action-gh-release.git"
|
"url": "git+https://github.com/softprops/action-gh-template.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"actions"
|
"actions"
|
||||||
],
|
],
|
||||||
"author": "softprops",
|
"author": "softprops",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^3.0.0",
|
"@actions/core": "^1.4.0",
|
||||||
"@actions/github": "^9.0.0",
|
"@actions/github": "^5.0.0",
|
||||||
"@octokit/plugin-retry": "^8.1.0",
|
"@octokit/plugin-retry": "^3.0.9",
|
||||||
"@octokit/plugin-throttling": "^11.0.3",
|
"@octokit/plugin-throttling": "^3.5.1",
|
||||||
"glob": "^13.0.6",
|
"glob": "^7.1.6",
|
||||||
"mime-types": "^3.0.2"
|
"mime": "^2.4.4",
|
||||||
|
"node-fetch": "^2.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/glob": "^9.0.0",
|
"@types/glob": "^7.1.1",
|
||||||
"@types/mime-types": "^3.0.1",
|
"@types/jest": "^24.0.25",
|
||||||
"@types/node": "^20.19.37",
|
"@types/mime": "^2.0.1",
|
||||||
"@vitest/coverage-v8": "^4.1.0",
|
"@types/node": "^12.12.24",
|
||||||
"esbuild": "^0.27.3",
|
"@types/node-fetch": "^2.5.12",
|
||||||
"prettier": "3.8.1",
|
"@zeit/ncc": "^0.21.0",
|
||||||
"ts-node": "^10.9.2",
|
"jest": "^24.9.0",
|
||||||
"typescript": "^5.9.3",
|
"jest-circus": "^24.9.0",
|
||||||
"typescript-formatter": "^7.2.2",
|
"prettier": "1.19.1",
|
||||||
"vitest": "^4.0.4"
|
"ts-jest": "^24.2.0",
|
||||||
|
"typescript": "^3.7.4",
|
||||||
|
"typescript-formatter": "^7.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# actions requires a node_modules dir https://github.com/actions/toolkit/blob/master/docs/javascript-action.md#publish-a-releasesv1-action
|
||||||
|
# but its recommended not to check these in https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations
|
||||||
|
# as such the following hack is how we dill with it
|
||||||
|
|
||||||
|
if [[ $# -ne 1 ]]; then
|
||||||
|
echo "please pass a release version. i.e. $0 v1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git checkout -b releases/$1 # If this branch already exists, omit the -b flag
|
||||||
|
rm -rf node_modules
|
||||||
|
sed -i '/node_modules/d' .gitignore # Bash command that removes node_modules from .gitignore
|
||||||
|
npm install --production
|
||||||
|
git add node_modules -f .gitignore
|
||||||
|
git commit -m node_modules
|
||||||
|
git push origin releases/$1
|
||||||
+133
-424
@@ -1,9 +1,9 @@
|
|||||||
import { GitHub } from '@actions/github/lib/utils';
|
import fetch from "node-fetch";
|
||||||
import { statSync } from 'fs';
|
import { GitHub } from "@actions/github/lib/utils";
|
||||||
import { open } from 'fs/promises';
|
import { Config, isTag, releaseBody } from "./util";
|
||||||
import { lookup } from 'mime-types';
|
import { lstatSync, readFileSync } from "fs";
|
||||||
import { basename } from 'path';
|
import { getType } from "mime";
|
||||||
import { alignAssetName, Config, isTag, releaseBody } from './util';
|
import { basename } from "path";
|
||||||
|
|
||||||
type GitHub = InstanceType<typeof GitHub>;
|
type GitHub = InstanceType<typeof GitHub>;
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ export interface ReleaseAsset {
|
|||||||
name: string;
|
name: string;
|
||||||
mime: string;
|
mime: string;
|
||||||
size: number;
|
size: number;
|
||||||
|
data: Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Release {
|
export interface Release {
|
||||||
@@ -27,7 +28,11 @@ export interface Release {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Releaser {
|
export interface Releaser {
|
||||||
getReleaseByTag(params: { owner: string; repo: string; tag: string }): Promise<{ data: Release }>;
|
getReleaseByTag(params: {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
tag: string;
|
||||||
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
createRelease(params: {
|
createRelease(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
@@ -39,8 +44,6 @@ export interface Releaser {
|
|||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
target_commitish: string | undefined;
|
target_commitish: string | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}): Promise<{ data: Release }>;
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
updateRelease(params: {
|
updateRelease(params: {
|
||||||
@@ -54,34 +57,12 @@ export interface Releaser {
|
|||||||
draft: boolean | undefined;
|
draft: boolean | undefined;
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}): Promise<{ data: Release }>;
|
}): Promise<{ data: Release }>;
|
||||||
|
|
||||||
finalizeRelease(params: {
|
allReleases(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
release_id: number;
|
}): AsyncIterableIterator<{ data: Release[] }>;
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}): Promise<{ data: Release }>;
|
|
||||||
|
|
||||||
allReleases(params: { owner: string; repo: string }): AsyncIterable<{ data: Release[] }>;
|
|
||||||
|
|
||||||
listReleaseAssets(params: {
|
|
||||||
owner: string;
|
|
||||||
repo: string;
|
|
||||||
release_id: number;
|
|
||||||
}): Promise<Array<{ id: number; name: string; [key: string]: any }>>;
|
|
||||||
|
|
||||||
deleteReleaseAsset(params: { owner: string; repo: string; asset_id: number }): Promise<void>;
|
|
||||||
|
|
||||||
uploadReleaseAsset(params: {
|
|
||||||
url: string;
|
|
||||||
size: number;
|
|
||||||
mime: string;
|
|
||||||
token: string;
|
|
||||||
data: any;
|
|
||||||
}): Promise<{ status: number; data: any }>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GitHubReleaser implements Releaser {
|
export class GitHubReleaser implements Releaser {
|
||||||
@@ -98,27 +79,7 @@ export class GitHubReleaser implements Releaser {
|
|||||||
return this.github.rest.repos.getReleaseByTag(params);
|
return this.github.rest.repos.getReleaseByTag(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getReleaseNotes(params: {
|
createRelease(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;
|
||||||
@@ -128,29 +89,11 @@ export class GitHubReleaser implements Releaser {
|
|||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
target_commitish: string | undefined;
|
target_commitish: string | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}): Promise<{ data: Release }> {
|
}): Promise<{ data: Release }> {
|
||||||
if (
|
|
||||||
typeof params.make_latest === 'string' &&
|
|
||||||
!['true', 'false', 'legacy'].includes(params.make_latest)
|
|
||||||
) {
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateRelease(params: {
|
updateRelease(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
release_id: number;
|
release_id: number;
|
||||||
@@ -161,225 +104,146 @@ export class GitHubReleaser implements Releaser {
|
|||||||
draft: boolean | undefined;
|
draft: boolean | undefined;
|
||||||
prerelease: boolean | undefined;
|
prerelease: boolean | undefined;
|
||||||
discussion_category_name: string | undefined;
|
discussion_category_name: string | undefined;
|
||||||
generate_release_notes: boolean | undefined;
|
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}): Promise<{ data: Release }> {
|
}): Promise<{ data: Release }> {
|
||||||
if (
|
|
||||||
typeof params.make_latest === 'string' &&
|
|
||||||
!['true', 'false', 'legacy'].includes(params.make_latest)
|
|
||||||
) {
|
|
||||||
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: {
|
allReleases(params: {
|
||||||
owner: string;
|
owner: string;
|
||||||
repo: string;
|
repo: string;
|
||||||
release_id: number;
|
}): AsyncIterableIterator<{ data: Release[] }> {
|
||||||
make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}) {
|
|
||||||
return await this.github.rest.repos.updateRelease({
|
|
||||||
owner: params.owner,
|
|
||||||
repo: params.repo,
|
|
||||||
release_id: params.release_id,
|
|
||||||
draft: false,
|
|
||||||
make_latest: params.make_latest,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
allReleases(params: { owner: string; repo: string }): AsyncIterable<{ data: Release[] }> {
|
|
||||||
const updatedParams = { per_page: 100, ...params };
|
const updatedParams = { per_page: 100, ...params };
|
||||||
return this.github.paginate.iterator(
|
return this.github.paginate.iterator(
|
||||||
this.github.rest.repos.listReleases.endpoint.merge(updatedParams),
|
this.github.rest.repos.listReleases.endpoint.merge(updatedParams)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async listReleaseAssets(params: {
|
|
||||||
owner: string;
|
|
||||||
repo: string;
|
|
||||||
release_id: number;
|
|
||||||
}): Promise<Array<{ id: number; name: string; [key: string]: any }>> {
|
|
||||||
return this.github.paginate(this.github.rest.repos.listReleaseAssets, {
|
|
||||||
...params,
|
|
||||||
per_page: 100,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteReleaseAsset(params: {
|
|
||||||
owner: string;
|
|
||||||
repo: string;
|
|
||||||
asset_id: number;
|
|
||||||
}): Promise<void> {
|
|
||||||
await this.github.rest.repos.deleteReleaseAsset(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
async uploadReleaseAsset(params: {
|
|
||||||
url: string;
|
|
||||||
size: number;
|
|
||||||
mime: string;
|
|
||||||
token: string;
|
|
||||||
data: any;
|
|
||||||
}): Promise<{ status: number; data: any }> {
|
|
||||||
return this.github.request({
|
|
||||||
method: 'POST',
|
|
||||||
url: params.url,
|
|
||||||
headers: {
|
|
||||||
'content-length': `${params.size}`,
|
|
||||||
'content-type': params.mime,
|
|
||||||
authorization: `token ${params.token}`,
|
|
||||||
},
|
|
||||||
data: params.data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const asset = (path: string): ReleaseAsset => {
|
export const asset = (path: string): ReleaseAsset => {
|
||||||
return {
|
return {
|
||||||
name: basename(path),
|
name: basename(path),
|
||||||
mime: mimeOrDefault(path),
|
mime: mimeOrDefault(path),
|
||||||
size: statSync(path).size,
|
size: lstatSync(path).size,
|
||||||
|
data: readFileSync(path)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mimeOrDefault = (path: string): string => {
|
export const mimeOrDefault = (path: string): string => {
|
||||||
return lookup(path) || 'application/octet-stream';
|
return getType(path) || "application/octet-stream";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const upload = async (
|
export const upload = async (
|
||||||
config: Config,
|
config: Config,
|
||||||
releaser: Releaser,
|
github: GitHub,
|
||||||
url: string,
|
url: string,
|
||||||
path: string,
|
path: string,
|
||||||
currentAssets: Array<{ id: number; name: string }>,
|
currentAssets: Array<{ id: number; name: string }>
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
const [owner, repo] = config.github_repository.split('/');
|
const [owner, repo] = config.github_repository.split("/");
|
||||||
const { name, mime, size } = asset(path);
|
const { name, size, mime, data: body } = asset(path);
|
||||||
const currentAsset = currentAssets.find(
|
const currentAsset = currentAssets.find(
|
||||||
// note: GitHub renames asset filenames that have special characters, non-alphanumeric characters, and leading or trailing periods. The "List release assets" endpoint lists the renamed filenames.
|
({ name: currentName }) => currentName == name
|
||||||
// due to this renaming we need to be mindful when we compare the file name we're uploading with a name github may already have rewritten for logical comparison
|
|
||||||
// see https://docs.github.com/en/rest/releases/assets?apiVersion=2022-11-28#upload-a-release-asset
|
|
||||||
({ name: currentName }) => currentName == alignAssetName(name),
|
|
||||||
);
|
);
|
||||||
if (currentAsset) {
|
if (currentAsset) {
|
||||||
if (config.input_overwrite_files === false) {
|
console.log(`♻️ Deleting previously uploaded asset ${name}...`);
|
||||||
console.log(`Asset ${name} already exists and overwrite_files is false...`);
|
await github.rest.repos.deleteReleaseAsset({
|
||||||
return null;
|
asset_id: currentAsset.id || 1,
|
||||||
} else {
|
owner,
|
||||||
console.log(`♻️ Deleting previously uploaded asset ${name}...`);
|
repo
|
||||||
await releaser.deleteReleaseAsset({
|
});
|
||||||
asset_id: currentAsset.id || 1,
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
console.log(`⬆️ Uploading ${name}...`);
|
console.log(`⬆️ Uploading ${name}...`);
|
||||||
const endpoint = new URL(url);
|
const endpoint = new URL(url);
|
||||||
endpoint.searchParams.append('name', name);
|
endpoint.searchParams.append("name", name);
|
||||||
const fh = await open(path);
|
const resp = await fetch(endpoint, {
|
||||||
try {
|
headers: {
|
||||||
const resp = await releaser.uploadReleaseAsset({
|
"content-length": `${size}`,
|
||||||
url: endpoint.toString(),
|
"content-type": mime,
|
||||||
size,
|
authorization: `token ${config.github_token}`
|
||||||
mime,
|
},
|
||||||
token: config.github_token,
|
method: "POST",
|
||||||
data: fh.readableWebStream({ type: 'bytes' }),
|
body
|
||||||
});
|
});
|
||||||
const json = resp.data;
|
const json = await resp.json();
|
||||||
if (resp.status !== 201) {
|
if (resp.status !== 201) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to upload release asset ${name}. received status code ${
|
`Failed to upload release asset ${name}. recieved status code ${
|
||||||
resp.status
|
resp.status
|
||||||
}\n${json.message}\n${JSON.stringify(json.errors)}`,
|
}\n${json.message}\n${JSON.stringify(json.errors)}`
|
||||||
);
|
);
|
||||||
}
|
|
||||||
console.log(`✅ Uploaded ${name}`);
|
|
||||||
return json;
|
|
||||||
} finally {
|
|
||||||
await fh.close();
|
|
||||||
}
|
}
|
||||||
|
return json;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const release = async (
|
export const release = async (
|
||||||
config: Config,
|
config: Config,
|
||||||
releaser: Releaser,
|
releaser: Releaser,
|
||||||
maxRetries: number = 3,
|
maxRetries: number = 3
|
||||||
): Promise<Release> => {
|
): Promise<Release> => {
|
||||||
if (maxRetries <= 0) {
|
if (maxRetries <= 0) {
|
||||||
console.log(`❌ Too many retries. Aborting...`);
|
console.log(`❌ Too many retries. Aborting...`);
|
||||||
throw new Error('Too many retries.');
|
throw new Error("Too many retries.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const [owner, repo] = config.github_repository.split('/');
|
const [owner, repo] = config.github_repository.split("/");
|
||||||
const tag =
|
const tag =
|
||||||
config.input_tag_name ||
|
config.input_tag_name ||
|
||||||
(isTag(config.github_ref) ? config.github_ref.replace('refs/tags/', '') : '');
|
(isTag(config.github_ref)
|
||||||
|
? config.github_ref.replace("refs/tags/", "")
|
||||||
|
: "");
|
||||||
|
|
||||||
const discussion_category_name = config.input_discussion_category_name;
|
const discussion_category_name = config.input_discussion_category_name;
|
||||||
const generate_release_notes = config.input_generate_release_notes;
|
|
||||||
try {
|
try {
|
||||||
const _release: Release | undefined = await findTagFromReleases(releaser, owner, repo, tag);
|
// you can't get a an existing draft by tag
|
||||||
|
// so we must find one in the list of all releases
|
||||||
if (_release === undefined) {
|
if (config.input_draft) {
|
||||||
return await createRelease(
|
for await (const response of releaser.allReleases({
|
||||||
tag,
|
|
||||||
config,
|
|
||||||
releaser,
|
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo
|
||||||
discussion_category_name,
|
})) {
|
||||||
generate_release_notes,
|
let release = response.data.find(release => release.tag_name === tag);
|
||||||
maxRetries,
|
if (release) {
|
||||||
);
|
return release;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let existingRelease = await releaser.getReleaseByTag({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
tag
|
||||||
|
});
|
||||||
|
|
||||||
let existingRelease: Release = _release!;
|
const release_id = existingRelease.data.id;
|
||||||
console.log(`Found release ${existingRelease.name} (with id=${existingRelease.id})`);
|
|
||||||
|
|
||||||
const release_id = existingRelease.id;
|
|
||||||
let target_commitish: string;
|
let target_commitish: string;
|
||||||
if (
|
if (
|
||||||
config.input_target_commitish &&
|
config.input_target_commitish &&
|
||||||
config.input_target_commitish !== existingRelease.target_commitish
|
config.input_target_commitish !== existingRelease.data.target_commitish
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
`Updating commit from "${existingRelease.target_commitish}" to "${config.input_target_commitish}"`,
|
`Updating commit from "${existingRelease.data.target_commitish}" to "${config.input_target_commitish}"`
|
||||||
);
|
);
|
||||||
target_commitish = config.input_target_commitish;
|
target_commitish = config.input_target_commitish;
|
||||||
} else {
|
} else {
|
||||||
target_commitish = existingRelease.target_commitish;
|
target_commitish = existingRelease.data.target_commitish;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag_name = tag;
|
const tag_name = tag;
|
||||||
const name = config.input_name || existingRelease.name || tag;
|
const name = config.input_name || existingRelease.data.name || tag;
|
||||||
// revisit: support a new body-concat-strategy input for accumulating
|
|
||||||
// body parts as a release gets updated. some users will likely want this while
|
|
||||||
// others won't previously this was duplicating content for most which
|
|
||||||
// no one wants
|
|
||||||
const workflowBody = releaseBody(config) || '';
|
|
||||||
const existingReleaseBody = existingRelease.body || '';
|
|
||||||
let body: string;
|
|
||||||
if (config.input_append_body && workflowBody && existingReleaseBody) {
|
|
||||||
body = existingReleaseBody + '\n' + workflowBody;
|
|
||||||
} else {
|
|
||||||
body = workflowBody || existingReleaseBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let body: string = "";
|
||||||
|
if (existingRelease.data.body) body += existingRelease.data.body;
|
||||||
|
let workflowBody = releaseBody(config);
|
||||||
|
if (existingRelease.data.body && workflowBody) body += "\n";
|
||||||
|
if (workflowBody) body += workflowBody;
|
||||||
|
|
||||||
|
const draft =
|
||||||
|
config.input_draft !== undefined
|
||||||
|
? config.input_draft
|
||||||
|
: existingRelease.data.draft;
|
||||||
const prerelease =
|
const prerelease =
|
||||||
config.input_prerelease !== undefined ? config.input_prerelease : existingRelease.prerelease;
|
config.input_prerelease !== undefined
|
||||||
|
? config.input_prerelease
|
||||||
const make_latest = config.input_make_latest;
|
: existingRelease.data.prerelease;
|
||||||
|
|
||||||
const release = await releaser.updateRelease({
|
const release = await releaser.updateRelease({
|
||||||
owner,
|
owner,
|
||||||
@@ -389,210 +253,55 @@ export const release = async (
|
|||||||
target_commitish,
|
target_commitish,
|
||||||
name,
|
name,
|
||||||
body,
|
body,
|
||||||
draft: existingRelease.draft,
|
draft,
|
||||||
prerelease,
|
prerelease,
|
||||||
discussion_category_name,
|
discussion_category_name
|
||||||
generate_release_notes,
|
|
||||||
make_latest,
|
|
||||||
});
|
});
|
||||||
return release.data;
|
return release.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.status !== 404) {
|
if (error.status === 404) {
|
||||||
|
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;
|
||||||
|
let commitMessage: string = "";
|
||||||
|
if (target_commitish) {
|
||||||
|
commitMessage = ` using commit "${target_commitish}"`;
|
||||||
|
}
|
||||||
console.log(
|
console.log(
|
||||||
`⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`,
|
`👩🏭 Creating new GitHub release in ${owner}/${repo} for tag ${tag_name}${commitMessage}...`
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
let release = await releaser.createRelease({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
tag_name,
|
||||||
|
name,
|
||||||
|
body,
|
||||||
|
draft,
|
||||||
|
prerelease,
|
||||||
|
target_commitish,
|
||||||
|
discussion_category_name
|
||||||
|
});
|
||||||
|
return release.data;
|
||||||
|
} catch (error) {
|
||||||
|
// presume a race with competing metrix runs
|
||||||
|
console.log(
|
||||||
|
`⚠️ GitHub release failed with status: ${
|
||||||
|
error.status
|
||||||
|
}\n${JSON.stringify(
|
||||||
|
error.response.data.errors
|
||||||
|
)}\nretrying... (${maxRetries - 1} retries remaining)`
|
||||||
|
);
|
||||||
|
return release(config, releaser, maxRetries - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
`⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await createRelease(
|
|
||||||
tag,
|
|
||||||
config,
|
|
||||||
releaser,
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
discussion_category_name,
|
|
||||||
generate_release_notes,
|
|
||||||
maxRetries,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
|
||||||
make_latest: config.input_make_latest,
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`error finalizing release: ${error}`);
|
|
||||||
console.log(`retrying... (${maxRetries - 1} retries remaining)`);
|
|
||||||
return finalizeRelease(config, releaser, release, maxRetries - 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists assets belonging to a release.
|
|
||||||
*
|
|
||||||
* @param config - Release configuration as specified by user
|
|
||||||
* @param releaser - The GitHub API wrapper for release operations
|
|
||||||
* @param release - The existing release to be checked
|
|
||||||
* @param maxRetries - The maximum number of attempts
|
|
||||||
*/
|
|
||||||
export const listReleaseAssets = async (
|
|
||||||
config: Config,
|
|
||||||
releaser: Releaser,
|
|
||||||
release: Release,
|
|
||||||
maxRetries: number = 3,
|
|
||||||
): Promise<Array<{ id: number; name: string; [key: string]: any }>> => {
|
|
||||||
if (maxRetries <= 0) {
|
|
||||||
console.log(`❌ Too many retries. Aborting...`);
|
|
||||||
throw new Error('Too many retries.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const [owner, repo] = config.github_repository.split('/');
|
|
||||||
try {
|
|
||||||
const assets = await releaser.listReleaseAssets({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
release_id: release.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return assets;
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`error listing assets of release: ${error}`);
|
|
||||||
console.log(`retrying... (${maxRetries - 1} retries remaining)`);
|
|
||||||
return listReleaseAssets(config, releaser, release, maxRetries - 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds a release by tag name.
|
|
||||||
*
|
|
||||||
* Uses the direct getReleaseByTag API for O(1) lookup instead of iterating
|
|
||||||
* through all releases. This also avoids GitHub's API pagination limit of
|
|
||||||
* 10000 results which would cause failures for repositories with many releases.
|
|
||||||
*
|
|
||||||
* @param releaser - The GitHub API wrapper for release operations
|
|
||||||
* @param owner - The owner of the repository
|
|
||||||
* @param repo - The name of the repository
|
|
||||||
* @param tag - The tag name to search for
|
|
||||||
* @returns The release with the given tag name, or undefined if no release with that tag name is found
|
|
||||||
*/
|
|
||||||
export async function findTagFromReleases(
|
|
||||||
releaser: Releaser,
|
|
||||||
owner: string,
|
|
||||||
repo: string,
|
|
||||||
tag: string,
|
|
||||||
): Promise<Release | undefined> {
|
|
||||||
try {
|
|
||||||
const { data: release } = await releaser.getReleaseByTag({ owner, repo, tag });
|
|
||||||
return release;
|
|
||||||
} catch (error) {
|
|
||||||
// Release not found (404) or other error - return undefined to allow creation
|
|
||||||
if (error.status === 404) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
// Re-throw unexpected errors
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createRelease(
|
|
||||||
tag: string,
|
|
||||||
config: Config,
|
|
||||||
releaser: Releaser,
|
|
||||||
owner: string,
|
|
||||||
repo: string,
|
|
||||||
discussion_category_name: string | undefined,
|
|
||||||
generate_release_notes: boolean | undefined,
|
|
||||||
maxRetries: number,
|
|
||||||
) {
|
|
||||||
const tag_name = tag;
|
|
||||||
const name = config.input_name || tag;
|
|
||||||
const body = releaseBody(config);
|
|
||||||
const prerelease = config.input_prerelease;
|
|
||||||
const target_commitish = config.input_target_commitish;
|
|
||||||
const make_latest = config.input_make_latest;
|
|
||||||
let commitMessage: string = '';
|
|
||||||
if (target_commitish) {
|
|
||||||
commitMessage = ` using commit "${target_commitish}"`;
|
|
||||||
}
|
|
||||||
console.log(`👩🏭 Creating new GitHub release for tag ${tag_name}${commitMessage}...`);
|
|
||||||
try {
|
|
||||||
let release = await releaser.createRelease({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
tag_name,
|
|
||||||
name,
|
|
||||||
body,
|
|
||||||
draft: true,
|
|
||||||
prerelease,
|
|
||||||
target_commitish,
|
|
||||||
discussion_category_name,
|
|
||||||
generate_release_notes,
|
|
||||||
make_latest,
|
|
||||||
});
|
|
||||||
return release.data;
|
|
||||||
} catch (error) {
|
|
||||||
// presume a race with competing matrix runs
|
|
||||||
console.log(`⚠️ GitHub release failed with status: ${error.status}`);
|
|
||||||
console.log(`${JSON.stringify(error.response.data)}`);
|
|
||||||
|
|
||||||
switch (error.status) {
|
|
||||||
case 403:
|
|
||||||
console.log(
|
|
||||||
'Skip retry — your GitHub token/PAT does not have the required permission to create a release',
|
|
||||||
);
|
|
||||||
throw error;
|
|
||||||
|
|
||||||
case 404:
|
|
||||||
console.log('Skip retry - discussion category mismatch');
|
|
||||||
throw error;
|
|
||||||
|
|
||||||
case 422:
|
|
||||||
// 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)`);
|
|
||||||
return release(config, releaser, maxRetries - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+50
-70
@@ -1,25 +1,32 @@
|
|||||||
import { setFailed, setOutput } from '@actions/core';
|
import {
|
||||||
import { getOctokit } from '@actions/github';
|
paths,
|
||||||
import { GitHubReleaser, release, finalizeRelease, upload, listReleaseAssets } from './github';
|
parseConfig,
|
||||||
import { isTag, parseConfig, paths, unmatchedPatterns, uploadUrl } from './util';
|
isTag,
|
||||||
|
unmatchedPatterns,
|
||||||
|
uploadUrl
|
||||||
|
} from "./util";
|
||||||
|
import { release, upload, GitHubReleaser } from "./github";
|
||||||
|
import { getOctokit } from "@actions/github";
|
||||||
|
import { setFailed, setOutput } from "@actions/core";
|
||||||
|
import { GitHub, getOctokitOptions } from "@actions/github/lib/utils";
|
||||||
|
|
||||||
import { env } from 'process';
|
import { env } from "process";
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
const config = parseConfig(env);
|
const config = parseConfig(env);
|
||||||
if (!config.input_tag_name && !isTag(config.github_ref) && !config.input_draft) {
|
if (
|
||||||
|
!config.input_tag_name &&
|
||||||
|
!isTag(config.github_ref) &&
|
||||||
|
!config.input_draft
|
||||||
|
) {
|
||||||
throw new Error(`⚠️ GitHub Releases requires a tag`);
|
throw new Error(`⚠️ GitHub Releases requires a tag`);
|
||||||
}
|
}
|
||||||
if (config.input_files) {
|
if (config.input_files) {
|
||||||
const patterns = unmatchedPatterns(config.input_files, config.input_working_directory);
|
const patterns = unmatchedPatterns(config.input_files);
|
||||||
patterns.forEach((pattern) => {
|
patterns.forEach(pattern =>
|
||||||
if (config.input_fail_on_unmatched_files) {
|
console.warn(`🤔 Pattern '${pattern}' does not match any files.`)
|
||||||
throw new Error(`⚠️ Pattern '${pattern}' does not match any files.`);
|
);
|
||||||
} else {
|
|
||||||
console.warn(`🤔 Pattern '${pattern}' does not match any files.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (patterns.length > 0 && config.input_fail_on_unmatched_files) {
|
if (patterns.length > 0 && config.input_fail_on_unmatched_files) {
|
||||||
throw new Error(`⚠️ There were unmatched files`);
|
throw new Error(`⚠️ There were unmatched files`);
|
||||||
}
|
}
|
||||||
@@ -34,7 +41,9 @@ async function run() {
|
|||||||
//new oktokit(
|
//new oktokit(
|
||||||
throttle: {
|
throttle: {
|
||||||
onRateLimit: (retryAfter, options) => {
|
onRateLimit: (retryAfter, options) => {
|
||||||
console.warn(`Request quota exhausted for request ${options.method} ${options.url}`);
|
console.warn(
|
||||||
|
`Request quota exhausted for request ${options.method} ${options.url}`
|
||||||
|
);
|
||||||
if (options.request.retryCount === 0) {
|
if (options.request.retryCount === 0) {
|
||||||
// only retries once
|
// only retries once
|
||||||
console.log(`Retrying after ${retryAfter} seconds!`);
|
console.log(`Retrying after ${retryAfter} seconds!`);
|
||||||
@@ -43,67 +52,38 @@ async function run() {
|
|||||||
},
|
},
|
||||||
onAbuseLimit: (retryAfter, options) => {
|
onAbuseLimit: (retryAfter, options) => {
|
||||||
// does not retry, only logs a warning
|
// does not retry, only logs a warning
|
||||||
console.warn(`Abuse detected for request ${options.method} ${options.url}`);
|
console.warn(
|
||||||
},
|
`Abuse detected for request ${options.method} ${options.url}`
|
||||||
},
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
//);
|
//);
|
||||||
const releaser = new GitHubReleaser(gh);
|
const rel = await release(config, new GitHubReleaser(gh));
|
||||||
let rel = await release(config, releaser);
|
if (config.input_files) {
|
||||||
let uploadedAssetIds: Set<number> = new Set();
|
const files = paths(config.input_files);
|
||||||
if (config.input_files && config.input_files.length > 0) {
|
|
||||||
const files = paths(config.input_files, config.input_working_directory);
|
|
||||||
if (files.length == 0) {
|
if (files.length == 0) {
|
||||||
if (config.input_fail_on_unmatched_files) {
|
console.warn(`🤔 ${config.input_files} not include valid file.`);
|
||||||
throw new Error(`⚠️ ${config.input_files} does not include a valid file.`);
|
|
||||||
} else {
|
|
||||||
console.warn(`🤔 ${config.input_files} does not include a valid file.`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const currentAssets = rel.assets;
|
const currentAsserts = rel.assets;
|
||||||
|
await Promise.all(
|
||||||
const uploadFile = async (path: string) => {
|
files.map(async path => {
|
||||||
const json = await upload(config, releaser, uploadUrl(rel.upload_url), path, currentAssets);
|
await upload(
|
||||||
return json ? (json.id as number) : undefined;
|
config,
|
||||||
};
|
gh,
|
||||||
|
uploadUrl(rel.upload_url),
|
||||||
let results: (number | undefined)[];
|
path,
|
||||||
if (!config.input_preserve_order) {
|
currentAsserts
|
||||||
results = await Promise.all(files.map(uploadFile));
|
);
|
||||||
} else {
|
})
|
||||||
results = [];
|
).catch(error => {
|
||||||
for (const path of files) {
|
throw error;
|
||||||
results.push(await uploadFile(path));
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadedAssetIds = new Set(results.filter((id): id is number => id !== undefined));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Finalizing release...');
|
|
||||||
rel = await finalizeRelease(config, releaser, rel);
|
|
||||||
|
|
||||||
// Draft releases use temporary "untagged-..." URLs for assets.
|
|
||||||
// URLs will be changed to correct ones once the release is published.
|
|
||||||
console.log('Getting assets list...');
|
|
||||||
{
|
|
||||||
let assets: any[] = [];
|
|
||||||
if (uploadedAssetIds.size > 0) {
|
|
||||||
const updatedAssets = await listReleaseAssets(config, releaser, rel);
|
|
||||||
assets = updatedAssets
|
|
||||||
.filter((a) => uploadedAssetIds.has(a.id))
|
|
||||||
.map((a) => {
|
|
||||||
const { uploader, ...rest } = a;
|
|
||||||
return rest;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setOutput('assets', assets);
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
||||||
setOutput('upload_url', rel.upload_url);
|
setOutput("upload_url", rel.upload_url);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setFailed(error.message);
|
setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-103
@@ -1,6 +1,5 @@
|
|||||||
import * as glob from 'glob';
|
import * as glob from "glob";
|
||||||
import { statSync, readFileSync } from 'fs';
|
import { lstatSync, readFileSync } from "fs";
|
||||||
import * as pathLib from 'path';
|
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
github_token: string;
|
github_token: string;
|
||||||
@@ -13,21 +12,15 @@ export interface Config {
|
|||||||
input_body?: string;
|
input_body?: string;
|
||||||
input_body_path?: string;
|
input_body_path?: string;
|
||||||
input_files?: string[];
|
input_files?: string[];
|
||||||
input_working_directory?: string;
|
|
||||||
input_overwrite_files?: boolean;
|
|
||||||
input_draft?: boolean;
|
input_draft?: boolean;
|
||||||
input_preserve_order?: boolean;
|
|
||||||
input_prerelease?: boolean;
|
input_prerelease?: boolean;
|
||||||
input_fail_on_unmatched_files?: boolean;
|
input_fail_on_unmatched_files?: boolean;
|
||||||
input_target_commitish?: string;
|
input_target_commitish?: string;
|
||||||
input_discussion_category_name?: string;
|
input_discussion_category_name?: string;
|
||||||
input_generate_release_notes?: boolean;
|
|
||||||
input_append_body?: boolean;
|
|
||||||
input_make_latest: 'true' | 'false' | 'legacy' | undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const uploadUrl = (url: string): string => {
|
export const uploadUrl = (url: string): string => {
|
||||||
const templateMarkerPos = url.indexOf('{');
|
const templateMarkerPos = url.indexOf("{");
|
||||||
if (templateMarkerPos > -1) {
|
if (templateMarkerPos > -1) {
|
||||||
return url.substring(0, templateMarkerPos);
|
return url.substring(0, templateMarkerPos);
|
||||||
}
|
}
|
||||||
@@ -35,123 +28,64 @@ export const uploadUrl = (url: string): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const releaseBody = (config: Config): string | undefined => {
|
export const releaseBody = (config: Config): string | undefined => {
|
||||||
if (config.input_body_path) {
|
return (
|
||||||
try {
|
(config.input_body_path &&
|
||||||
const contents = readFileSync(config.input_body_path, 'utf8');
|
readFileSync(config.input_body_path).toString("utf8")) ||
|
||||||
return contents;
|
config.input_body
|
||||||
} 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
|
return files.split(/\r?\n/).reduce<string[]>(
|
||||||
.split(/\r?\n/)
|
(acc, line) =>
|
||||||
.flatMap((line) => smartSplit(line))
|
acc
|
||||||
.filter((pat) => pat.trim() !== '');
|
.concat(line.split(","))
|
||||||
|
.filter(pat => pat)
|
||||||
|
.map(pat => pat.trim()),
|
||||||
|
[]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseConfig = (env: Env): Config => {
|
export const parseConfig = (env: Env): Config => {
|
||||||
return {
|
return {
|
||||||
github_token: env.GITHUB_TOKEN || env.INPUT_TOKEN || '',
|
github_token: env.GITHUB_TOKEN || env.INPUT_TOKEN || "",
|
||||||
github_ref: env.GITHUB_REF || '',
|
github_ref: env.GITHUB_REF || "",
|
||||||
github_repository: env.INPUT_REPOSITORY || env.GITHUB_REPOSITORY || '',
|
github_repository: env.INPUT_REPOSITORY || env.GITHUB_REPOSITORY || "",
|
||||||
input_name: env.INPUT_NAME,
|
input_name: env.INPUT_NAME,
|
||||||
input_tag_name: env.INPUT_TAG_NAME?.trim(),
|
input_tag_name: env.INPUT_TAG_NAME?.trim(),
|
||||||
input_body: env.INPUT_BODY,
|
input_body: env.INPUT_BODY,
|
||||||
input_body_path: env.INPUT_BODY_PATH,
|
input_body_path: env.INPUT_BODY_PATH,
|
||||||
input_files: parseInputFiles(env.INPUT_FILES || ''),
|
input_files: parseInputFiles(env.INPUT_FILES || ""),
|
||||||
input_working_directory: env.INPUT_WORKING_DIRECTORY || undefined,
|
input_draft: env.INPUT_DRAFT ? env.INPUT_DRAFT === "true" : undefined,
|
||||||
input_overwrite_files: env.INPUT_OVERWRITE_FILES
|
input_prerelease: env.INPUT_PRERELEASE
|
||||||
? env.INPUT_OVERWRITE_FILES == 'true'
|
? env.INPUT_PRERELEASE == "true"
|
||||||
: undefined,
|
: undefined,
|
||||||
input_draft: env.INPUT_DRAFT ? env.INPUT_DRAFT === 'true' : undefined,
|
input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == "true",
|
||||||
input_preserve_order: env.INPUT_PRESERVE_ORDER ? env.INPUT_PRESERVE_ORDER == 'true' : undefined,
|
input_target_commitish: env.INPUT_TARGET_COMMITISH,
|
||||||
input_prerelease: env.INPUT_PRERELEASE ? env.INPUT_PRERELEASE == 'true' : undefined,
|
input_discussion_category_name: env.INPUT_DISCUSSION_CATEGORY_NAME
|
||||||
input_fail_on_unmatched_files: env.INPUT_FAIL_ON_UNMATCHED_FILES == 'true',
|
|
||||||
input_target_commitish: env.INPUT_TARGET_COMMITISH || undefined,
|
|
||||||
input_discussion_category_name: env.INPUT_DISCUSSION_CATEGORY_NAME || undefined,
|
|
||||||
input_generate_release_notes: env.INPUT_GENERATE_RELEASE_NOTES == 'true',
|
|
||||||
input_append_body: env.INPUT_APPEND_BODY == 'true',
|
|
||||||
input_make_latest: parseMakeLatest(env.INPUT_MAKE_LATEST),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseMakeLatest = (value: string | undefined): 'true' | 'false' | 'legacy' | undefined => {
|
export const paths = (patterns: string[]): string[] => {
|
||||||
if (value === 'true' || value === 'false' || value === 'legacy') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const paths = (patterns: string[], cwd?: string): string[] => {
|
|
||||||
return patterns.reduce((acc: string[], pattern: string): string[] => {
|
return patterns.reduce((acc: string[], pattern: string): string[] => {
|
||||||
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
|
return acc.concat(
|
||||||
const resolved = matches
|
glob.sync(pattern).filter(path => lstatSync(path).isFile())
|
||||||
.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[], cwd?: string): string[] => {
|
export const unmatchedPatterns = (patterns: string[]): string[] => {
|
||||||
return patterns.reduce((acc: string[], pattern: string): string[] => {
|
return patterns.reduce((acc: string[], pattern: string): string[] => {
|
||||||
const matches = glob.sync(pattern, { cwd, dot: true, absolute: false });
|
return acc.concat(
|
||||||
const files = matches.filter((p) => {
|
glob.sync(pattern).filter(path => lstatSync(path).isFile()).length == 0
|
||||||
try {
|
? [pattern]
|
||||||
const full = cwd ? pathLib.join(cwd, p) : p;
|
: []
|
||||||
return statSync(full).isFile();
|
);
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return acc.concat(files.length == 0 ? [pattern] : []);
|
|
||||||
}, []);
|
}, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isTag = (ref: string): boolean => {
|
export const isTag = (ref: string): boolean => {
|
||||||
return ref.startsWith('refs/tags/');
|
return ref.startsWith("refs/tags/");
|
||||||
};
|
|
||||||
|
|
||||||
export const alignAssetName = (assetName: string): string => {
|
|
||||||
return assetName.replace(/ /g, '.');
|
|
||||||
};
|
};
|
||||||
+5
-7
@@ -1,10 +1,9 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"useUnknownInCatchVariables": false,
|
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
// "incremental": true, /* Enable incremental compilation */
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
"target": "es2022",
|
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||||
"module": "NodeNext",
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
// "checkJs": true, /* Report errors in .js files. */
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
@@ -25,7 +24,6 @@
|
|||||||
/* Strict Type-Checking Options */
|
/* Strict Type-Checking Options */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
"skipLibCheck": true,
|
|
||||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
@@ -45,7 +43,7 @@
|
|||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
"types": ["node", "vitest/globals"],
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
@@ -61,5 +59,5 @@
|
|||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "**/*.test.ts", "vitest.config.ts"]
|
"exclude": ["node_modules", "**/*.test.ts"]
|
||||||
}
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { defineConfig } from 'vitest/config';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
test: {
|
|
||||||
environment: 'node',
|
|
||||||
coverage: {
|
|
||||||
reporter: ['text', 'lcov'],
|
|
||||||
},
|
|
||||||
include: ['__tests__/**/*.ts'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Reference in new issue
Block a user