Compare commits

..
3 Commits
Author SHA1 Message Date
softprops b21b43df68 empathy for those new to typescript projects 2019-09-09 21:59:28 +09:00
softprops 4976c1864c call out cross platform support 2019-09-09 21:50:33 +09:00
softprops a40b254993 node_modules 2019-09-09 21:38:33 +09:00
476 changed files with 89425 additions and 5841 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
ko_fi: softprops
-97
View File
@@ -1,97 +0,0 @@
name: Bug report
description: Report a bug or regression in action-gh-release
title: "[Bug]: "
labels:
- bug
body:
- type: markdown
attributes:
value: |
Before filing:
- confirm the problem still reproduces on the latest release or `master`
- search existing issues for the same behavior
- if the original repository is private, include a minimal public repro, a sanitized workflow snippet, or exact redacted steps a maintainer can follow
- type: checkboxes
id: checks
attributes:
label: Pre-flight checks
options:
- label: I searched existing issues and did not find a duplicate
required: true
- label: I reproduced this with the latest released version or current `master`
required: true
- label: I included a reproducible example or a sanitized/redacted reproduction path if the original repository is private
required: true
- type: input
id: action_version
attributes:
label: action-gh-release version
description: Tag, SHA, or ref used in your workflow
placeholder: v2.5.2
validations:
required: true
- type: dropdown
id: runner
attributes:
label: Runner operating system
options:
- ubuntu-latest
- windows-latest
- macos-latest
- other
validations:
required: true
- type: input
id: target_repository
attributes:
label: Release target repository
description: Fill this in if you set the `repository:` input
placeholder: owner/repo
- type: input
id: repro_reference
attributes:
label: Reproduction repo, gist, or artifact
description: Link a minimal repro repository, gist, run URL, or other shareable artifact if you have one
placeholder: https://github.com/owner/repro-repo
- type: textarea
id: workflow
attributes:
label: Workflow snippet
description: Include the relevant `uses:` step and inputs. If the original repo is private, paste a sanitized version here.
render: yaml
- type: textarea
id: expected
attributes:
label: Expected behavior
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual behavior
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: Include tags, matrix/concurrency details, and any repo rules involved. If the original repo is private, describe the smallest setup a maintainer can recreate locally or in a throwaway repo.
placeholder: |
1. Trigger workflow with ...
2. Action creates ...
3. Action fails with ...
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant logs
description: Paste the relevant error output or run URL
render: shell
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional context
description: Any extra environment, token, ruleset, or asset details
@@ -1,50 +0,0 @@
name: Feature request
description: Propose an enhancement or new capability for action-gh-release
title: "[Feature]: "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
Use this template for new capabilities, behavior changes, or ergonomics improvements.
If you are reporting something broken, use the bug report template instead.
- type: checkboxes
id: checks
attributes:
label: Pre-flight checks
options:
- label: I searched existing issues and did not find a duplicate request
required: true
- label: This is not a bug report for existing behavior
required: true
- type: textarea
id: problem
attributes:
label: Problem to solve
description: What workflow pain point or gap are you trying to address?
validations:
required: true
- type: textarea
id: proposal
attributes:
label: Proposed solution
description: Describe the behavior, input, or output you want
validations:
required: true
- type: textarea
id: workflow
attributes:
label: Example workflow snippet
description: Show how you would expect to use this
render: yaml
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: Workarounds or other approaches you evaluated
- type: textarea
id: impact
attributes:
label: Why this belongs in action-gh-release
description: Explain the user impact or why this should live in the action rather than in workflow glue
-29
View File
@@ -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)"
-22
View File
@@ -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:
- "*"
+14 -20
View File
@@ -1,32 +1,26 @@
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@master
with: with:
node-version-file: ".tool-versions" fetch-depth: 1
cache: "npm"
- name: Install - name: Install
run: npm ci run: npm ci
- name: Build - name: Build
run: npm run build run: npm run build
- name: Test - name: Test
run: npm run test run: npm run test
- name: Format - name: "check for uncommitted changes"
run: npm run fmtcheck # Ensure no changes, but ignore node_modules dir since dev/fresh ci deps installed.
# - name: "check for uncommitted changes" run: |
# # Ensure no changes, but ignore node_modules dir since dev/fresh ci deps installed. git diff --exit-code --stat -- . ':!node_modules' \
# run: | || (echo "##[error] found changed files after build. please 'npm run build && npm run format'" \
# git diff --exit-code --stat -- . ':!node_modules' \ "and check in all changes" \
# || (echo "##[error] found changed files after build. please 'npm run build && npm run fmt'" \ && exit 1)
# "and check in all changes" \
# && exit 1)
-3
View File
@@ -1,5 +1,2 @@
__tests__/runner/* __tests__/runner/*
# 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
coverage
-16
View File
@@ -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
-11
View File
@@ -1,11 +0,0 @@
/**
* @type {import('prettier').Config}
*/
module.exports = {
trailingComma: 'all',
tabWidth: 2,
semi: true,
singleQuote: true,
printWidth: 100,
bracketSpacing: true,
};
-1
View File
@@ -1 +0,0 @@
nodejs 24.11.0
+4 -346
View File
@@ -1,351 +1,9 @@
## 2.5.2 ## 0.1.0
`2.5.2` is a patch release focused on the remaining release-creation and prerelease regressions in the `2.5.x` bug-fix cycle. * Initial release
It fixes `#705`, fixes `#708`, fixes `#740`, fixes `#741`, and fixes `#722`.
Regression testing covers the shared-tag race, prerelease event behavior, dotfile asset labels,
same-filename concurrent uploads, and blocked-tag cleanup behavior.
If you still hit an issue after upgrading, please open a report with the bug template and include a minimal repro or sanitized workflow snippet where possible.
## What's Changed
### Bug fixes 🐛
* fix: canonicalize releases after concurrent create by @chenrui333 in https://github.com/softprops/action-gh-release/pull/746
* fix: preserve prereleased events for prereleases by @chenrui333 in https://github.com/softprops/action-gh-release/pull/748
* fix: restore dotfile asset labels by @chenrui333 in https://github.com/softprops/action-gh-release/pull/749
* fix: handle upload already_exists races across workflows by @api2062 in https://github.com/softprops/action-gh-release/pull/745
* fix: clean up orphan drafts when tag creation is blocked by @chenrui333 in https://github.com/softprops/action-gh-release/pull/750
## 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
- fixed error message formatting for file uploads
## 0.1.9
- add support for linking release to GitHub discussion [#136](https://github.com/softprops/action-gh-release/pull/136)
## 0.1.8
- address recent warnings in assert upload api as well as introduce asset upload overrides, allowing for multiple runs for the same release with the same named asserts [#134](https://github.com/softprops/action-gh-release/pull/134)
- fix backwards compatibility with `GITHUB_TOKEN` resolution. `GITHUB_TOKEN` is now resolved first from an env variable and then from an input [#133](https://github.com/softprops/action-gh-release/pull/133)
- trim white space in provided `tag_name` [#130](https://github.com/softprops/action-gh-release/pull/130)
## 0.1.7
- allow creating draft releases without a tag [#95](https://github.com/softprops/action-gh-release/pull/95)
- Set default token for simpler setup [#83](https://github.com/softprops/action-gh-release/pull/83)
- fix regression with action yml [#126](https://github.com/softprops/action-gh-release/pull/126)
## 0.1.6
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 `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 `upload_url` as action output, useful for managing uploads separately [#75](https://github.com/softprops/action-gh-release/pull/75)
- Support custom `target_commitish` value, useful to customize the default [#76](https://github.com/softprops/action-gh-release/pull/76)
- fix `body_path` input first then fall back on `body` input. This was the originally documented precedence but was implemented in the opposite order! [#85](https://github.com/softprops/action-gh-release/pull/85)
- Retain original release info if the keys are not set, useful for filling in blanks for a release you've already started separately [#109](https://github.com/softprops/action-gh-release/pull/109)
- Limit number of times github api request to create a release is retried, useful for avoiding eating up your rate limit and action minutes due to either an invalid token or other circumstance causing the api call to fail [#111](https://github.com/softprops/action-gh-release/pull/111)
## 0.1.5
- Added support for specifying tag name [#39](https://github.com/softprops/action-gh-release/pull/39)
## 0.1.4
- Added support for updating releases body [#36](https://github.com/softprops/action-gh-release/pull/36)
- Steps can now access the url of releases with the `url` output of this Action [#28](https://github.com/softprops/action-gh-release/pull/28)
- Added basic GitHub API retry support to manage API turbulence [#26](https://github.com/softprops/action-gh-release/pull/26)
## 0.1.3
- Fixed where `with: body_path` was not being used in generated GitHub releases
## 0.1.2
- Add support for merging draft releases [#16](https://github.com/softprops/action-gh-release/pull/16)
GitHub's api doesn't explicitly have a way of fetching a draft release by tag name which caused draft releases to appear as separate releases when used in a build matrix.
This is now fixed.
- Add support for newline-delimited asset list [#18](https://github.com/softprops/action-gh-release/pull/18)
GitHub actions inputs don't inherently support lists of things and one might like to append a list of files to include in a release. Previously this was possible using a comma-delimited list of asset path patterns to upload. You can now provide these as a newline delimited list for better readability
```yaml
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
filea.txt
fileb.txt
filec.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
- Add support for prerelease annotated GitHub releases with the new input field `with.prerelease: true` [#19](https://github.com/softprops/action-gh-release/pull/19)
---
## 0.1.1 ## 0.1.1
- Add support for publishing releases on all supported virtual hosts * Add support for publishing releases on all supported virtual hosts
You'll need to remove `docker://` prefix and use the `@v1` action tag You'll need to remove `docker://` prefix and use the `@v1` action tag
---
## 0.1.0
- Initial release
+5 -4
View File
@@ -1,12 +1,12 @@
## bootstrapping ## bootstrapping
This a [JavaScript](https://help.github.com/en/articles/about-actions#types-of-actions) action but uses [TypeScript](https://www.typescriptlang.org/docs/home.html) to generate that JavaScript. This a [JavaScript](https://help.github.com/en/articles/about-actions#types-of-actions) action but uses [TypeScript](https://www.typescriptlang.org/docs/home.html) to generate that JavaScript.
You can bootstrap your environment with a modern version of npm and by running `npm i` at the root of this repo. You can bootstrap your envrinment with a modern version of npm and by running `npm i` at the root of this repo.
## testing ## testing
Tests can be found under under `__tests__` directory and are runnable with the `npm t` command. Tests can be found under under `__tests__` directory and are runnable with the `npm t` command
## source code ## source code
@@ -14,4 +14,5 @@ Source code can be found under the `src` directory. Running `npm run build` will
## formatting ## formatting
A minimal attempt at keeping a consistent code style is can be applied by running `npm run fmt`. A minimal attempt at keeping a consistent code style is can be applied by running `npm run fmt`
+1 -1
View File
@@ -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
+42 -147
View File
@@ -1,35 +1,11 @@
<div align="center">
📦 :octocat:
</div>
<h1 align="center">
action gh-release
</h1>
<p align="center"> # action gh-release [![](https://github.com/softprops/action-gh-release/workflows/Main/badge.svg)](https://github.com/softprops/action-gh-release/actions)
A GitHub Action for creating GitHub Releases on Linux, Windows, and macOS virtual environments
</p>
<div align="center"> > A GitHub Action for creating GitHub Releases on Linux, Windows, and OSX virtual environments
<img src="demo.png"/>
</div>
<div align="center"> > **⚠️ Note:** To use this action, you must have access to the [GitHub Actions](https://github.com/features/actions) feature. GitHub Actions are currently only available in public beta. You can [apply for the GitHub Actions beta here](https://github.com/features/actions/signup/).
<a href="https://github.com/softprops/action-gh-release/actions">
<img src="https://github.com/softprops/action-gh-release/workflows/Main/badge.svg"/>
</a>
</div>
<br /> > **⚠️ 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
- [🤸 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
@@ -37,7 +13,7 @@
Typically usage of this action involves adding a step to a build that Typically usage of this action involves adding a step to a build that
is gated pushes to git tags. You may find `step.if` field helpful in accomplishing this is gated pushes to git tags. You may find `step.if` field helpful in accomplishing this
as it maximizes the reuse value of your workflow for non-tag pushes. as it maximizes the resuse value of your workflow for non-tag pushes.
Below is a simple example of `step.if` tag gating Below is a simple example of `step.if` tag gating
@@ -51,10 +27,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@master
- 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/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
``` ```
You can also use push config tag filter You can also use push config tag filter
@@ -65,27 +43,29 @@ name: Main
on: on:
push: push:
tags: tags:
- "v*.*.*" - 'v*.*.*'
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@master
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
``` ```
### ⬆️ Uploading release assets ### ⬆️ Uploading release assets
You can configure a number of options for your You can can configure a number of options for your
GitHub release and all are optional. 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 comma-separated 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,48 +79,20 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@master
- 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
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
``` ```
Below is an example of uploading more than one asset with a GitHub release
```yaml
name: Main
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Build
run: echo ${{ github.sha }} > Release.txt
- name: Test
run: cat Release.txt
- name: Release
uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
with:
files: |
Release.txt
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 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
Many systems exist that can help generate release notes for you. This action supports Many systems exist that can help generate release notes for you. This action supports
@@ -157,18 +109,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@master
- name: Generate Changelog - name: Generate Changelog
run: echo "# Good things have arrived" > ${{ github.workspace }}-CHANGELOG.txt run: echo "# Good things have arrived" > ${{ github.workflow }}-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.workflow }}-CHANGELOG.txt
repository: my_gh_org/my_gh_repo env:
# note you'll typically need to create a personal access token GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with permissions to create releases in the other repo
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
``` ```
### 💅 Customizing ### 💅 Customizing
@@ -177,77 +127,22 @@ 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 | | `files` | String | Comma-delimited globs of paths to assets to upload for release |
| `preserve_order` | Boolean | Indicator of whether order of files should be preserved when uploading assets | | `name` | String | Name of the release. defaults to tag name |
| `files` | String | Newline-delimited globs of paths to assets to upload for release |
| `overwrite_files` | Boolean | Indicator of whether files should be overwritten when they already exist. Defaults to true |
| `name` | String | Name of the release. defaults to tag name |
| `tag_name` | String | Name of a tag. defaults to `github.ref_name` |
| `fail_on_unmatched_files` | Boolean | Indicator of whether to fail if any of the `files` globs match nothing |
| `repository` | String | Name of a target repository in `<owner>/<repo>` format. Defaults to GITHUB_REPOSITORY env variable |
| `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. |
| `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.
💡 When the release info keys (such as `name`, `body`, `draft`, `prerelease`, etc.)
are not explicitly set and there is already an existing release for the tag, the
release will retain its original info.
#### outputs
The following outputs can be accessed via `${{ steps.<step-id>.outputs }}` from this action
| Name | Type | Description |
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url` | String | Github.com URL for the release |
| `id` | String | Release ID |
| `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
The following `step.env` keys are allowed as a fallback but deprecated in favor of using inputs. The following are *required* as `step.env` keys
| Name | Description | | Name | Description |
| ------------------- | ------------------------------------------------------------------------------------------ | |----------------|--------------------------------------|
| `GITHUB_TOKEN` | GITHUB_TOKEN as provided by `secrets` | | `GITHUB_TOKEN` | GITHUB_TOKEN as provided by `secrets`|
| `GITHUB_REPOSITORY` | Name of a target repository in `<owner>/<repo>` format. defaults to the current repository |
> **⚠️ 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 -723
View File
@@ -1,732 +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,
upload,
} from '../src/github';
import { mkdtempSync, rmSync, writeFileSync } from 'fs'; describe("github", () => {
import { tmpdir } from 'os'; describe("mimeOrDefault", () => {
import { join } from 'path'; it("returns a specific mime for common path", async () => {
import { assert, describe, expect, it, vi } from 'vitest'; assert.equal(mimeOrDefault("foo.tar.gz"), "application/gzip");
describe('github', () => {
const config = {
github_token: 'test-token',
github_ref: 'refs/tags/v1.0.0',
github_repository: 'owner/repo',
input_tag_name: undefined,
input_name: undefined,
input_body: undefined,
input_body_path: undefined,
input_files: [],
input_draft: undefined,
input_prerelease: undefined,
input_preserve_order: undefined,
input_overwrite_files: undefined,
input_fail_on_unmatched_files: false,
input_target_commitish: undefined,
input_discussion_category_name: undefined,
input_generate_release_notes: false,
input_append_body: false,
input_make_latest: undefined,
};
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, file } = 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(file.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'),
deleteRelease: () => Promise.reject('Not implemented'),
updateReleaseAsset: () => 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,
};
const publishedPrerelease: Release = {
...draftRelease,
draft: false,
prerelease: true,
};
it.each([
{
name: 'returns early when input_draft is true',
input_draft: true,
release: draftRelease,
expectedCalls: 0,
expectedResult: draftRelease,
},
{
name: 'finalizes release when input_draft is false',
input_draft: false,
release: draftRelease,
expectedCalls: 1,
expectedResult: finalizedRelease,
},
{
name: 'returns early when release is already published',
input_draft: false,
release: publishedPrerelease,
expectedCalls: 0,
expectedResult: publishedPrerelease,
},
])('$name', async ({ input_draft, release, 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'),
deleteRelease: () => Promise.reject('Not implemented'),
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
};
const result = await finalizeRelease(
{
...config,
input_draft,
},
releaser,
release,
);
expect(finalizeReleaseSpy).toHaveBeenCalledTimes(expectedCalls);
assert.strictEqual(result, expectedResult);
if (expectedCalls === 1) {
expect(finalizeReleaseSpy).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
release_id: release.id,
});
}
});
it('deletes a newly created draft when tag creation is blocked by repository rules', async () => {
const finalizeReleaseSpy = vi.fn(async () => {
throw {
status: 422,
response: {
data: {
errors: [
{
field: 'pre_receive',
message:
'pre_receive Repository rule violations found\n\nCannot create ref due to creations being restricted.\n\n',
},
],
},
},
};
});
const deleteReleaseSpy = vi.fn(async () => undefined);
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'),
deleteRelease: deleteReleaseSpy,
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
};
await expect(
finalizeRelease(
{
...config,
input_draft: false,
},
releaser,
draftRelease,
true,
),
).rejects.toThrow(
'Tag creation for v1.0.0 is blocked by repository rules. Deleted draft release 1 to avoid leaving an orphaned draft release.',
);
expect(finalizeReleaseSpy).toHaveBeenCalledTimes(1);
expect(deleteReleaseSpy).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
release_id: draftRelease.id,
});
});
it('does not delete an existing draft release when tag creation is blocked by repository rules', async () => {
const finalizeReleaseSpy = vi.fn(async () => {
throw {
status: 422,
response: {
data: {
errors: [
{
field: 'pre_receive',
message:
'pre_receive Repository rule violations found\n\nCannot create ref due to creations being restricted.\n\n',
},
],
},
},
};
});
const deleteReleaseSpy = vi.fn(async () => undefined);
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'),
deleteRelease: deleteReleaseSpy,
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
};
await expect(
finalizeRelease(
{
...config,
input_draft: false,
},
releaser,
draftRelease,
false,
1,
),
).rejects.toThrow('Too many retries.');
expect(finalizeReleaseSpy).toHaveBeenCalledTimes(1);
expect(deleteReleaseSpy).not.toHaveBeenCalled();
});
});
describe('error handling', () => {
it('creates published prereleases without the forced draft-first path', async () => {
const prereleaseConfig = {
...config,
input_prerelease: true,
input_draft: false,
};
const createdRelease: Release = {
id: 1,
upload_url: 'test',
html_url: 'test',
tag_name: 'v1.0.0',
name: 'test',
body: 'test',
target_commitish: 'main',
draft: false,
prerelease: true,
assets: [],
};
const createReleaseSpy = vi.fn(async () => ({ data: createdRelease }));
const mockReleaser: Releaser = {
getReleaseByTag: () => Promise.reject({ status: 404 }),
createRelease: createReleaseSpy,
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
yield { data: [createdRelease] };
},
listReleaseAssets: () => Promise.reject('Not implemented'),
deleteReleaseAsset: () => Promise.reject('Not implemented'),
deleteRelease: () => Promise.reject('Not implemented'),
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
} as const;
const result = await release(prereleaseConfig, mockReleaser, 1);
assert.equal(result.release.id, createdRelease.id);
assert.equal(result.created, true);
expect(createReleaseSpy).toHaveBeenCalledWith(
expect.objectContaining({
draft: false,
prerelease: true,
}),
);
});
it('retries upload after deleting conflicting asset on 422 already_exists race', async () => {
const uploadReleaseAsset = vi
.fn()
.mockRejectedValueOnce({
status: 422,
response: { data: { errors: [{ code: 'already_exists' }] } },
})
.mockResolvedValueOnce({
status: 201,
data: { id: 123, name: 'release.txt' },
});
const listReleaseAssets = vi.fn().mockResolvedValue([{ id: 99, name: 'release.txt' }]);
const deleteReleaseAsset = vi.fn().mockResolvedValue(undefined);
const mockReleaser: Releaser = {
getReleaseByTag: () => Promise.reject('Not implemented'),
createRelease: () => Promise.reject('Not implemented'),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
throw new Error('Not implemented');
},
listReleaseAssets,
deleteReleaseAsset,
uploadReleaseAsset,
};
const result = await upload(
config,
mockReleaser,
'https://uploads.github.com/repos/owner/repo/releases/1/assets',
'__tests__/release.txt',
[],
);
expect(result).toStrictEqual({ id: 123, name: 'release.txt' });
expect(listReleaseAssets).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
release_id: 1,
});
expect(deleteReleaseAsset).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
asset_id: 99,
});
expect(uploadReleaseAsset).toHaveBeenCalledTimes(2);
});
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'),
deleteRelease: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
} as const;
const result = await release(config, mockReleaser, 2);
assert.ok(result);
assert.equal(result.release.id, 1);
assert.equal(result.created, false);
});
it('reuses a canonical release after concurrent create success and removes empty duplicates', async () => {
const canonicalRelease: Release = {
id: 1,
upload_url: 'canonical-upload',
html_url: 'canonical-html',
tag_name: 'v1.0.0',
name: 'canonical',
body: 'test',
target_commitish: 'main',
draft: true,
prerelease: false,
assets: [],
};
const duplicateRelease: Release = {
id: 2,
upload_url: 'duplicate-upload',
html_url: 'duplicate-html',
tag_name: 'v1.0.0',
name: 'duplicate',
body: 'test',
target_commitish: 'main',
draft: true,
prerelease: false,
assets: [],
};
let lookupCount = 0;
const deleteReleaseSpy = vi.fn(async () => undefined);
const mockReleaser: Releaser = {
getReleaseByTag: () => {
lookupCount += 1;
if (lookupCount === 1) {
return Promise.reject({ status: 404 });
}
return Promise.resolve({ data: canonicalRelease });
},
createRelease: () => Promise.resolve({ data: duplicateRelease }),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
yield { data: [duplicateRelease, canonicalRelease] };
},
listReleaseAssets: () => Promise.reject('Not implemented'),
deleteReleaseAsset: () => Promise.reject('Not implemented'),
deleteRelease: deleteReleaseSpy,
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
};
const result = await release(config, mockReleaser, 2);
assert.equal(result.release.id, canonicalRelease.id);
assert.equal(result.created, false);
expect(deleteReleaseSpy).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
release_id: duplicateRelease.id,
});
});
it('falls back to recent releases when tag lookup still lags after create', async () => {
const canonicalRelease: Release = {
id: 1,
upload_url: 'canonical-upload',
html_url: 'canonical-html',
tag_name: 'v1.0.0',
name: 'canonical',
body: 'test',
target_commitish: 'main',
draft: true,
prerelease: false,
assets: [],
};
const duplicateRelease: Release = {
id: 2,
upload_url: 'duplicate-upload',
html_url: 'duplicate-html',
tag_name: 'v1.0.0',
name: 'duplicate',
body: 'test',
target_commitish: 'main',
draft: true,
prerelease: false,
assets: [],
};
const deleteReleaseSpy = vi.fn(async () => undefined);
const mockReleaser: Releaser = {
getReleaseByTag: () => Promise.reject({ status: 404 }),
createRelease: () => Promise.resolve({ data: duplicateRelease }),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
yield { data: [duplicateRelease, canonicalRelease] };
},
listReleaseAssets: () => Promise.reject('Not implemented'),
deleteReleaseAsset: () => Promise.reject('Not implemented'),
deleteRelease: deleteReleaseSpy,
updateReleaseAsset: () => Promise.reject('Not implemented'),
uploadReleaseAsset: () => Promise.reject('Not implemented'),
};
const result = await release(config, mockReleaser, 1);
assert.equal(result.release.id, canonicalRelease.id);
assert.equal(result.created, false);
expect(deleteReleaseSpy).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
release_id: duplicateRelease.id,
});
});
});
describe('upload', () => {
it('restores a dotfile label when GitHub normalizes the uploaded asset name', async () => {
const tempDir = mkdtempSync(join(tmpdir(), 'gh-release-dotfile-'));
const dotfilePath = join(tempDir, '.config');
writeFileSync(dotfilePath, 'config');
const updateReleaseAssetSpy = vi.fn(async () => ({
data: {
id: 1,
name: 'default.config',
label: '.config',
},
}));
const releaser: Releaser = {
getReleaseByTag: () => Promise.reject('Not implemented'),
createRelease: () => Promise.reject('Not implemented'),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
throw new Error('Not implemented');
},
listReleaseAssets: () => Promise.reject('Not implemented'),
deleteReleaseAsset: () => Promise.reject('Not implemented'),
deleteRelease: () => Promise.reject('Not implemented'),
updateReleaseAsset: updateReleaseAssetSpy,
uploadReleaseAsset: () =>
Promise.resolve({
status: 201,
data: {
id: 1,
name: 'default.config',
label: '',
},
}),
};
try {
const result = await upload(
config,
releaser,
'https://uploads.example.test/assets',
dotfilePath,
[],
);
expect(updateReleaseAssetSpy).toHaveBeenCalledWith({
owner: 'owner',
repo: 'repo',
asset_id: 1,
name: 'default.config',
label: '.config',
});
expect(result).toEqual({
id: 1,
name: 'default.config',
label: '.config',
});
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
});
it('matches an existing asset by label when overwriting a dotfile', async () => {
const tempDir = mkdtempSync(join(tmpdir(), 'gh-release-dotfile-'));
const dotfilePath = join(tempDir, '.config');
writeFileSync(dotfilePath, 'config');
const deleteReleaseAssetSpy = vi.fn(async () => undefined);
const releaser: Releaser = {
getReleaseByTag: () => Promise.reject('Not implemented'),
createRelease: () => Promise.reject('Not implemented'),
updateRelease: () => Promise.reject('Not implemented'),
finalizeRelease: () => Promise.reject('Not implemented'),
allReleases: async function* () {
throw new Error('Not implemented');
},
listReleaseAssets: () => Promise.reject('Not implemented'),
deleteReleaseAsset: deleteReleaseAssetSpy,
deleteRelease: () => Promise.reject('Not implemented'),
updateReleaseAsset: () =>
Promise.resolve({
data: {
id: 2,
name: 'default.config',
label: '.config',
},
}),
uploadReleaseAsset: () =>
Promise.resolve({
status: 201,
data: {
id: 2,
name: 'default.config',
label: '',
},
}),
};
try {
await upload(config, releaser, 'https://uploads.example.test/assets', dotfilePath, [
{
id: 1,
name: 'default.config',
label: '.config',
},
]);
expect(deleteReleaseAssetSpy).toHaveBeenCalledWith({
asset_id: 1,
owner: 'owner',
repo: 'repo',
});
} finally {
rmSync(tempDir, { recursive: true, force: true });
}
}); });
}); });
}); });
-1
View File
@@ -1 +0,0 @@
bar
+14 -518
View File
@@ -1,525 +1,21 @@
import { import { isTag, paths } from "../src/util";
alignAssetName, import * as assert from "assert";
isTag,
parseConfig,
parseInputFiles,
paths,
releaseBody,
unmatchedPatterns,
uploadUrl,
} from '../src/util';
import { assert, describe, expect, it } from 'vitest'; describe("util", () => {
describe("isTag", () => {
describe('util', () => { it("returns true for tags", async () => {
describe('uploadUrl', () => { assert.equal(isTag("refs/tags/foo"), true);
it('strips template', () => { });
assert.equal( it("returns false for other kinds of refs", async () => {
uploadUrl( assert.equal(isTag("refs/heads/master"), false);
'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}',
),
'https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets',
);
}); });
}); });
describe('parseInputFiles', () => {
it('parses empty strings', () => { describe("paths", () => {
assert.deepStrictEqual(parseInputFiles(''), []); it("resolves files given a set of paths", async () => {
}); assert.deepStrictEqual(paths(["tests/data/**/*"]), [
it('parses comma-delimited strings', () => { "tests/data/foo/bar.txt"
assert.deepStrictEqual(parseInputFiles('foo,bar'), ['foo', 'bar']);
});
it('parses newline and comma-delimited (and then some)', () => {
assert.deepStrictEqual(parseInputFiles('foo,bar\nbaz,boom,\n\ndoom,loom '), [
'foo',
'bar',
'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', () => {
it('parses basic config', () => {
assert.deepStrictEqual(
parseConfig({
// note: inputs declared in actions.yml, even when declared not required,
// 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_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: false,
input_make_latest: undefined,
},
);
});
it('parses basic config with commitish', () => {
assert.deepStrictEqual(
parseConfig({
INPUT_TARGET_COMMITISH: 'affa18ef97bc9db20076945705aba8c516139abd',
}),
{
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_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_path: undefined,
input_draft: false,
input_prerelease: true,
input_preserve_order: true,
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,
},
);
});
it('uses input token as the source of GITHUB_TOKEN by default', () => {
assert.deepStrictEqual(
parseConfig({
INPUT_DRAFT: 'false',
INPUT_PRERELEASE: 'true',
INPUT_TOKEN: 'input-token',
}),
{
github_ref: '',
github_repository: '',
github_token: 'input-token',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
input_draft: false,
input_prerelease: true,
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,
},
);
});
it('parses basic config with draft and prerelease', () => {
assert.deepStrictEqual(
parseConfig({
INPUT_DRAFT: 'false',
INPUT_PRERELEASE: 'true',
}),
{
github_ref: '',
github_repository: '',
github_token: '',
input_working_directory: undefined,
input_append_body: false,
input_body: undefined,
input_body_path: undefined,
input_draft: false,
input_prerelease: true,
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,
},
);
});
it('parses basic config where make_latest is passed', () => {
assert.deepStrictEqual(
parseConfig({
INPUT_MAKE_LATEST: 'false',
}),
{
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', () => {
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 () => {
assert.deepStrictEqual(
unmatchedPatterns(['tests/data/**/*', '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',
]);
}); });
}); });
+14 -64
View File
@@ -1,78 +1,28 @@
# https://help.github.com/en/articles/metadata-syntax-for-github-actions # https://help.github.com/en/articles/metadata-syntax-for-github-actions
name: "GH Release" name: 'GH Release'
description: "Github Action for creating Github Releases" description: 'Github Action for creating Github Releases'
author: "softprops" author: 'softprops'
inputs: inputs:
body: body:
description: "Note-worthy description of changes in release" description: 'Note-worthy description of changes in release'
required: false required: false
body_path: body-path:
description: "Path to load note-worthy description of changes in release from" description: 'Path to load note-worthy description of changes in release from'
required: false required: false
name: name:
description: "Gives the release a custom name. Defaults to tag name" description: 'Gives the release a custom name. Defaults to tag name'
required: false
tag_name:
description: "Gives a tag name. Defaults to github.ref_name"
required: false required: false
draft: draft:
description: "Creates a draft release. Defaults to false" description: 'Creates a draft release'
required: false
prerelease:
description: "Identify the release as a prerelease. Defaults to false"
required: false
preserve_order:
description: "Preserver the order of the artifacts when uploading"
required: false required: false
files: files:
description: "Newline-delimited list of path globs for asset files to upload" description: 'Comma-delimited list of path globs for asset files to upload'
required: false
working_directory:
description: "Base directory to resolve 'files' globs against (defaults to job working-directory)"
required: false
overwrite_files:
description: "Overwrite existing files with the same name. Defaults to true"
required: false
default: 'true'
fail_on_unmatched_files:
description: "Fails if any of the `files` globs match nothing. Defaults to false"
required: false
repository:
description: "Repository to make releases against, in <owner>/<repo> format"
required: false
token:
description: "Authorized secret GitHub Personal Access Token. Defaults to github.token"
required: false
default: ${{ github.token }}
target_commitish:
description: "Commitish value that determines where the Git tag is created from. Can be any branch or commit SHA."
required: false
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."
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 required: false
env: env:
GITHUB_TOKEN: "As provided by Github Actions" 'GITHUB_TOKEN': 'As provided by Github Actions'
outputs:
url:
description: "URL to the Release HTML Page"
id:
description: "Release ID"
upload_url:
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: 'lib/main.js'
branding: branding:
color: "green" color: 'green'
icon: "package" icon: 'package'
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

-90
View File
@@ -1,90 +0,0 @@
"use strict";var Rw=Object.create;var pp=Object.defineProperty;var Tw=Object.getOwnPropertyDescriptor;var Fw=Object.getOwnPropertyNames;var Sw=Object.getPrototypeOf,Uw=Object.prototype.hasOwnProperty;var Q=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Nw=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Fw(t))!Uw.call(e,i)&&i!==s&&pp(e,i,{get:()=>t[i],enumerable:!(r=Tw(t,i))||r.enumerable});return e};var de=(e,t,s)=>(s=e!=null?Rw(Sw(e)):{},Nw(t||!e||!e.__esModule?pp(s,"default",{value:e,enumerable:!0}):s,e));var Ip=Q(Zs=>{"use strict";var V_=require("net"),_w=require("tls"),$a=require("http"),Qp=require("https"),Yw=require("events"),q_=require("assert"),Ow=require("util");Zs.httpOverHttp=Jw;Zs.httpsOverHttp=Pw;Zs.httpOverHttps=Hw;Zs.httpsOverHttps=Vw;function Jw(e){var t=new Rt(e);return t.request=$a.request,t}function Pw(e){var t=new Rt(e);return t.request=$a.request,t.createSocket=Bp,t.defaultPort=443,t}function Hw(e){var t=new Rt(e);return t.request=Qp.request,t}function Vw(e){var t=new Rt(e);return t.request=Qp.request,t.createSocket=Bp,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=Cp(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)})}Ow.inherits(Rt,Yw.EventEmitter);Rt.prototype.addRequest=function(t,s,r,i){var o=this,n=eA({request:t},o.options,Cp(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
`,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 Bp(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=_w.connect(0,o);s.sockets[s.sockets.indexOf(r)]=n,t(n)})}function Cp(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((j_,wp)=>{wp.exports=Ip()});var j=Q((z_,bp)=>{bp.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((Z_,zp)=>{"use strict";var yp=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[yp]===!0}[yp]=!0},xp=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[xp]===!0}[xp]=!0},vp=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[vp]===!0}[vp]=!0},kp=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[kp]===!0}[kp]=!0},Dp=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[Dp]===!0}[Dp]=!0},Rp=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 ax(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(Vy.has(n)){i=n;break}}i!==""&&(e.referrerPolicy=i)}function Ax(){return"allowed"}function cx(){return"success"}function lx(){return"success"}function ux(e){let t=null;t=e.mode,e.headersList.set("sec-fetch-mode",t,!0)}function px(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 gx(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 hx(e){return nr(Zy.now(),e)}function dx(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 ch(){return{referrerPolicy:"strict-origin-when-cross-origin"}}function Ex(e){return{referrerPolicy:e.referrerPolicy}}function mx(e){let t=e.referrerPolicy;ws(t);let s=null;if(e.referrer==="client"){let a=rh();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 fx(e,t){if(_o===void 0)return!0;let s=lh(t);if(s==="no metadata"||s.length===0)return!0;let r=Bx(s),i=Cx(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)),Ix(A,a))return!0}return!1}var Qx=/(?<algo>sha256|sha384|sha512)-((?<hash>[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i;function lh(e){let t=[],s=!0;for(let r of e.split(" ")){s=!1;let i=Qx.exec(r);if(i===null||i.groups===void 0||i.groups.algo===void 0)continue;let o=i.groups.algo.toLowerCase();oh.includes(o)&&t.push(i.groups)}return s===!0?"no metadata":t}function Bx(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 Cx(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 Ix(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 wx(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 bx(){let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}}function yx(e){return e.controller.state==="aborted"}function xx(e){return e.controller.state==="aborted"||e.controller.state==="terminated"}function vx(e){return $y[e.toLowerCase()]??e}function kx(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 Dx=Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));function uh(e,t,s=0,r=1){class i{#e;#t;#i;constructor(n,a){this.#e=n, Line truncated
`);function ov(e){for(let t=0;t<e.length;++t)if((e.charCodeAt(t)&-128)!==0)return!1;return!0}function nv(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 av(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,rv,o)||o.position===e.length-4&&Po(e,iv,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",ov(u)||(u=""),g=new tv([p],c,{type:u})):g=Zx(Buffer.from(p)),Jo(wh(A)),Jo(typeof g=="string"&&wh(g)||Xx(g)),i.push($x(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),!Kx.test(n.toString())||e[t.position]!==58)return"failure";switch(t.position++,Ar(a=>a===32||a===9,e,t),zx(n)){case"content-disposition":{if(s=r=null,!Po(e,sv,t)||(t.position+=17,s=xh(e,t),s===null))return"failure";if(Po(e,yh,t)){let a=t.position+yh.length;if(e[a]===42&&(t.position+=1,a+=1),e[a]!==61||e[a+1]!==34||(t.position+=12,r=xh(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=bh(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=bh(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 xh(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}vh.exports={multipartFormDataParser:av,validateBoundary:nv}});var ur=Q((C2,Lh)=>{"use strict";var li=U(),{ReadableStreamFrom:cv,isBlobLike:Dh,isReadableStreamLike:lv,readableStreamClose:uv,createDeferredPromise:pv,fullyReadBody:gv,extractMimeType:hv,utf8DecodeBytes:Fh}=Ue(),{FormData:Rh}=ci(),{kState:lr}=Kt(),{webidl:dv}=ge(),{Blob:Ev}=require("node:buffer"),oc=require("node:assert"),{isErrored:Sh,isDisturbed:mv}=require("node:stream"),{isArrayBuffer:fv}=require("node:util/types"),{serializeAMimeType:Qv}=ve(),{multipartFormDataParser:Bv}=kh(),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 Cv(){}var Uh=globalThis.FinalizationRegistry&&process.version.indexOf("v18")!==0,Nh;Uh&&(Nh=new FinalizationRegistry(e=>{let t=e.deref();t&&!t.locked&&!mv(t)&&!Sh(t)&&t.cancel("Response object has been garbage collected").catch(Cv)}));function Gh(e,t=!1){let s=null;e instanceof ReadableStream?s=e:Dh(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(()=>uv(A))},start(){},type:"bytes"}),oc(lv(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(fv(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,d]of e)if(typeof d=="string"){let f=Ho.encode(c+`; name="${u(l(m))}"\r
\r
${l(d)}\r
`);p.push(f),o+=f.byteLength}else{let f=Ho.encode(`${c}; name="${u(l(m))}"`+(d.name?`; filename="${u(d.name)}"`:"")+`\r
Content-Type: ${d.type||"application/octet-stream"}\r
\r
`);p.push(f,d,g),typeof d.size=="number"?o+=f.byteLength+d.size+g.byteLength:h=!0}let E=Ho.encode(`--${A}--\r
`);p.push(E),o+=E.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(Dh(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:cv(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(!Sh(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 Iv(e,t=!1){return e instanceof ReadableStream&&(oc(!li.isDisturbed(e),"The body has already been consumed."),oc(!e.locked,"The stream is locked.")),Gh(e,t)}function wv(e,t){let[s,r]=t.stream.tee();return t.stream=s,{stream:r,length:t.length,source:t.source}}function bv(e){if(e.aborted)throw new DOMException("The operation was aborted.","AbortError")}function yv(e){return{blob(){return cr(this,s=>{let r=Th(this);return r===null?r="":r&&(r=Qv(r)),new Ev([s],{type:r})},e)},arrayBuffer(){return cr(this,s=>new Uint8Array(s).buffer,e)},text(){return cr(this,Fh,e)},json(){return cr(this,vv,e)},formData(){return cr(this,s=>{let r=Th(this);if(r!==null)switch(r.essence){case"multipart/form-data":{let i=Bv(s,r);if(i==="failure")throw new TypeError("Failed to parse body as FormData.");let o=new Rh;return o[lr]=i,o}case"application/x-www-form-urlencoded":{let i=new URLSearchParams(s.toString()),o=new Rh;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 xv(e){Object.assign(e.prototype,yv(e))}async function cr(e,t,s){if(dv.brandCheck(e,s),Mh(e))throw new TypeError("Body is unusable: Body has already been read");bv(e[lr]);let r=pv(),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 gv(e[lr].body,o,i),r.promise)}function Mh(e){let t=e[lr].body;return t!=null&&(t.stream.locked||li.isDisturbed(t.stream))}function vv(e){return JSON.parse(Fh(e))}function Th(e){let t=e[lr].headersList,s=hv(t);return s==="failure"?null:s}Lh.exports={extractBody:Gh,safelyExtractBody:Iv,cloneBody:wv,mixinBody:xv,streamRegistry:Nh,hasFinalizationRegistry:Uh,bodyUnusable:Mh}});var zh=Q((I2,jh)=>{"use strict";var k=require("node:assert"),F=U(),{channels:_h}=Xs(),ac=JA(),{RequestContentLengthMismatchError:bs,ResponseContentLengthMismatchError:kv,RequestAbortedError:Vh,HeadersTimeoutError:Dv,HeadersOverflowError:Rv,SocketError:Zo,InformationalError:pr,BodyTimeoutError:Tv,HTTPParserError:Fv,ResponseExceededMaxSizeError:Sv}=L(),{kUrl:qh,kReset:ke,kClient:uc,kParser:X,kBlocking:gi,kRunning:Ee,kPending:Uv,kSize:Yh,kWriting:$t,kQueue:st,kNoRef:ui,kKeepAliveDefaultTimeout:Nv,kHostHeader:Gv,kPendingIdx:Mv,kRunningIdx:qe,kError:We,kPipelining:jo,kSocket:gr,kKeepAliveTimeoutValue:Ko,kMaxHeadersSize:Ac,kKeepAliveMaxTimeout:Lv,kKeepAliveTimeoutThreshold:_v,kHeadersTimeout:Yv,kBodyTimeout:Ov,kStrictContentLength:pc,kMaxRequests:Oh,kCounter:Jv,kMaxResponseSize:Pv,kOnError:Hv,kResume:Xt,kHTTPContext:Wh}=j(),ft=Ng(),Vv=Buffer.alloc(0),Vo=Buffer[Symbol.species],qo=F.addListener,qv=F.removeAllListeners,cc;async function Wv(){let e=process.env.JEST_WORKER_ID?VA():void 0,t;try{t=await WebAssembly.compile(Lg())}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=Wv();gc.catch();var oe=null,Qt=null,Wo=0,Bt=null,jv=0,pi=1,hr=2|pi,zo=4|pi,hc=8|jv,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"?E+=`host: ${i}\r
`:E+=e[Gv],o?E+=`connection: upgrade\r
upgrade: ${o}\r
`:e[jo]&&!g[ke]?E+=`connection: keep-alive\r
`:E+=`connection: close\r
`,Array.isArray(c))for(let m=0;m<c.length;m+=2){let d=c[m+0],f=c[m+1];if(Array.isArray(f))for(let C=0;C<f.length;C++)E+=`${d}: ${f[C]}\r
`;else E+=`${d}: ${f}\r
`}return _h.sendHeaders.hasSubscribers&&_h.sendHeaders.publish({request:t,headers:E,socket:g}),!A||p===0?Ph(h,null,e,t,g,u,E,l):F.isBuffer(A)?Ph(h,A,e,t,g,u,E,l):F.isBlobLike(A)?typeof A.stream=="function"?Hh(h,A.stream(),e,t,g,u,E,l):ek(h,A,e,t,g,u,E,l):F.isStream(A)?$v(h,A,e,t,g,u,E,l):F.isIterable(A)?Hh(h,A,e,t,g,u,E,l):k(!1),!0}function $v(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(E){F.destroy(this,E)}},l=function(){A||t.resume&&t.resume()},p=function(){if(queueMicrotask(()=>{t.removeListener("error",g)}),!A){let h=new Vh;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(E){h=E}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 Ph(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 ek(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 Hh(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))}};jh.exports=zv});var rd=Q((w2,sd)=>{"use strict";var je=require("node:assert"),{pipeline:tk}=require("node:stream"),N=U(),{RequestContentLengthMismatchError:Ec,RequestAbortedError:Zh,SocketError:hi,InformationalError:mc}=L(),{kUrl:$o,kReset:tn,kClient:dr,kRunning:sn,kPending:sk,kQueue:es,kPendingIdx:fc,kRunningIdx:rt,kError:ot,kSocket:ae,kStrictContentLength:rk,kOnError:Qc,kMaxConcurrentStreams:td,kHTTP2Session:it,kResume:ts,kSize:ik,kHTTPContext:ok}=j(),Gt=Symbol("open streams"),Kh,Xh=!1,en;try{en=require("node:http2")}catch{en={constants:{}}}var{constants:{HTTP2_HEADER_AUTHORITY:nk,HTTP2_HEADER_METHOD:ak,HTTP2_HEADER_PATH:Ak,HTTP2_HEADER_SCHEME:ck,HTTP2_HEADER_CONTENT_LENGTH:lk,HTTP2_HEADER_EXPECT:uk,HTTP2_HEADER_STATUS:pk}}=en;function gk(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 hk(e,t){e[ae]=t,Xh||(Xh=!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[td]});s[Gt]=0,s[dr]=e,s[ae]=t,N.addListener(s,"error",Ek),N.addListener(s,"frameError",mk),N.addListener(s,"end",fk),N.addListener(s,"goaway",Qk),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[sk]===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 Ck(e,...i)},resume(){dk(e)},destroy(i,o){r?queueMicrotask(o):t.destroy(i).on("close",o)},get destroyed(){return t.destroyed},busy(){return!1}}}function dk(e){let t=e[ae];t?.destroyed===!1&&(e[ik]===0&&e[td]===0?(t.unref(),e[it].unref()):(t.ref(),e[it].ref()))}function Ek(e){je(e.code!=="ERR_TLS_CERT_ALTNAME_INVALID"),this[ae][ot]=e,this[dr][Qc](e)}function mk(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 fk(){let e=new hi("other side closed",N.getSocketInfo(this[ae]));this.destroy(e),N.destroy(this[ae],e)}function Qk(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[ok]=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 Bk(e){return e!=="GET"&&e!=="HEAD"&&e!=="OPTIONS"&&e!=="TRACE"&&e!=="CONNECT"}function Ck(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 B=0;B<c.length;B+=2){let b=c[B+0],Y=c[B+1];if(Array.isArray(Y))for(let O=0;O<Y.length;O++)l[b]?l[b]+=`,${Y[O]}`:l[b]=Y[O];else l[b]=Y}let p,{hostname:g,port:h}=e[$o];l[nk]=o||`${g}${h?`:${h}`:""}`,l[ak]=r;let E=B=>{t.aborted||t.completed||(B=B||new Zh,N.errorRequest(e,t,B),p!=null&&N.destroy(p,B),N.destroy(u,B),e[es][e[rt]++]=null,e[ts]())};try{t.onConnect(E)}catch(B){N.errorRequest(e,t,B)}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[ck]="https";let m=r==="PUT"||r==="POST"||r==="PATCH";u&&typeof u.read=="function"&&u.read(0);let d=N.bodyLength(u);if(N.isFormDataLike(u)){Kh??=ur().extractBody;let[B,b]=Kh(u);l["content-type"]=b,u=B.stream,d=B.length}if(d==null&&(d=t.contentLength),(d===0||!m)&&(d=null),Bk(r)&&d>0&&t.contentLength!=null&&t.contentLength!==d){if(e[rk])return N.errorRequest(e,t,new Ec),!1;process.emitWarning(new Ec)}d!=null&&(je(u,"no body must not have content length"),l[lk]=`${d}`),s.ref();let f=r==="GET"||r==="HEAD"||u===null;return a?(l[uk]="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[Wk]=A??3e5,this[qk]=i??3e5,this[jk]=f??!0,this[zk]=B,this[wc]=Y,this[rs]=null,this[e0]=pe>-1?pe:-1,this[s0]=Wt??100,this[ee]=null,this[nt]=[],this[Lt]=0,this[at]=0,this[fi]=jt=>yc(this,jt),this[t0]=jt=>dd(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[_k](){return!!this[ee]&&!this[mr]&&!this[ee].destroyed}get[Ic](){return!!(this[ee]?.busy(null)||this[Qi]>=(hd(this)||1)||this[Ci]>0)}[Lk](t){Ed(this),this.once("connect",t)}[$k](t,s){let r=t.origin||this[It].origin,i=new Fk(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[Kk](){return new Promise(t=>{this[Qi]?this[rs]=t:t(null)})}async[Xk](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]()})}},o0=nn();function dd(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 Ed(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(gd.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",ud),new Nk);return}Mt(o);try{e[ee]=o.alpnProtocol==="h2"?await i0(e,o):await r0(e,o)}catch(n){throw o.destroy().on("error",ud),n}e[mr]=!1,o[Zk]=0,o[wc]=e[wc],o[Mk]=e,o[Ok]=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 dd(e,o);e.emit("connectionError",e[It],[e],o)}e[fi]()}function pd(e){e[is]=0,e.emit("drain",e[It],[e])}function yc(e,t){e[xs]!==2&&(e[xs]=2,n0(e,t),e[xs]=0,e[Lt]>256&&(e[nt].splice(0,e[Lt]),e[at]-=e[Lt],e[Lt]=0))}function n0(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(()=>pd(e))):pd(e);continue}if(e[Ci]===0||e[Bi]>=(hd(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 Uk("servername changed"),()=>{e[ee]=null,yc(e)})}if(e[mr])return;if(!e[ee]){Ed(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)}}md.exports=bc});var xc=Q((k2,fd)=>{"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)}};fd.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 Bd=Q((D2,Qd)=>{var{kFree:a0,kConnected:A0,kPending:c0,kQueued:l0,kRunning:u0,kSize:p0}=j(),vs=Symbol("pool"),vc=class{constructor(t){this[vs]=t}get connected(){return this[vs][A0]}get free(){return this[vs][a0]}get pending(){return this[vs][c0]}get queued(){return this[vs][l0]}get running(){return this[vs][u0]}get size(){return this[vs][p0]}};Qd.exports=vc});var Sc=Q((R2,Rd)=>{"use strict";var g0=sr(),h0=xc(),{kConnected:kc,kSize:Cd,kRunning:Id,kPending:wd,kQueued:Ii,kBusy:d0,kFree:E0,kUrl:m0,kClose:f0,kDestroy:Q0,kDispatch:B0}=j(),C0=Bd(),De=Symbol("clients"),Ce=Symbol("needDrain"),wi=Symbol("queue"),Dc=Symbol("closed resolve"),Rc=Symbol("onDrain"),bd=Symbol("onConnect"),yd=Symbol("onDisconnect"),xd=Symbol("onConnectionError"),Tc=Symbol("get dispatcher"),kd=Symbol("add client"),Dd=Sym Line truncated
${r.count} ${r.noun} ${r.is} pending:
${t.format(s)}
`.trim())}};Gm.exports=Sl});var xn=Q((iY,Om)=>{"use strict";var Lm=Symbol.for("undici.globalDispatcher.1"),{InvalidArgumentError:WR}=L(),jR=Br();Ym()===void 0&&_m(new jR);function _m(e){if(!e||typeof e.dispatch!="function")throw new WR("Argument agent must implement Agent");Object.defineProperty(globalThis,Lm,{value:e,writable:!0,enumerable:!1,configurable:!1})}function Ym(){return globalThis[Lm]}Om.exports={setGlobalDispatcher:_m,getGlobalDispatcher:Ym}});var vn=Q((nY,Jm)=>{"use strict";Jm.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 Hm=Q((aY,Pm)=>{"use strict";var zR=on();Pm.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 zR(s,n,i,o);return s(a,A)}}});var qm=Q((AY,Vm)=>{"use strict";var ZR=En();Vm.exports=e=>t=>function(r,i){return t(r,new ZR({...r,retryOptions:{...e,...r.retryOptions}},{handler:i,dispatch:t}))}});var jm=Q((cY,Wm)=>{"use strict";var KR=U(),{InvalidArgumentError:XR,RequestAbortedError:$R}=L(),eT=vn(),Ul=class extends eT{#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 XR("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=KR.parseHeaders(s)["content-length"];if(n!=null&&n>this.#e)throw new $R(`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 tT({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)}}Wm.exports=tT});var Km=Q((lY,Zm)=>{"use strict";var{isIP:sT}=require("node:net"),{lookup:rT}=require("node:dns"),iT=vn(),{InvalidArgumentError:Rr,InformationalError:oT}=L(),zm=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 oT("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){rT(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===zm?(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===zm?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 iT{#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":TB(o)&&(s[i]=o);break;case"id":FB(o)&&(s[i]=o);break;case"event":o.length>0&&(s[i]=o);break}}processEvent(t){t.retry&&TB(t.retry)&&(this.state.reconnectionTime=parseInt(t.retry,10)),t.id&&FB(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}}};SB.exports={EventSourceStream:Cu}});var JB=Q((OY,OB)=>{"use strict";var{pipeline:dN}=require("node:stream"),{fetching:EN}=Gi(),{makeRequest:mN}=Sr(),{webidl:Pt}=ge(),{EventSourceStream:fN}=UB(),{parseMIMEType:QN}=ve(),{createFastMessageEvent:BN}=_r(),{isNetworkError:NB}=Ui(),{delay:CN}=Qu(),{kEnumerableProperty:Js}=U(),{environmentSettingsObject:GB}=Ue(),MB=!1,LB=3e3,zi=0,_B=1,Zi=2,IN="anonymous",wN="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),MB||(MB=!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:LB};let i=GB,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=IN;s.withCredentials&&(n=wN,this.#i=!0);let a={redirect:"follow",keepalive:!0,mode:"cors",credentials:n==="anonymous"?"same-origin":"omit",referrer:"no-referrer"};a.client=GB.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=mN(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=>{NB(r)&&(this.dispatchEvent(new Event("error")),this.close()),this.#g()};t.processResponseEndOfBody=s,t.processResponse=r=>{if(NB(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?QN(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=_B,this.dispatchEvent(new Event("open")),this.#c.origin=r.urlList[r.urlList.length-1].origin;let a=new fN({eventSourceSettings:this.#c,push:A=>{this.dispatchEvent(BN(A.type,A.options))}});dN(r.body.stream,a,A=>{A?.aborted===!1&&(this.close(),this.dispatchEvent(new Event("error")))})},this.#A=EN(t)}async#g(){this.#s!==Zi&&(this.#s=zi,this.dispatchEvent(new Event("error")),await CN(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}},YB={CONNECTING:{__proto__:null,configurable:!1,enumerable:!0,value:zi,writable:!1},OPEN:{__proto__:null,configurable:!1,enumerable:!0,value:_B,writable:!1},CLOSED:{__proto__:null,configurable:!1,enumerable:!0,value:Zi,writable:!1}};Object.defineProperties(Hr,YB);Object.defineProperties(Hr.prototype,YB);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}]);OB.exports={EventSource:Hr,defaultReconnectionTime:LB}});var da=Q((JY,R)=>{"use strict";var bN=fr(),PB=ei(),yN=Qr(),xN=_d(),vN=Br(),kN=qc(),DN=cE(),RN=dE(),HB=L(),ha=U(),{InvalidArgumentError:ga}=HB,Vr=tm(),TN=si(),FN=vl(),SN=Mm(),UN=Rl(),NN=hl(),GN=En(),{getGlobalDispatcher:VB,setGlobalDispatcher:MN}=xn(),LN=vn(),_N=on(),YN=nn();Object.assign(PB.prototype,Vr);R.exports.Dispatcher=PB;R.exports.Client=bN;R.exports.Pool=yN;R.exports.BalancedPool=xN;R.exports.Agent=vN;R.exports.ProxyAgent=kN;R.exports.EnvHttpProxyAgent=DN;R.exports.RetryAgent=RN;R.exports.RetryHandler=GN;R.exports.DecoratorHandler=LN;R.exports.Redire Line truncated
`+e.errors.map(t=>` - ${t.message}`).join(`
`)}var EM=class extends Error{constructor(e,t,s){super(dM(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},mM=["method","baseUrl","url","headers","request","query","mediaType","operationName"],fM=["query","method","url"],GC=/\/api\/v3\/?$/;function QM(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(fM.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)=>mM.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 GC.test(o)&&(i.url=o.replace(GC,"/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 EM(i,a,n.data)}return n.data.data})}function Nu(e,t){let s=e.defaults(t);return Object.assign((i,o)=>QM(s,i,o),{defaults:Nu.bind(null,s),endpoint:s.endpoint})}var tJ=Nu(ro,{headers:{"user-agent":`octokit-graphql.js/${hM} ${ds()}`},method:"POST",url:"/graphql"});function MC(e){return Nu(e,{method:"POST",url:"/graphql"})}var Gu="(?:[a-zA-Z0-9_-]+)",LC="\\.",_C=new RegExp(`^${Gu}${LC}${Gu}${LC}${Gu}$`),BM=_C.test.bind(_C);async function CM(e){let t=BM(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 IM(e){return e.split(/\./).length===3?`bearer ${e}`:`token ${e}`}async function wM(e,t,s,r){let i=t.endpoint.merge(s,r);return i.headers.authorization=IM(e),t(i)}var YC=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(CM.bind(null,t),{hook:wM.bind(null,t)})};var Mu="7.0.6";var OC=()=>{},bM=console.warn.bind(console),yM=console.error.bind(console);function xM(e={}){return typeof e.debug!="function"&&(e.debug=OC),typeof e.info!="function"&&(e.info=OC),typeof e.warn!="function"&&(e.warn=bM),typeof e.error!="function"&&(e.error=yM),e}var JC=`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 dC.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} ${JC}`:JC,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=MC(this.request).defaults(r),this.log=xM(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=YC(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 vM={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 OI(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(xL))?r=t.dot?kL:vL:(s=e.match(EL))?r=(t.nocase?t.dot?BL:QL:t.dot?fL:mL)(s[1]):(s=e.match(DL))?r=(t.nocase?t.dot?TL:RL:t.dot?FL:SL)(s):(s=e.match(CL))?r=t.dot?wL:IL:(s=e.match(bL))&&(r=yL);let i=GI.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?GL:t.dot?ML:LL,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"?PL(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=GI;ye.Minimatch=fs;ye.escape=MI;ye.unescape=Kr;var HL=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,PI=new Set,$u=typeof process=="object"&&process?process:{},HI=(e,t,s,r)=>{typeof $u.emitWarning=="function"?$u.emitWarning(e,t,s,r):console.error(`[${s}] ${t}: ${e}`)},Oa=globalThis.AbortController,hI=globalThis.AbortSignal;if(typeof Oa>"u"){hI=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(s,r){this._onabort.push(r)}},Oa=class{constructor(){t()}signal=new hI;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,HI("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 VL=e=>!PI.has(e),ms=e=>e&&e===Math.floor(e)&&e>0&&isFinite(e),VI=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)}},qL=class uo{heap;length;static#e=!1;static create(t){let s=VI(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 qI{#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 deleteRelease(t){await this.github.rest.repos.deleteRelease(t)}async updateReleaseAsset(t){return await this.github.rest.repos.updateReleaseAsset(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})}},k_=e=>({name:(0,xw.basename)(e),mime:D_(e),size:(0,ww.statSync)(e).size}),D_=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}=k_(r),u=s.match(/\/releases\/(\d+)\/assets/),l=u?Number(u[1]):void 0,p=i.find(({name:E,label:m})=>E===a||E===ap(a)||m===a);if(p){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:p.id||1,owner:o,repo:n})}console.log(`\u2B06\uFE0F Uploading ${a}...`);let g=new URL(s);g.searchParams.append("name",a);let h=async()=>{let E=await(0,bw.open)(r);try{return await t.uploadReleaseAsset({url:g.toString(),size:c,mime:A,token:e.github_token,data:E.readableWebStream({type:"bytes"})})}finally{await E.close()}};try{let E=await h(),m=E.data;if(E.status!==201)throw new Error(`Failed to upload release asset ${a}. received status code ${E.status}
${m.message}
${JSON.stringify(m.errors)}`);if(m.name&&m.name!==a&&m.id){console.log(`\u270F\uFE0F Restoring asset label to ${a}...`);try{let{data:d}=await t.updateReleaseAsset({owner:o,repo:n,asset_id:m.id,name:m.name,label:a});return console.log(`\u2705 Uploaded ${a}`),d}catch(d){console.warn(`error updating release asset label for ${a}: ${d}`)}}return console.log(`\u2705 Uploaded ${a}`),m}catch(E){let m=E?.status??E?.response?.status,d=E?.response?.data;if(e.input_overwrite_files!==!1&&m===422&&d?.errors?.[0]?.code==="already_exists"&&l!==void 0){console.log(`\u26A0\uFE0F Asset ${a} already exists (race condition), refreshing assets and retrying once...`);let C=(await t.listReleaseAssets({owner:o,repo:n,release_id:l})).find(({name:B})=>B==ap(a));if(C){await t.deleteReleaseAsset({owner:o,repo:n,asset_id:C.id});let B=await h(),b=B.data;if(B.status!==201)throw new Error(`Failed to upload release asset ${a}. received status code ${B.status}
${b.message}
${JSON.stringify(b.errors)}`);return console.log(`\u2705 Uploaded ${a}`),b}}throw E}},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 kw(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)||"",E=c.body||"",m;e.input_append_body&&h&&E?m=E+`
`+h:m=h||E;let d=e.input_prerelease!==void 0?e.input_prerelease:c.prerelease,f=e.input_make_latest;return{release:(await t.updateRelease({owner:r,repo:i,release_id:u,tag_name:p,target_commitish:l,name:g,body:m,draft:c.draft,prerelease:d,discussion_category_name:n,generate_release_notes:a,make_latest:f})).data,created:!1}}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)}},cp=async(e,t,s,r=!1,i=3)=>{if(e.input_draft===!0||s.draft===!1)return s;if(i<=0)throw console.log("\u274C Too many retries. Aborting..."),new Error("Too many retries.");let[o,n]=e.github_repository.split("/");try{let{data:a}=await t.finalizeRelease({owner:o,repo:n,release_id:s.id,make_latest:e.input_make_latest});return a}catch(a){if(console.warn(`error finalizing release: ${a}`),r&&s.draft&&M_(a)){let A=!1;try{console.log(`\u{1F9F9} Deleting draft release ${s.id} for tag ${s.tag_name} because tag creation is blocked by repository rules...`),await t.deleteRelease({owner:o,repo:n,release_id:s.id}),A=!0}catch(u){console.warn(`error deleting orphan draft release ${s.id}: ${u}`)}let c=A?`Deleted draft release ${s.id} to avoid leaving an orphaned draft release.`:`Failed to delete draft release ${s.id}; manual cleanup may still be required.`;throw new Error(`Tag creation for ${s.tag_name} is blocked by repository rules. ${c}`)}return console.log(`retrying... (${i-1} retries remaining)`),cp(e,t,s,r,i-1)}},lp=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)`),lp(e,t,s,r-1)}};async function kw(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}}var R_=1e3,T_=2;async function F_(e){await new Promise(t=>setTimeout(t,e))}async function S_(e,t,s,r){let i=[],o=0;for await(let n of e.allReleases({owner:t,repo:s}))if(i.push(...n.data.filter(a=>a.tag_name===r)),o+=1,o>=T_)break;return i}function U_(e,t){return t&&e.some(s=>s.id===t.id)||e.length===0?t:[...e].sort((s,r)=>s.draft!==r.draft?Number(s.draft)-Number(r.draft):s.id-r.id)[0]}async function N_(e,t,s,r,i,o){for(let n of o)if(!(n.id===i||!n.draft||n.assets.length>0))try{console.log(`\u{1F9F9} Removing duplicate draft release ${n.id} for tag ${r}...`),await e.deleteRelease({owner:t,repo:s,release_id:n.id})}catch(a){console.warn(`error deleting duplicate release ${n.id}: ${a}`)}}async function G_(e,t,s,r,i,o){let n=Math.max(o,1);for(let a=1;a<=n;a+=1){let A;try{A=await kw(e,t,s,r)}catch(l){console.warn(`error reloading release for tag ${r}: ${l}`)}let c=[];try{c=await S_(e,t,s,r)}catch(l){console.warn(`error listing recent releases for tag ${r}: ${l}`)}let u=U_(c,A);if(u)return u.id!==i.id&&console.log(`\u21AA\uFE0F Using release ${u.id} for tag ${r} instead of duplicate draft ${i.id}`),await N_(e,t,s,r,u.id,c),u;a<n&&(console.log(`Release ${i.id} is not yet discoverable by tag ${r}, retrying... (${n-a} retries remaining)`),await F_(R_))}return console.log(`\u26A0\uFE0F Continuing with newly created release ${i.id} because tag ${r} is still not discoverable`),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=l===!0?t.input_draft===!0:!0,g=t.input_target_commitish,h=t.input_make_latest,E="";g&&(E=` using commit "${g}"`),console.log(`\u{1F469}\u200D\u{1F3ED} Creating new GitHub release for tag ${A}${E}...`);try{let m=await s.createRelease({owner:r,repo:i,tag_name:A,name:c,body:u,draft:p,prerelease:l,target_commitish:g,discussion_category_name:o,generate_release_notes:n,make_latest:h}),d=await G_(s,r,i,A,m.data,a);return{release:d,created:d.id===m.data.id}}catch(m){switch(console.log(`\u26A0\uFE0F GitHub release failed with status: ${m.status}`),console.log(`${JSON.stringify(m.response.data)}`),m.status){case 403:throw console.log("Skip retry \u2014 your GitHub token/PAT does not have the required permission to create a release"),m;case 404:throw console.log("Skip retry - discussion category mismatch"),m;case 422:if(m.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"),m;break}return console.log(`retrying... (${a-1} retries remaining)`),Ap(t,s,a-1)}}function M_(e){let t=e?.response?.data?.errors;return!Array.isArray(t)||e?.status!==422?!1:t.some(({field:s,message:r})=>s==="pre_receive"&&typeof r=="string"&&r.includes("creations being restricted"))}var Dw=require("process");async function L_(){try{let e=Qw(Dw.env);if(!e.input_tag_name&&!ja(e.github_ref)&&!e.input_draft)throw new Error("\u26A0\uFE0F Git Line truncated
/*! 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 *)
*/
+11
View File
@@ -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
}
+79
View File
@@ -0,0 +1,79 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const mime_1 = require("mime");
const path_1 = require("path");
exports.asset = (path) => {
return {
name: path_1.basename(path),
mime: exports.mimeOrDefault(path),
size: fs_1.lstatSync(path).size,
file: fs_1.readFileSync(path)
};
};
exports.mimeOrDefault = (path) => {
return mime_1.getType(path) || "application/octet-stream";
};
exports.upload = (gh, url, path) => __awaiter(void 0, void 0, void 0, function* () {
let { name, size, mime, file } = exports.asset(path);
console.log(`⬆️ Uploading ${name}...`);
return yield gh.repos.uploadReleaseAsset({
url,
headers: {
"content-length": size,
"content-type": mime
},
name,
file
});
});
exports.release = (config, gh) => __awaiter(void 0, void 0, void 0, function* () {
const [owner, repo] = config.github_repository.split("/");
const tag = config.github_ref.replace("refs/tags/", "");
try {
let release = yield gh.repos.getReleaseByTag({
owner,
repo,
tag
});
return release.data;
}
catch (error) {
if (error.status === 404) {
try {
const tag_name = tag;
const name = config.input_name || tag;
const body = config.input_body;
const draft = config.input_draft;
console.log(`👩‍🏭 Creating new GitHub release for tag ${tag_name}...`);
let release = yield gh.repos.createRelease({
owner,
repo,
tag_name,
name,
body,
draft
});
return release.data;
}
catch (error) {
// presume a race with competing metrix runs
console.log(`⚠️ GitHub release failed with status: ${error.status}, retrying...`);
return exports.release(config, gh);
}
}
else {
console.log(`⚠️ Unexpected error fetching GitHub release for tag ${config.github_ref}: ${error}`);
throw error;
}
}
});
+38
View File
@@ -0,0 +1,38 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("./util");
const github_1 = require("./github");
const core_1 = require("@actions/core");
const github_2 = require("@actions/github");
const process_1 = require("process");
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const config = util_1.parseConfig(process_1.env);
if (!util_1.isTag(config.github_ref)) {
throw new Error(`⚠️ GitHub Releases requires a tag`);
}
const gh = new github_2.GitHub(config.github_token);
let rel = yield github_1.release(config, gh);
if (config.input_files) {
util_1.paths(config.input_files).forEach((path) => __awaiter(this, void 0, void 0, function* () {
yield github_1.upload(gh, rel.upload_url, path);
}));
}
console.log(`🎉 Release ready at ${rel.html_url}`);
}
catch (error) {
core_1.setFailed(error.message);
}
});
}
run();
+31
View File
@@ -0,0 +1,31 @@
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const glob = __importStar(require("glob"));
const fs_1 = require("fs");
exports.parseConfig = (env) => {
return {
github_token: env.GITHUB_TOKEN || "",
github_ref: env.GITHUB_REF || "",
github_repository: env.GITHUB_REPOSITORY || "",
input_name: env.INPUT_NAME,
input_body: env.INPUT_BODY,
input_body_path: env.INPUT_BODY_PATH,
input_files: (env.INPUT_FILES || "").split(","),
input_draft: env.INPUT_DRAFT === "true"
};
};
exports.paths = (patterns) => {
return patterns.reduce((acc, pattern) => {
return acc.concat(glob.sync(pattern).filter(path => fs_1.lstatSync(path).isFile()));
}, []);
};
exports.isTag = (ref) => {
return ref.startsWith("refs/tags/");
};
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../mime/cli.js
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../semver/bin/semver
Generated Vendored Symlink
+1
View File
@@ -0,0 +1 @@
../which/bin/which
+7
View File
@@ -0,0 +1,7 @@
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+97
View File
@@ -0,0 +1,97 @@
# `@actions/core`
> Core functions for setting results, logging, registering secrets and exporting variables across actions
## Usage
#### Inputs/Outputs
You can use this library to get inputs or set outputs:
```js
const core = require('@actions/core');
const myInput = core.getInput('inputName', { required: true });
// Do stuff
core.setOutput('outputKey', 'outputVal');
```
#### Exporting variables
You can also export variables for future steps. Variables get set in the environment.
```js
const core = require('@actions/core');
// Do stuff
core.exportVariable('envVar', 'Val');
```
#### PATH Manipulation
You can explicitly add items to the path for all remaining steps in a workflow:
```js
const core = require('@actions/core');
core.addPath('pathToTool');
```
#### Exit codes
You should use this library to set the failing exit code for your action:
```js
const core = require('@actions/core');
try {
// Do stuff
}
catch (err) {
// setFailed logs the message and sets a failing exit code
core.setFailed(`Action failed with error ${err}`);
}
```
#### Logging
Finally, this library provides some utilities for logging. Note that debug logging is hidden from the logs by default. This behavior can be toggled by enabling the [Step Debug Logs](../../docs/action-debugging.md#step-debug-logs).
```js
const core = require('@actions/core');
const myInput = core.getInput('input');
try {
core.debug('Inside try block');
if (!myInput) {
core.warning('myInput was not set');
}
// Do stuff
}
catch (err) {
core.error(`Error ${err}, action may still succeed though`);
}
```
This library can also wrap chunks of output in foldable groups.
```js
const core = require('@actions/core')
// Manually wrap output
core.startGroup('Do some function')
doSomeFunction()
core.endGroup()
// Wrap an asynchronous function call
const result = await core.group('Do something async', async () => {
const response = await doSomeHTTPRequest()
return response
})
```
+16
View File
@@ -0,0 +1,16 @@
interface CommandProperties {
[key: string]: string;
}
/**
* Commands
*
* Command Format:
* ##[name key=value;key=value]message
*
* Examples:
* ##[warning]This is the user warning message
* ##[set-secret name=mypassword]definitelyNotAPassword!
*/
export declare function issueCommand(command: string, properties: CommandProperties, message: string): void;
export declare function issue(name: string, message?: string): void;
export {};
+66
View File
@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const os = require("os");
/**
* Commands
*
* Command Format:
* ##[name key=value;key=value]message
*
* Examples:
* ##[warning]This is the user warning message
* ##[set-secret name=mypassword]definitelyNotAPassword!
*/
function issueCommand(command, properties, message) {
const cmd = new Command(command, properties, message);
process.stdout.write(cmd.toString() + os.EOL);
}
exports.issueCommand = issueCommand;
function issue(name, message = '') {
issueCommand(name, {}, message);
}
exports.issue = issue;
const CMD_PREFIX = '##[';
class Command {
constructor(command, properties, message) {
if (!command) {
command = 'missing.command';
}
this.command = command;
this.properties = properties;
this.message = message;
}
toString() {
let cmdStr = CMD_PREFIX + this.command;
if (this.properties && Object.keys(this.properties).length > 0) {
cmdStr += ' ';
for (const key in this.properties) {
if (this.properties.hasOwnProperty(key)) {
const val = this.properties[key];
if (val) {
// safely append the val - avoid blowing up when attempting to
// call .replace() if message is not a string for some reason
cmdStr += `${key}=${escape(`${val || ''}`)};`;
}
}
}
}
cmdStr += ']';
// safely append the message - avoid blowing up when attempting to
// call .replace() if message is not a string for some reason
const message = `${this.message || ''}`;
cmdStr += escapeData(message);
return cmdStr;
}
}
function escapeData(s) {
return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A');
}
function escape(s) {
return s
.replace(/\r/g, '%0D')
.replace(/\n/g, '%0A')
.replace(/]/g, '%5D')
.replace(/;/g, '%3B');
}
//# sourceMappingURL=command.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":";;AAAA,yBAAwB;AAQxB;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAC1B,OAAe,EACf,UAA6B,EAC7B,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;AAC/C,CAAC;AAPD,oCAOC;AAED,SAAgB,KAAK,CAAC,IAAY,EAAE,UAAkB,EAAE;IACtD,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACjC,CAAC;AAFD,sBAEC;AAED,MAAM,UAAU,GAAG,KAAK,CAAA;AAExB,MAAM,OAAO;IAKX,YAAY,OAAe,EAAE,UAA6B,EAAE,OAAe;QACzE,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,GAAG,iBAAiB,CAAA;SAC5B;QAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,QAAQ;QACN,IAAI,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,OAAO,CAAA;QAEtC,IAAI,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9D,MAAM,IAAI,GAAG,CAAA;YACb,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,UAAU,EAAE;gBACjC,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;oBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;oBAChC,IAAI,GAAG,EAAE;wBACP,8DAA8D;wBAC9D,6DAA6D;wBAC7D,MAAM,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,CAAA;qBAC9C;iBACF;aACF;SACF;QAED,MAAM,IAAI,GAAG,CAAA;QAEb,kEAAkE;QAClE,6DAA6D;QAC7D,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAA;QACvC,MAAM,IAAI,UAAU,CAAC,OAAO,CAAC,CAAA;QAE7B,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AACtD,CAAC;AAED,SAAS,MAAM,CAAC,CAAS;IACvB,OAAO,CAAC;SACL,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACzB,CAAC"}
+94
View File
@@ -0,0 +1,94 @@
/**
* Interface for getInput options
*/
export interface InputOptions {
/** Optional. Whether the input is required. If required and not present, will throw. Defaults to false */
required?: boolean;
}
/**
* The code to exit an action
*/
export declare enum ExitCode {
/**
* A code indicating that the action was successful
*/
Success = 0,
/**
* A code indicating that the action was a failure
*/
Failure = 1
}
/**
* sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable
*/
export declare function exportVariable(name: string, val: string): void;
/**
* exports the variable and registers a secret which will get masked from logs
* @param name the name of the variable to set
* @param val value of the secret
*/
export declare function exportSecret(name: string, val: string): void;
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
export declare function addPath(inputPath: string): void;
/**
* Gets the value of an input. The value is also trimmed.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string
*/
export declare function getInput(name: string, options?: InputOptions): string;
/**
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store
*/
export declare function setOutput(name: string, value: string): void;
/**
* Sets the action status to failed.
* When the action exits it will be with an exit code of 1
* @param message add error issue message
*/
export declare function setFailed(message: string): void;
/**
* Writes debug message to user log
* @param message debug message
*/
export declare function debug(message: string): void;
/**
* Adds an error issue
* @param message error issue message
*/
export declare function error(message: string): void;
/**
* Adds an warning issue
* @param message warning issue message
*/
export declare function warning(message: string): void;
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
export declare function startGroup(name: string): void;
/**
* End an output group.
*/
export declare function endGroup(): void;
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
export declare function group<T>(name: string, fn: () => Promise<T>): Promise<T>;
+168
View File
@@ -0,0 +1,168 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const command_1 = require("./command");
const path = require("path");
/**
* The code to exit an action
*/
var ExitCode;
(function (ExitCode) {
/**
* A code indicating that the action was successful
*/
ExitCode[ExitCode["Success"] = 0] = "Success";
/**
* A code indicating that the action was a failure
*/
ExitCode[ExitCode["Failure"] = 1] = "Failure";
})(ExitCode = exports.ExitCode || (exports.ExitCode = {}));
//-----------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------
/**
* sets env variable for this action and future actions in the job
* @param name the name of the variable to set
* @param val the value of the variable
*/
function exportVariable(name, val) {
process.env[name] = val;
command_1.issueCommand('set-env', { name }, val);
}
exports.exportVariable = exportVariable;
/**
* exports the variable and registers a secret which will get masked from logs
* @param name the name of the variable to set
* @param val value of the secret
*/
function exportSecret(name, val) {
exportVariable(name, val);
// the runner will error with not implemented
// leaving the function but raising the error earlier
command_1.issueCommand('set-secret', {}, val);
throw new Error('Not implemented.');
}
exports.exportSecret = exportSecret;
/**
* Prepends inputPath to the PATH (for this action and future actions)
* @param inputPath
*/
function addPath(inputPath) {
command_1.issueCommand('add-path', {}, inputPath);
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
}
exports.addPath = addPath;
/**
* Gets the value of an input. The value is also trimmed.
*
* @param name name of the input to get
* @param options optional. See InputOptions.
* @returns string
*/
function getInput(name, options) {
const val = process.env[`INPUT_${name.replace(' ', '_').toUpperCase()}`] || '';
if (options && options.required && !val) {
throw new Error(`Input required and not supplied: ${name}`);
}
return val.trim();
}
exports.getInput = getInput;
/**
* Sets the value of an output.
*
* @param name name of the output to set
* @param value value to store
*/
function setOutput(name, value) {
command_1.issueCommand('set-output', { name }, value);
}
exports.setOutput = setOutput;
//-----------------------------------------------------------------------
// Results
//-----------------------------------------------------------------------
/**
* Sets the action status to failed.
* When the action exits it will be with an exit code of 1
* @param message add error issue message
*/
function setFailed(message) {
process.exitCode = ExitCode.Failure;
error(message);
}
exports.setFailed = setFailed;
//-----------------------------------------------------------------------
// Logging Commands
//-----------------------------------------------------------------------
/**
* Writes debug message to user log
* @param message debug message
*/
function debug(message) {
command_1.issueCommand('debug', {}, message);
}
exports.debug = debug;
/**
* Adds an error issue
* @param message error issue message
*/
function error(message) {
command_1.issue('error', message);
}
exports.error = error;
/**
* Adds an warning issue
* @param message warning issue message
*/
function warning(message) {
command_1.issue('warning', message);
}
exports.warning = warning;
/**
* Begin an output group.
*
* Output until the next `groupEnd` will be foldable in this group
*
* @param name The name of the output group
*/
function startGroup(name) {
command_1.issue('group', name);
}
exports.startGroup = startGroup;
/**
* End an output group.
*/
function endGroup() {
command_1.issue('endgroup');
}
exports.endGroup = endGroup;
/**
* Wrap an asynchronous function call in a group.
*
* Returns the same type as the function itself.
*
* @param name The name of the group
* @param fn The function to wrap in the group
*/
function group(name, fn) {
return __awaiter(this, void 0, void 0, function* () {
startGroup(name);
let result;
try {
result = yield fn();
}
finally {
endGroup();
}
return result;
});
}
exports.group = group;
//# sourceMappingURL=core.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,uCAA6C;AAE7C,6BAA4B;AAU5B;;GAEG;AACH,IAAY,QAUX;AAVD,WAAY,QAAQ;IAClB;;OAEG;IACH,6CAAW,CAAA;IAEX;;OAEG;IACH,6CAAW,CAAA;AACb,CAAC,EAVW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAUnB;AAED,yEAAyE;AACzE,YAAY;AACZ,yEAAyE;AAEzE;;;;GAIG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,GAAW;IACtD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAA;IACvB,sBAAY,CAAC,SAAS,EAAE,EAAC,IAAI,EAAC,EAAE,GAAG,CAAC,CAAA;AACtC,CAAC;AAHD,wCAGC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,IAAY,EAAE,GAAW;IACpD,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAEzB,6CAA6C;IAC7C,qDAAqD;IACrD,sBAAY,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;AACrC,CAAC;AAPD,oCAOC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,SAAiB;IACvC,sBAAY,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,CAAC,CAAA;IACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAA;AAC7E,CAAC;AAHD,0BAGC;AAED;;;;;;GAMG;AACH,SAAgB,QAAQ,CAAC,IAAY,EAAE,OAAsB;IAC3D,MAAM,GAAG,GACP,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;IACpE,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAA;KAC5D;IAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;AACnB,CAAC;AARD,4BAQC;AAED;;;;;GAKG;AACH,SAAgB,SAAS,CAAC,IAAY,EAAE,KAAa;IACnD,sBAAY,CAAC,YAAY,EAAE,EAAC,IAAI,EAAC,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAFD,8BAEC;AAED,yEAAyE;AACzE,UAAU;AACV,yEAAyE;AAEzE;;;;GAIG;AACH,SAAgB,SAAS,CAAC,OAAe;IACvC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAA;IACnC,KAAK,CAAC,OAAO,CAAC,CAAA;AAChB,CAAC;AAHD,8BAGC;AAED,yEAAyE;AACzE,mBAAmB;AACnB,yEAAyE;AAEzE;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAe;IACnC,sBAAY,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACpC,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,KAAK,CAAC,OAAe;IACnC,eAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;AACzB,CAAC;AAFD,sBAEC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,OAAe;IACrC,eAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;AAC3B,CAAC;AAFD,0BAEC;AAED;;;;;;GAMG;AACH,SAAgB,UAAU,CAAC,IAAY;IACrC,eAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;AACtB,CAAC;AAFD,gCAEC;AAED;;GAEG;AACH,SAAgB,QAAQ;IACtB,eAAK,CAAC,UAAU,CAAC,CAAA;AACnB,CAAC;AAFD,4BAEC;AAED;;;;;;;GAOG;AACH,SAAsB,KAAK,CAAI,IAAY,EAAE,EAAoB;;QAC/D,UAAU,CAAC,IAAI,CAAC,CAAA;QAEhB,IAAI,MAAS,CAAA;QAEb,IAAI;YACF,MAAM,GAAG,MAAM,EAAE,EAAE,CAAA;SACpB;gBAAS;YACR,QAAQ,EAAE,CAAA;SACX;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CAAA;AAZD,sBAYC"}
+67
View File
@@ -0,0 +1,67 @@
{
"_args": [
[
"@actions/core@1.1.0",
"/Users/dougtangren/code/rust/action-gh-release"
]
],
"_from": "@actions/core@1.1.0",
"_id": "@actions/core@1.1.0",
"_inBundle": false,
"_integrity": "sha512-KKpo3xzo0Zsikni9tbOsEQkxZBGDsYSJZNkTvmo0gPSXrc98TBOcdTvKwwjitjkjHkreTggWdB1ACiAFVgsuzA==",
"_location": "/@actions/core",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@actions/core@1.1.0",
"name": "@actions/core",
"escapedName": "@actions%2fcore",
"scope": "@actions",
"rawSpec": "1.1.0",
"saveSpec": null,
"fetchSpec": "1.1.0"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/@actions/core/-/core-1.1.0.tgz",
"_spec": "1.1.0",
"_where": "/Users/dougtangren/code/rust/action-gh-release",
"bugs": {
"url": "https://github.com/actions/toolkit/issues"
},
"description": "Actions core lib",
"devDependencies": {
"@types/node": "^12.0.2"
},
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"gitHead": "a2ab4bcf78e4f7080f0d45856e6eeba16f0bbc52",
"homepage": "https://github.com/actions/toolkit/tree/master/packages/core",
"keywords": [
"github",
"actions",
"core"
],
"license": "MIT",
"main": "lib/core.js",
"name": "@actions/core",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/toolkit.git"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1",
"tsc": "tsc"
},
"version": "1.1.0"
}
+7
View File
@@ -0,0 +1,7 @@
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+50
View File
@@ -0,0 +1,50 @@
# `@actions/github`
> A hydrated Octokit client.
## Usage
Returns an Octokit client. See https://octokit.github.io/rest.js for the API.
```js
const github = require('@actions/github');
const core = require('@actions/core');
// This should be a token with access to your repository scoped in as a secret.
const myToken = core.getInput('myToken');
const octokit = new github.GitHub(myToken);
const { data: pullRequest } = await octokit.pulls.get({
owner: 'octokit',
repo: 'rest.js',
pull_number: 123,
mediaType: {
format: 'diff'
}
});
console.log(pullRequest);
```
You can pass client options (except `auth`, which is handled by the token argument), as specified by [Octokit](https://octokit.github.io/rest.js/), as a second argument to the `GitHub` constructor.
You can also make GraphQL requests. See https://github.com/octokit/graphql.js for the API.
```js
const result = await octokit.graphql(query, variables);
```
Finally, you can get the context of the current action:
```js
const github = require('@actions/github');
const context = github.context;
const newIssue = await octokit.issues.create({
...context.repo,
title: 'New issue!',
body: 'Hello Universe!'
});
```
+26
View File
@@ -0,0 +1,26 @@
import { WebhookPayload } from './interfaces';
export declare class Context {
/**
* Webhook payload object that triggered the workflow
*/
payload: WebhookPayload;
eventName: string;
sha: string;
ref: string;
workflow: string;
action: string;
actor: string;
/**
* Hydrate the context from the environment
*/
constructor();
readonly issue: {
owner: string;
repo: string;
number: number;
};
readonly repo: {
owner: string;
repo: string;
};
}
+45
View File
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = require("fs");
const os_1 = require("os");
class Context {
/**
* Hydrate the context from the environment
*/
constructor() {
this.payload = {};
if (process.env.GITHUB_EVENT_PATH) {
if (fs_1.existsSync(process.env.GITHUB_EVENT_PATH)) {
this.payload = JSON.parse(fs_1.readFileSync(process.env.GITHUB_EVENT_PATH, { encoding: 'utf8' }));
}
else {
process.stdout.write(`GITHUB_EVENT_PATH ${process.env.GITHUB_EVENT_PATH} does not exist${os_1.EOL}`);
}
}
this.eventName = process.env.GITHUB_EVENT_NAME;
this.sha = process.env.GITHUB_SHA;
this.ref = process.env.GITHUB_REF;
this.workflow = process.env.GITHUB_WORKFLOW;
this.action = process.env.GITHUB_ACTION;
this.actor = process.env.GITHUB_ACTOR;
}
get issue() {
const payload = this.payload;
return Object.assign(Object.assign({}, this.repo), { number: (payload.issue || payload.pullRequest || payload).number });
}
get repo() {
if (process.env.GITHUB_REPOSITORY) {
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
return { owner, repo };
}
if (this.payload.repository) {
return {
owner: this.payload.repository.owner.login,
repo: this.payload.repository.name
};
}
throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'");
}
}
exports.Context = Context;
//# sourceMappingURL=context.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;AAEA,2BAA2C;AAC3C,2BAAsB;AAEtB,MAAa,OAAO;IAalB;;OAEG;IACH;QACE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACjC,IAAI,eAAU,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE;gBAC7C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CACvB,iBAAY,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC,CAChE,CAAA;aACF;iBAAM;gBACL,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBACE,OAAO,CAAC,GAAG,CAAC,iBACd,kBAAkB,QAAG,EAAE,CACxB,CAAA;aACF;SACF;QACD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAA2B,CAAA;QACxD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAyB,CAAA;QACrD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAuB,CAAA;QACjD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAsB,CAAA;IACjD,CAAC;IAED,IAAI,KAAK;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAE5B,uCACK,IAAI,CAAC,IAAI,KACZ,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,MAAM,IACjE;IACH,CAAC;IAED,IAAI,IAAI;QACN,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACjC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC9D,OAAO,EAAC,KAAK,EAAE,IAAI,EAAC,CAAA;SACrB;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YAC3B,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK;gBAC1C,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI;aACnC,CAAA;SACF;QAED,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAA;IACH,CAAC;CACF;AAjED,0BAiEC"}
+8
View File
@@ -0,0 +1,8 @@
import { GraphQlQueryResponse, Variables } from '@octokit/graphql';
import Octokit from '@octokit/rest';
import * as Context from './context';
export declare const context: Context.Context;
export declare class GitHub extends Octokit {
graphql: (query: string, variables?: Variables) => Promise<GraphQlQueryResponse>;
constructor(token: string, opts?: Omit<Octokit.Options, 'auth'>);
}
+29
View File
@@ -0,0 +1,29 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
// Originally pulled from https://github.com/JasonEtco/actions-toolkit/blob/master/src/github.ts
const graphql_1 = require("@octokit/graphql");
const rest_1 = __importDefault(require("@octokit/rest"));
const Context = __importStar(require("./context"));
// We need this in order to extend Octokit
rest_1.default.prototype = new rest_1.default();
exports.context = new Context.Context();
class GitHub extends rest_1.default {
constructor(token, opts = {}) {
super(Object.assign(Object.assign({}, opts), { auth: `token ${token}` }));
this.graphql = graphql_1.defaults({
headers: { authorization: `token ${token}` }
});
}
}
exports.GitHub = GitHub;
//# sourceMappingURL=github.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,gGAAgG;AAChG,8CAA0E;AAC1E,yDAAmC;AACnC,mDAAoC;AAEpC,0CAA0C;AAC1C,cAAO,CAAC,SAAS,GAAG,IAAI,cAAO,EAAE,CAAA;AAEpB,QAAA,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;AAE5C,MAAa,MAAO,SAAQ,cAAO;IAMjC,YAAY,KAAa,EAAE,OAAsC,EAAE;QACjE,KAAK,iCAAK,IAAI,KAAE,IAAI,EAAE,SAAS,KAAK,EAAE,IAAE,CAAA;QACxC,IAAI,CAAC,OAAO,GAAG,kBAAQ,CAAC;YACtB,OAAO,EAAE,EAAC,aAAa,EAAE,SAAS,KAAK,EAAE,EAAC;SAC3C,CAAC,CAAA;IACJ,CAAC;CACF;AAZD,wBAYC"}
+36
View File
@@ -0,0 +1,36 @@
export interface PayloadRepository {
[key: string]: any;
full_name?: string;
name: string;
owner: {
[key: string]: any;
login: string;
name?: string;
};
html_url?: string;
}
export interface WebhookPayload {
[key: string]: any;
repository?: PayloadRepository;
issue?: {
[key: string]: any;
number: number;
html_url?: string;
body?: string;
};
pull_request?: {
[key: string]: any;
number: number;
html_url?: string;
body?: string;
};
sender?: {
[key: string]: any;
type: string;
};
action?: string;
installation?: {
id: number;
[key: string]: any;
};
}
+4
View File
@@ -0,0 +1,4 @@
"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=interfaces.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA,uDAAuD"}
+71
View File
@@ -0,0 +1,71 @@
{
"_args": [
[
"@actions/github@1.1.0",
"/Users/dougtangren/code/rust/action-gh-release"
]
],
"_from": "@actions/github@1.1.0",
"_id": "@actions/github@1.1.0",
"_inBundle": false,
"_integrity": "sha512-cHf6PyoNMdei13jEdGPhKprIMFmjVVW/dnM5/9QmQDJ1ZTaGVyezUSCUIC/ySNLRvDUpeFwPYMdThSEJldSbUw==",
"_location": "/@actions/github",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@actions/github@1.1.0",
"name": "@actions/github",
"escapedName": "@actions%2fgithub",
"scope": "@actions",
"rawSpec": "1.1.0",
"saveSpec": null,
"fetchSpec": "1.1.0"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/@actions/github/-/github-1.1.0.tgz",
"_spec": "1.1.0",
"_where": "/Users/dougtangren/code/rust/action-gh-release",
"bugs": {
"url": "https://github.com/actions/toolkit/issues"
},
"dependencies": {
"@octokit/graphql": "^2.0.1",
"@octokit/rest": "^16.15.0"
},
"description": "Actions github lib",
"devDependencies": {
"jest": "^24.7.1"
},
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"gitHead": "a2ab4bcf78e4f7080f0d45856e6eeba16f0bbc52",
"homepage": "https://github.com/actions/toolkit/tree/master/packages/github",
"keywords": [
"github",
"actions"
],
"license": "MIT",
"main": "lib/github.js",
"name": "@actions/github",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/toolkit.git"
},
"scripts": {
"build": "tsc",
"test": "jest",
"tsc": "tsc"
},
"version": "1.1.0"
}
+21
View File
@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+421
View File
@@ -0,0 +1,421 @@
# endpoint.js
> Turns GitHub REST API endpoints into generic request options
[![@latest](https://img.shields.io/npm/v/@octokit/endpoint.svg)](https://www.npmjs.com/package/@octokit/endpoint)
[![Build Status](https://travis-ci.org/octokit/endpoint.js.svg?branch=master)](https://travis-ci.org/octokit/endpoint.js)
[![Greenkeeper](https://badges.greenkeeper.io/octokit/endpoint.js.svg)](https://greenkeeper.io/)
`@octokit/endpoint` combines [GitHub REST API routes](https://developer.github.com/v3/) with your parameters and turns them into generic request options that can be used in any request library.
<!-- update table of contents by running `npx markdown-toc README.md -i` -->
<!-- toc -->
- [Usage](#usage)
- [API](#api)
- [endpoint()](#endpoint)
- [endpoint.defaults()](#endpointdefaults)
- [endpoint.DEFAULTS](#endpointdefaults)
- [endpoint.merge()](#endpointmerge)
- [endpoint.parse()](#endpointparse)
- [Special cases](#special-cases)
- [The `data` parameter – set request body directly](#the-data-parameter-%E2%80%93-set-request-body-directly)
- [Set parameters for both the URL/query and the request body](#set-parameters-for-both-the-urlquery-and-the-request-body)
- [LICENSE](#license)
<!-- tocstop -->
## Usage
<table>
<tbody valign=top align=left>
<tr><th>
Browsers
</th><td width=100%>
Load <code>@octokit/endpoint</code> directly from <a href="https://cdn.pika.dev">cdn.pika.dev</a>
```html
<script type="module">
import { endpoint } from "https://cdn.pika.dev/@octokit/endpoint";
</script>
```
</td></tr>
<tr><th>
Node
</th><td>
Install with <code>npm install @octokit/endpoint</code>
```js
const { endpoint } = require("@octokit/endpoint");
// or: import { endpoint } from "@octokit/endpoint";
```
</td></tr>
</tbody>
</table>
Example for [List organization repositories](https://developer.github.com/v3/repos/#list-organization-repositories)
```js
const requestOptions = endpoint("GET /orgs/:org/repos", {
headers: {
authorization: "token 0000000000000000000000000000000000000001"
},
org: "octokit",
type: "private"
});
```
The resulting `requestOptions` looks as follows
```json
{
"method": "GET",
"url": "https://api.github.com/orgs/octokit/repos?type=private",
"headers": {
"accept": "application/vnd.github.v3+json",
"authorization": "token 0000000000000000000000000000000000000001",
"user-agent": "octokit/endpoint.js v1.2.3"
}
}
```
You can pass `requestOptions` to commen request libraries
```js
const { url, ...options } = requestOptions;
// using with fetch (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
fetch(url, options);
// using with request (https://github.com/request/request)
request(requestOptions);
// using with got (https://github.com/sindresorhus/got)
got[options.method](url, options);
// using with axios
axios(requestOptions);
```
## API
### `endpoint(route, options)` or `endpoint(options)`
<table>
<thead align=left>
<tr>
<th>
name
</th>
<th>
type
</th>
<th width=100%>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th>
<code>route</code>
</th>
<td>
String
</td>
<td>
If set, it has to be a string consisting of URL and the request method, e.g., <code>GET /orgs/:org</code>. If it’s set to a URL, only the method defaults to <code>GET</code>.
</td>
</tr>
<tr>
<th>
<code>options.method</code>
</th>
<td>
String
</td>
<td>
<strong>Required unless <code>route</code> is set.</strong> Any supported <a href="https://developer.github.com/v3/#http-verbs">http verb</a>. <em>Defaults to <code>GET</code></em>.
</td>
</tr>
<tr>
<th>
<code>options.url</code>
</th>
<td>
String
</td>
<td>
<strong>Required unless <code>route</code> is set.</strong> A path or full URL which may contain <code>:variable</code> or <code>{variable}</code> placeholders,
e.g., <code>/orgs/:org/repos</code>. The <code>url</code> is parsed using <a href="https://github.com/bramstein/url-template">url-template</a>.
</td>
</tr>
<tr>
<th>
<code>options.baseUrl</code>
</th>
<td>
String
</td>
<td>
<em>Defaults to <code>https://api.github.com</code></em>.
</td>
</tr>
<tr>
<th>
<code>options.headers</code>
</th>
<td>
Object
</td>
<td>
Custom headers. Passed headers are merged with defaults:<br>
<em><code>headers['user-agent']</code> defaults to <code>octokit-endpoint.js/1.2.3</code> (where <code>1.2.3</code> is the released version)</em>.<br>
<em><code>headers['accept']</code> defaults to <code>application/vnd.github.v3+json</code></em>.<br>
</td>
</tr>
<tr>
<th>
<code>options.mediaType.format</code>
</th>
<td>
String
</td>
<td>
Media type param, such as <code>raw</code>, <code>diff</code>, or <code>text+json</code>. See <a href="https://developer.github.com/v3/media/">Media Types</a>. Setting <code>options.mediaType.format</code> will amend the <code>headers.accept</code> value.
</td>
</tr>
<tr>
<th>
<code>options.mediaType.previews</code>
</th>
<td>
Array of Strings
</td>
<td>
Name of previews, such as <code>mercy</code>, <code>symmetra</code>, or <code>scarlet-witch</code>. See <a href="https://developer.github.com/v3/previews/">API Previews</a>. If <code>options.mediaType.previews</code> was set as default, the new previews will be merged into the default ones. Setting <code>options.mediaType.previews</code> will amend the <code>headers.accept</code> value. <code>options.mediaType.previews</code> will be merged with an existing array set using <code>.defaults()</code>.
</td>
</tr>
<tr>
<th>
<code>options.data</code>
</th>
<td>
Any
</td>
<td>
Set request body directly instead of setting it to JSON based on additional parameters. See <a href="#data-parameter">"The <code>data</code> parameter"</a> below.
</td>
</tr>
<tr>
<th>
<code>options.request</code>
</th>
<td>
Object
</td>
<td>
Pass custom meta information for the request. The <code>request</code> object will be returned as is.
</td>
</tr>
</tbody>
</table>
All other options will be passed depending on the `method` and `url` options.
1. If the option key has a placeholder in the `url`, it will be used as the replacement. For example, if the passed options are `{url: '/orgs/:org/repos', org: 'foo'}` the returned `options.url` is `https://api.github.com/orgs/foo/repos`.
2. If the `method` is `GET` or `HEAD`, the option is passed as a query parameter.
3. Otherwise, the parameter is passed in the request body as a JSON key.
**Result**
`endpoint()` is a synchronous method and returns an object with the following keys:
<table>
<thead align=left>
<tr>
<th>
key
</th>
<th>
type
</th>
<th width=100%>
description
</th>
</tr>
</thead>
<tbody align=left valign=top>
<tr>
<th><code>method</code></th>
<td>String</td>
<td>The http method. Always lowercase.</td>
</tr>
<tr>
<th><code>url</code></th>
<td>String</td>
<td>The url with placeholders replaced with passed parameters.</td>
</tr>
<tr>
<th><code>headers</code></th>
<td>Object</td>
<td>All header names are lowercased.</td>
</tr>
<tr>
<th><code>body</code></th>
<td>Any</td>
<td>The request body if one is present. Only for <code>PATCH</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code> requests.</td>
</tr>
<tr>
<th><code>request</code></th>
<td>Object</td>
<td>Request meta option, it will be returned as it was passed into <code>endpoint()</code></td>
</tr>
</tbody>
</table>
### `endpoint.defaults()`
Override or set default options. Example:
```js
const request = require("request");
const myEndpoint = require("@octokit/endpoint").defaults({
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
headers: {
"user-agent": "myApp/1.2.3",
authorization: `token 0000000000000000000000000000000000000001`
},
org: "my-project",
per_page: 100
});
request(myEndpoint(`GET /orgs/:org/repos`));
```
You can call `.defaults()` again on the returned method, the defaults will cascade.
```js
const myProjectEndpoint = endpoint.defaults({
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
headers: {
"user-agent": "myApp/1.2.3"
},
org: "my-project"
});
const myProjectEndpointWithAuth = myProjectEndpoint.defaults({
headers: {
authorization: `token 0000000000000000000000000000000000000001`
}
});
```
`myProjectEndpointWithAuth` now defaults the `baseUrl`, `headers['user-agent']`,
`org` and `headers['authorization']` on top of `headers['accept']` that is set
by the global default.
### `endpoint.DEFAULTS`
The current default options.
```js
endpoint.DEFAULTS.baseUrl; // https://api.github.com
const myEndpoint = endpoint.defaults({
baseUrl: "https://github-enterprise.acme-inc.com/api/v3"
});
myEndpoint.DEFAULTS.baseUrl; // https://github-enterprise.acme-inc.com/api/v3
```
### `endpoint.merge(route, options)` or `endpoint.merge(options)`
Get the defaulted endpoint options, but without parsing them into request options:
```js
const myProjectEndpoint = endpoint.defaults({
baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
headers: {
"user-agent": "myApp/1.2.3"
},
org: "my-project"
});
myProjectEndpoint.merge("GET /orgs/:org/repos", {
headers: {
authorization: `token 0000000000000000000000000000000000000001`
},
org: "my-secret-project",
type: "private"
});
// {
// baseUrl: 'https://github-enterprise.acme-inc.com/api/v3',
// method: 'GET',
// url: '/orgs/:org/repos',
// headers: {
// accept: 'application/vnd.github.v3+json',
// authorization: `token 0000000000000000000000000000000000000001`,
// 'user-agent': 'myApp/1.2.3'
// },
// org: 'my-secret-project',
// type: 'private'
// }
```
### `endpoint.parse()`
Stateless method to turn endpoint options into request options. Calling
`endpoint(options)` is the same as calling `endpoint.parse(endpoint.merge(options))`.
## Special cases
<a name="data-parameter"></a>
### The `data` parameter – set request body directly
Some endpoints such as [Render a Markdown document in raw mode](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode) don’t have parameters that are sent as request body keys, instead, the request body needs to be set directly. In these cases, set the `data` parameter.
```js
const options = endpoint("POST /markdown/raw", {
data: "Hello world github/linguist#1 **cool**, and #1!",
headers: {
accept: "text/html;charset=utf-8",
"content-type": "text/plain"
}
});
// options is
// {
// method: 'post',
// url: 'https://api.github.com/markdown/raw',
// headers: {
// accept: 'text/html;charset=utf-8',
// 'content-type': 'text/plain',
// 'user-agent': userAgent
// },
// body: 'Hello world github/linguist#1 **cool**, and #1!'
// }
```
### Set parameters for both the URL/query and the request body
There are API endpoints that accept both query parameters as well as a body. In that case, you need to add the query parameters as templates to `options.url`, as defined in the [RFC 6570 URI Template specification](https://tools.ietf.org/html/rfc6570).
Example
```js
endpoint(
"POST https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
{
name: "example.zip",
label: "short description",
headers: {
"content-type": "text/plain",
"content-length": 14,
authorization: `token 0000000000000000000000000000000000000001`
},
data: "Hello, world!"
}
);
```
## LICENSE
[MIT](LICENSE)
+377
View File
@@ -0,0 +1,377 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var isPlainObject = _interopDefault(require('is-plain-object'));
var universalUserAgent = require('universal-user-agent');
function lowercaseKeys(object) {
if (!object) {
return {};
}
return Object.keys(object).reduce((newObj, key) => {
newObj[key.toLowerCase()] = object[key];
return newObj;
}, {});
}
function mergeDeep(defaults, options) {
const result = Object.assign({}, defaults);
Object.keys(options).forEach(key => {
if (isPlainObject(options[key])) {
if (!(key in defaults)) Object.assign(result, {
[key]: options[key]
});else result[key] = mergeDeep(defaults[key], options[key]);
} else {
Object.assign(result, {
[key]: options[key]
});
}
});
return result;
}
function merge(defaults, route, options) {
if (typeof route === "string") {
let [method, url] = route.split(" ");
options = Object.assign(url ? {
method,
url
} : {
url: method
}, options);
} else {
options = route || {};
} // lowercase header names before merging with defaults to avoid duplicates
options.headers = lowercaseKeys(options.headers);
const mergedOptions = mergeDeep(defaults || {}, options); // mediaType.previews arrays are merged, instead of overwritten
if (defaults && defaults.mediaType.previews.length) {
mergedOptions.mediaType.previews = defaults.mediaType.previews.filter(preview => !mergedOptions.mediaType.previews.includes(preview)).concat(mergedOptions.mediaType.previews);
}
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map(preview => preview.replace(/-preview/, ""));
return mergedOptions;
}
function addQueryParameters(url, parameters) {
const separator = /\?/.test(url) ? "&" : "?";
const names = Object.keys(parameters);
if (names.length === 0) {
return url;
}
return url + separator + names.map(name => {
if (name === "q") {
return "q=" + parameters.q.split("+").map(encodeURIComponent).join("+");
}
return `${name}=${encodeURIComponent(parameters[name])}`;
}).join("&");
}
const urlVariableRegex = /\{[^}]+\}/g;
function removeNonChars(variableName) {
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
}
function extractUrlVariableNames(url) {
const matches = url.match(urlVariableRegex);
if (!matches) {
return [];
}
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
}
function omit(object, keysToOmit) {
return Object.keys(object).filter(option => !keysToOmit.includes(option)).reduce((obj, key) => {
obj[key] = object[key];
return obj;
}, {});
}
// Based on https://github.com/bramstein/url-template, licensed under BSD
// TODO: create separate package.
//
// Copyright (c) 2012-2014, Bram Stein
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* istanbul ignore file */
function encodeReserved(str) {
return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) {
if (!/%[0-9A-Fa-f]/.test(part)) {
part = encodeURI(part).replace(/%5B/g, "[").replace(/%5D/g, "]");
}
return part;
}).join("");
}
function encodeUnreserved(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
});
}
function encodeValue(operator, value, key) {
value = operator === "+" || operator === "#" ? encodeReserved(value) : encodeUnreserved(value);
if (key) {
return encodeUnreserved(key) + "=" + value;
} else {
return value;
}
}
function isDefined(value) {
return value !== undefined && value !== null;
}
function isKeyOperator(operator) {
return operator === ";" || operator === "&" || operator === "?";
}
function getValues(context, operator, key, modifier) {
var value = context[key],
result = [];
if (isDefined(value) && value !== "") {
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
value = value.toString();
if (modifier && modifier !== "*") {
value = value.substring(0, parseInt(modifier, 10));
}
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
} else {
if (modifier === "*") {
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
});
} else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
result.push(encodeValue(operator, value[k], k));
}
});
}
} else {
const tmp = [];
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
tmp.push(encodeValue(operator, value));
});
} else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
tmp.push(encodeUnreserved(k));
tmp.push(encodeValue(operator, value[k].toString()));
}
});
}
if (isKeyOperator(operator)) {
result.push(encodeUnreserved(key) + "=" + tmp.join(","));
} else if (tmp.length !== 0) {
result.push(tmp.join(","));
}
}
}
} else {
if (operator === ";") {
if (isDefined(value)) {
result.push(encodeUnreserved(key));
}
} else if (value === "" && (operator === "&" || operator === "?")) {
result.push(encodeUnreserved(key) + "=");
} else if (value === "") {
result.push("");
}
}
return result;
}
function parseUrl(template) {
return {
expand: expand.bind(null, template)
};
}
function expand(template, context) {
var operators = ["+", "#", ".", "/", ";", "?", "&"];
return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) {
if (expression) {
let operator = "";
const values = [];
if (operators.indexOf(expression.charAt(0)) !== -1) {
operator = expression.charAt(0);
expression = expression.substr(1);
}
expression.split(/,/g).forEach(function (variable) {
var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
values.push(getValues(context, operator, tmp[1], tmp[2] || tmp[3]));
});
if (operator && operator !== "+") {
var separator = ",";
if (operator === "?") {
separator = "&";
} else if (operator !== "#") {
separator = operator;
}
return (values.length !== 0 ? operator : "") + values.join(separator);
} else {
return values.join(",");
}
} else {
return encodeReserved(literal);
}
});
}
function parse(options) {
// https://fetch.spec.whatwg.org/#methods
let method = options.method.toUpperCase(); // replace :varname with {varname} to make it RFC 6570 compatible
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
let headers = Object.assign({}, options.headers);
let body;
let parameters = omit(options, ["method", "baseUrl", "url", "headers", "request", "mediaType"]); // extract variable names from URL to calculate remaining variables later
const urlVariableNames = extractUrlVariableNames(url);
url = parseUrl(url).expand(parameters);
if (!/^http/.test(url)) {
url = options.baseUrl + url;
}
const omittedParameters = Object.keys(options).filter(option => urlVariableNames.includes(option)).concat("baseUrl");
const remainingParameters = omit(parameters, omittedParameters);
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
if (!isBinaryRequset) {
if (options.mediaType.format) {
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
headers.accept = headers.accept.split(/,/).map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`)).join(",");
}
if (options.mediaType.previews.length) {
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
headers.accept = previewsFromAcceptHeader.concat(options.mediaType.previews).map(preview => {
const format = options.mediaType.format ? `.${options.mediaType.format}` : "+json";
return `application/vnd.github.${preview}-preview${format}`;
}).join(",");
}
} // for GET/HEAD requests, set URL query parameters from remaining parameters
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
if (["GET", "HEAD"].includes(method)) {
url = addQueryParameters(url, remainingParameters);
} else {
if ("data" in remainingParameters) {
body = remainingParameters.data;
} else {
if (Object.keys(remainingParameters).length) {
body = remainingParameters;
} else {
headers["content-length"] = 0;
}
}
} // default content-type for JSON if body is set
if (!headers["content-type"] && typeof body !== "undefined") {
headers["content-type"] = "application/json; charset=utf-8";
} // GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
// fetch does not allow to set `content-length` header, but we can set body to an empty string
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
body = "";
} // Only return body/request keys if present
return Object.assign({
method,
url,
headers
}, typeof body !== "undefined" ? {
body
} : null, options.request ? {
request: options.request
} : null);
}
function endpointWithDefaults(defaults, route, options) {
return parse(merge(defaults, route, options));
}
function withDefaults(oldDefaults, newDefaults) {
const DEFAULTS = merge(oldDefaults, newDefaults);
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
return Object.assign(endpoint, {
DEFAULTS,
defaults: withDefaults.bind(null, DEFAULTS),
merge: merge.bind(null, DEFAULTS),
parse
});
}
const VERSION = "0.0.0-development";
const userAgent = `octokit-endpoint.js/${VERSION} ${universalUserAgent.getUserAgent()}`;
const DEFAULTS = {
method: "GET",
baseUrl: "https://api.github.com",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": userAgent
},
mediaType: {
format: "",
previews: []
}
};
const endpoint = withDefaults(null, DEFAULTS);
exports.endpoint = endpoint;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../dist-src/util/lowercase-keys.js","../dist-src/util/merge-deep.js","../dist-src/merge.js","../dist-src/util/add-query-parameters.js","../dist-src/util/extract-url-variable-names.js","../dist-src/util/omit.js","../dist-src/util/url-template.js","../dist-src/parse.js","../dist-src/endpoint-with-defaults.js","../dist-src/with-defaults.js","../dist-src/version.js","../dist-src/defaults.js","../dist-src/index.js"],"sourcesContent":["export function lowercaseKeys(object) {\n if (!object) {\n return {};\n }\n return Object.keys(object).reduce((newObj, key) => {\n newObj[key.toLowerCase()] = object[key];\n return newObj;\n }, {});\n}\n","import isPlainObject from \"is-plain-object\";\nexport function mergeDeep(defaults, options) {\n const result = Object.assign({}, defaults);\n Object.keys(options).forEach(key => {\n if (isPlainObject(options[key])) {\n if (!(key in defaults))\n Object.assign(result, { [key]: options[key] });\n else\n result[key] = mergeDeep(defaults[key], options[key]);\n }\n else {\n Object.assign(result, { [key]: options[key] });\n }\n });\n return result;\n}\n","import { lowercaseKeys } from \"./util/lowercase-keys\";\nimport { mergeDeep } from \"./util/merge-deep\";\nexport function merge(defaults, route, options) {\n if (typeof route === \"string\") {\n let [method, url] = route.split(\" \");\n options = Object.assign(url ? { method, url } : { url: method }, options);\n }\n else {\n options = route || {};\n }\n // lowercase header names before merging with defaults to avoid duplicates\n options.headers = lowercaseKeys(options.headers);\n const mergedOptions = mergeDeep(defaults || {}, options);\n // mediaType.previews arrays are merged, instead of overwritten\n if (defaults && defaults.mediaType.previews.length) {\n mergedOptions.mediaType.previews = defaults.mediaType.previews\n .filter(preview => !mergedOptions.mediaType.previews.includes(preview))\n .concat(mergedOptions.mediaType.previews);\n }\n mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map((preview) => preview.replace(/-preview/, \"\"));\n return mergedOptions;\n}\n","export function addQueryParameters(url, parameters) {\n const separator = /\\?/.test(url) ? \"&\" : \"?\";\n const names = Object.keys(parameters);\n if (names.length === 0) {\n return url;\n }\n return (url +\n separator +\n names\n .map(name => {\n if (name === \"q\") {\n return (\"q=\" +\n parameters\n .q.split(\"+\")\n .map(encodeURIComponent)\n .join(\"+\"));\n }\n return `${name}=${encodeURIComponent(parameters[name])}`;\n })\n .join(\"&\"));\n}\n","const urlVariableRegex = /\\{[^}]+\\}/g;\nfunction removeNonChars(variableName) {\n return variableName.replace(/^\\W+|\\W+$/g, \"\").split(/,/);\n}\nexport function extractUrlVariableNames(url) {\n const matches = url.match(urlVariableRegex);\n if (!matches) {\n return [];\n }\n return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);\n}\n","export function omit(object, keysToOmit) {\n return Object.keys(object)\n .filter(option => !keysToOmit.includes(option))\n .reduce((obj, key) => {\n obj[key] = object[key];\n return obj;\n }, {});\n}\n","// Based on https://github.com/bramstein/url-template, licensed under BSD\n// TODO: create separate package.\n//\n// Copyright (c) 2012-2014, Bram Stein\n// All rights reserved.\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n// notice, this list of conditions and the following disclaimer in the\n// documentation and/or other materials provided with the distribution.\n// 3. The name of the author may not be used to endorse or promote products\n// derived from this software without specific prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFILine truncated
+15
View File
@@ -0,0 +1,15 @@
import { getUserAgent } from "universal-user-agent";
import { VERSION } from "./version";
const userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`;
export const DEFAULTS = {
method: "GET",
baseUrl: "https://api.github.com",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": userAgent
},
mediaType: {
format: "",
previews: []
}
};
+5
View File
@@ -0,0 +1,5 @@
import { merge } from "./merge";
import { parse } from "./parse";
export function endpointWithDefaults(defaults, route, options) {
return parse(merge(defaults, route, options));
}
View File
Whitespace-only changes.
+3
View File
@@ -0,0 +1,3 @@
import { withDefaults } from "./with-defaults";
import { DEFAULTS } from "./defaults";
export const endpoint = withDefaults(null, DEFAULTS);
+22
View File
@@ -0,0 +1,22 @@
import { lowercaseKeys } from "./util/lowercase-keys";
import { mergeDeep } from "./util/merge-deep";
export function merge(defaults, route, options) {
if (typeof route === "string") {
let [method, url] = route.split(" ");
options = Object.assign(url ? { method, url } : { url: method }, options);
}
else {
options = route || {};
}
// lowercase header names before merging with defaults to avoid duplicates
options.headers = lowercaseKeys(options.headers);
const mergedOptions = mergeDeep(defaults || {}, options);
// mediaType.previews arrays are merged, instead of overwritten
if (defaults && defaults.mediaType.previews.length) {
mergedOptions.mediaType.previews = defaults.mediaType.previews
.filter(preview => !mergedOptions.mediaType.previews.includes(preview))
.concat(mergedOptions.mediaType.previews);
}
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map((preview) => preview.replace(/-preview/, ""));
return mergedOptions;
}
+81
View File
@@ -0,0 +1,81 @@
import { addQueryParameters } from "./util/add-query-parameters";
import { extractUrlVariableNames } from "./util/extract-url-variable-names";
import { omit } from "./util/omit";
import { parseUrl } from "./util/url-template";
export function parse(options) {
// https://fetch.spec.whatwg.org/#methods
let method = options.method.toUpperCase();
// replace :varname with {varname} to make it RFC 6570 compatible
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
let headers = Object.assign({}, options.headers);
let body;
let parameters = omit(options, [
"method",
"baseUrl",
"url",
"headers",
"request",
"mediaType"
]);
// extract variable names from URL to calculate remaining variables later
const urlVariableNames = extractUrlVariableNames(url);
url = parseUrl(url).expand(parameters);
if (!/^http/.test(url)) {
url = options.baseUrl + url;
}
const omittedParameters = Object.keys(options)
.filter(option => urlVariableNames.includes(option))
.concat("baseUrl");
const remainingParameters = omit(parameters, omittedParameters);
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
if (!isBinaryRequset) {
if (options.mediaType.format) {
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
headers.accept = headers.accept
.split(/,/)
.map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`))
.join(",");
}
if (options.mediaType.previews.length) {
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
headers.accept = previewsFromAcceptHeader
.concat(options.mediaType.previews)
.map(preview => {
const format = options.mediaType.format
? `.${options.mediaType.format}`
: "+json";
return `application/vnd.github.${preview}-preview${format}`;
})
.join(",");
}
}
// for GET/HEAD requests, set URL query parameters from remaining parameters
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
if (["GET", "HEAD"].includes(method)) {
url = addQueryParameters(url, remainingParameters);
}
else {
if ("data" in remainingParameters) {
body = remainingParameters.data;
}
else {
if (Object.keys(remainingParameters).length) {
body = remainingParameters;
}
else {
headers["content-length"] = 0;
}
}
}
// default content-type for JSON if body is set
if (!headers["content-type"] && typeof body !== "undefined") {
headers["content-type"] = "application/json; charset=utf-8";
}
// GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
// fetch does not allow to set `content-length` header, but we can set body to an empty string
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
body = "";
}
// Only return body/request keys if present
return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
}
View File
Whitespace-only changes.
+21
View File
@@ -0,0 +1,21 @@
export function addQueryParameters(url, parameters) {
const separator = /\?/.test(url) ? "&" : "?";
const names = Object.keys(parameters);
if (names.length === 0) {
return url;
}
return (url +
separator +
names
.map(name => {
if (name === "q") {
return ("q=" +
parameters
.q.split("+")
.map(encodeURIComponent)
.join("+"));
}
return `${name}=${encodeURIComponent(parameters[name])}`;
})
.join("&"));
}
@@ -0,0 +1,11 @@
const urlVariableRegex = /\{[^}]+\}/g;
function removeNonChars(variableName) {
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
}
export function extractUrlVariableNames(url) {
const matches = url.match(urlVariableRegex);
if (!matches) {
return [];
}
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
}
+9
View File
@@ -0,0 +1,9 @@
export function lowercaseKeys(object) {
if (!object) {
return {};
}
return Object.keys(object).reduce((newObj, key) => {
newObj[key.toLowerCase()] = object[key];
return newObj;
}, {});
}
+16
View File
@@ -0,0 +1,16 @@
import isPlainObject from "is-plain-object";
export function mergeDeep(defaults, options) {
const result = Object.assign({}, defaults);
Object.keys(options).forEach(key => {
if (isPlainObject(options[key])) {
if (!(key in defaults))
Object.assign(result, { [key]: options[key] });
else
result[key] = mergeDeep(defaults[key], options[key]);
}
else {
Object.assign(result, { [key]: options[key] });
}
});
return result;
}
+8
View File
@@ -0,0 +1,8 @@
export function omit(object, keysToOmit) {
return Object.keys(object)
.filter(option => !keysToOmit.includes(option))
.reduce((obj, key) => {
obj[key] = object[key];
return obj;
}, {});
}
+170
View File
@@ -0,0 +1,170 @@
// Based on https://github.com/bramstein/url-template, licensed under BSD
// TODO: create separate package.
//
// Copyright (c) 2012-2014, Bram Stein
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* istanbul ignore file */
function encodeReserved(str) {
return str
.split(/(%[0-9A-Fa-f]{2})/g)
.map(function (part) {
if (!/%[0-9A-Fa-f]/.test(part)) {
part = encodeURI(part)
.replace(/%5B/g, "[")
.replace(/%5D/g, "]");
}
return part;
})
.join("");
}
function encodeUnreserved(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return ("%" +
c
.charCodeAt(0)
.toString(16)
.toUpperCase());
});
}
function encodeValue(operator, value, key) {
value =
operator === "+" || operator === "#"
? encodeReserved(value)
: encodeUnreserved(value);
if (key) {
return encodeUnreserved(key) + "=" + value;
}
else {
return value;
}
}
function isDefined(value) {
return value !== undefined && value !== null;
}
function isKeyOperator(operator) {
return operator === ";" || operator === "&" || operator === "?";
}
function getValues(context, operator, key, modifier) {
var value = context[key], result = [];
if (isDefined(value) && value !== "") {
if (typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean") {
value = value.toString();
if (modifier && modifier !== "*") {
value = value.substring(0, parseInt(modifier, 10));
}
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
}
else {
if (modifier === "*") {
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
});
}
else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
result.push(encodeValue(operator, value[k], k));
}
});
}
}
else {
const tmp = [];
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
tmp.push(encodeValue(operator, value));
});
}
else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
tmp.push(encodeUnreserved(k));
tmp.push(encodeValue(operator, value[k].toString()));
}
});
}
if (isKeyOperator(operator)) {
result.push(encodeUnreserved(key) + "=" + tmp.join(","));
}
else if (tmp.length !== 0) {
result.push(tmp.join(","));
}
}
}
}
else {
if (operator === ";") {
if (isDefined(value)) {
result.push(encodeUnreserved(key));
}
}
else if (value === "" && (operator === "&" || operator === "?")) {
result.push(encodeUnreserved(key) + "=");
}
else if (value === "") {
result.push("");
}
}
return result;
}
export function parseUrl(template) {
return {
expand: expand.bind(null, template)
};
}
function expand(template, context) {
var operators = ["+", "#", ".", "/", ";", "?", "&"];
return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) {
if (expression) {
let operator = "";
const values = [];
if (operators.indexOf(expression.charAt(0)) !== -1) {
operator = expression.charAt(0);
expression = expression.substr(1);
}
expression.split(/,/g).forEach(function (variable) {
var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
values.push(getValues(context, operator, tmp[1], tmp[2] || tmp[3]));
});
if (operator && operator !== "+") {
var separator = ",";
if (operator === "?") {
separator = "&";
}
else if (operator !== "#") {
separator = operator;
}
return (values.length !== 0 ? operator : "") + values.join(separator);
}
else {
return values.join(",");
}
}
else {
return encodeReserved(literal);
}
});
}
+1
View File
@@ -0,0 +1 @@
export const VERSION = "0.0.0-development";
+13
View File
@@ -0,0 +1,13 @@
import { endpointWithDefaults } from "./endpoint-with-defaults";
import { merge } from "./merge";
import { parse } from "./parse";
export function withDefaults(oldDefaults, newDefaults) {
const DEFAULTS = merge(oldDefaults, newDefaults);
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
return Object.assign(endpoint, {
DEFAULTS,
defaults: withDefaults.bind(null, DEFAULTS),
merge: merge.bind(null, DEFAULTS),
parse
});
}
+2
View File
@@ -0,0 +1,2 @@
import { Defaults } from "./types";
export declare const DEFAULTS: Defaults;
@@ -0,0 +1,2 @@
import { Defaults, Endpoint, RequestOptions, Route, Parameters } from "./types";
export declare function endpointWithDefaults(defaults: Defaults, route: Route | Endpoint, options?: Parameters): RequestOptions;
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
export declare const endpoint: import("./types").endpoint;
+2
View File
@@ -0,0 +1,2 @@
import { Defaults, Route, Parameters } from "./types";
export declare function merge(defaults: Defaults | null, route?: Route | Parameters, options?: Parameters): Defaults;
+2
View File
@@ -0,0 +1,2 @@
import { Defaults, RequestOptions } from "./types";
export declare function parse(options: Defaults): RequestOptions;
+150
View File
@@ -0,0 +1,150 @@
import { Routes as KnownRoutes } from "./generated/routes";
export interface endpoint {
/**
* Transforms a GitHub REST API endpoint into generic request options
*
* @param {object} endpoint Must set `method` and `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*/
(options: Endpoint): RequestOptions;
/**
* Transforms a GitHub REST API endpoint into generic request options
*
* @param {string} route Request method + URL. Example: `'GET /orgs/:org'`
* @param {object} [parameters] URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*/
<R extends Route>(route: keyof KnownRoutes | R, options?: R extends keyof KnownRoutes ? KnownRoutes[R][0] & Parameters : Parameters): R extends keyof KnownRoutes ? KnownRoutes[R][1] : RequestOptions;
/**
* Object with current default route and parameters
*/
DEFAULTS: Defaults;
/**
* Returns a new `endpoint` with updated route and parameters
*/
defaults: (newDefaults: Parameters) => endpoint;
merge: {
/**
* Merges current endpoint defaults with passed route and parameters,
* without transforming them into request options.
*
* @param {string} route Request method + URL. Example: `'GET /orgs/:org'`
* @param {object} [parameters] URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*
*/
(route: Route, parameters?: Parameters): Defaults;
/**
* Merges current endpoint defaults with passed route and parameters,
* without transforming them into request options.
*
* @param {object} endpoint Must set `method` and `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*/
(options: Parameters): Defaults;
/**
* Returns current default options.
*
* @deprecated use endpoint.DEFAULTS instead
*/
(): Defaults;
};
/**
* Stateless method to turn endpoint options into request options.
* Calling `endpoint(options)` is the same as calling `endpoint.parse(endpoint.merge(options))`.
*
* @param {object} options `method`, `url`. Plus URL, query or body parameters, as well as `headers`, `mediaType.{format|previews}`, `request`, or `baseUrl`.
*/
parse: (options: Defaults) => RequestOptions;
}
/**
* Request method + URL. Example: `'GET /orgs/:org'`
*/
export declare type Route = string;
/**
* Relative or absolute URL. Examples: `'/orgs/:org'`, `https://example.com/foo/bar`
*/
export declare type Url = string;
/**
* Request method
*/
export declare type Method = "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT";
/**
* Endpoint parameters
*/
export declare type Parameters = {
/**
* Base URL to be used when a relative URL is passed, such as `/orgs/:org`.
* If `baseUrl` is `https://enterprise.acme-inc.com/api/v3`, then the resulting
* `RequestOptions.url` will be `https://enterprise.acme-inc.com/api/v3/orgs/:org`.
*/
baseUrl?: string;
/**
* HTTP headers. Use lowercase keys.
*/
headers?: Headers;
/**
* Media type options, see {@link https://developer.github.com/v3/media/|GitHub Developer Guide}
*/
mediaType?: {
/**
* `json` by default. Can be `raw`, `text`, `html`, `full`, `diff`, `patch`, `sha`, `base64`. Depending on endpoint
*/
format?: string;
/**
* Custom media type names of {@link https://developer.github.com/v3/media/|API Previews} without the `-preview` suffix.
* Example for single preview: `['squirrel-girl']`.
* Example for multiple previews: `['squirrel-girl', 'mister-fantastic']`.
*/
previews?: string[];
};
/**
* Pass custom meta information for the request. The `request` object will be returned as is.
*/
request?: EndpointRequestOptions;
/**
* Any additional parameter will be passed as follows
* 1. URL parameter if `':parameter'` or `{parameter}` is part of `url`
* 2. Query parameter if `method` is `'GET'` or `'HEAD'`
* 3. Request body if `parameter` is `'data'`
* 4. JSON in the request body in the form of `body[parameter]` unless `parameter` key is `'data'`
*/
[parameter: string]: any;
};
export declare type Endpoint = Parameters & {
method: Method;
url: Url;
};
export declare type Defaults = Parameters & {
method: Method;
baseUrl: string;
headers: Headers & {
accept: string;
"user-agent": string;
};
mediaType: {
format: string;
previews: string[];
};
};
export declare type RequestOptions = {
method: Method;
url: Url;
headers: Headers;
body?: any;
request?: EndpointRequestOptions;
};
export declare type Headers = {
/**
* Avoid setting `accept`, use `mediaFormat.{format|previews}` instead.
*/
accept?: string;
/**
* Use `authorization` to send authenticated request, remember `token ` / `bearer ` prefixes. Example: `token 1234567890abcdef1234567890abcdef12345678`
*/
authorization?: string;
/**
* `user-agent` is set do a default and can be overwritten as needed.
*/
"user-agent"?: string;
[header: string]: string | number | undefined;
};
export declare type EndpointRequestOptions = {
[option: string]: any;
};
@@ -0,0 +1,4 @@
export declare function addQueryParameters(url: string, parameters: {
[x: string]: string | undefined;
q?: string;
}): string;
@@ -0,0 +1 @@
export declare function extractUrlVariableNames(url: string): string[];
+5
View File
@@ -0,0 +1,5 @@
export declare function lowercaseKeys(object?: {
[key: string]: any;
}): {
[key: string]: any;
};
+1
View File
@@ -0,0 +1 @@
export declare function mergeDeep(defaults: any, options: any): object;
+5
View File
@@ -0,0 +1,5 @@
export declare function omit(object: {
[key: string]: any;
}, keysToOmit: string[]): {
[key: string]: any;
};
+3
View File
@@ -0,0 +1,3 @@
export declare function parseUrl(template: string): {
expand: (context: object) => string;
};
+1
View File
@@ -0,0 +1 @@
export declare const VERSION = "0.0.0-development";
+2
View File
@@ -0,0 +1,2 @@
import { Defaults, endpoint, Parameters } from "./types";
export declare function withDefaults(oldDefaults: Defaults | null, newDefaults: Parameters): endpoint;
+377
View File
@@ -0,0 +1,377 @@
import isPlainObject from 'is-plain-object';
import { getUserAgent } from 'universal-user-agent';
function lowercaseKeys(object) {
if (!object) {
return {};
}
return Object.keys(object).reduce((newObj, key) => {
newObj[key.toLowerCase()] = object[key];
return newObj;
}, {});
}
function mergeDeep(defaults, options) {
const result = Object.assign({}, defaults);
Object.keys(options).forEach(key => {
if (isPlainObject(options[key])) {
if (!(key in defaults))
Object.assign(result, { [key]: options[key] });
else
result[key] = mergeDeep(defaults[key], options[key]);
}
else {
Object.assign(result, { [key]: options[key] });
}
});
return result;
}
function merge(defaults, route, options) {
if (typeof route === "string") {
let [method, url] = route.split(" ");
options = Object.assign(url ? { method, url } : { url: method }, options);
}
else {
options = route || {};
}
// lowercase header names before merging with defaults to avoid duplicates
options.headers = lowercaseKeys(options.headers);
const mergedOptions = mergeDeep(defaults || {}, options);
// mediaType.previews arrays are merged, instead of overwritten
if (defaults && defaults.mediaType.previews.length) {
mergedOptions.mediaType.previews = defaults.mediaType.previews
.filter(preview => !mergedOptions.mediaType.previews.includes(preview))
.concat(mergedOptions.mediaType.previews);
}
mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map((preview) => preview.replace(/-preview/, ""));
return mergedOptions;
}
function addQueryParameters(url, parameters) {
const separator = /\?/.test(url) ? "&" : "?";
const names = Object.keys(parameters);
if (names.length === 0) {
return url;
}
return (url +
separator +
names
.map(name => {
if (name === "q") {
return ("q=" +
parameters
.q.split("+")
.map(encodeURIComponent)
.join("+"));
}
return `${name}=${encodeURIComponent(parameters[name])}`;
})
.join("&"));
}
const urlVariableRegex = /\{[^}]+\}/g;
function removeNonChars(variableName) {
return variableName.replace(/^\W+|\W+$/g, "").split(/,/);
}
function extractUrlVariableNames(url) {
const matches = url.match(urlVariableRegex);
if (!matches) {
return [];
}
return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);
}
function omit(object, keysToOmit) {
return Object.keys(object)
.filter(option => !keysToOmit.includes(option))
.reduce((obj, key) => {
obj[key] = object[key];
return obj;
}, {});
}
// Based on https://github.com/bramstein/url-template, licensed under BSD
// TODO: create separate package.
//
// Copyright (c) 2012-2014, Bram Stein
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. The name of the author may not be used to endorse or promote products
// derived from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* istanbul ignore file */
function encodeReserved(str) {
return str
.split(/(%[0-9A-Fa-f]{2})/g)
.map(function (part) {
if (!/%[0-9A-Fa-f]/.test(part)) {
part = encodeURI(part)
.replace(/%5B/g, "[")
.replace(/%5D/g, "]");
}
return part;
})
.join("");
}
function encodeUnreserved(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return ("%" +
c
.charCodeAt(0)
.toString(16)
.toUpperCase());
});
}
function encodeValue(operator, value, key) {
value =
operator === "+" || operator === "#"
? encodeReserved(value)
: encodeUnreserved(value);
if (key) {
return encodeUnreserved(key) + "=" + value;
}
else {
return value;
}
}
function isDefined(value) {
return value !== undefined && value !== null;
}
function isKeyOperator(operator) {
return operator === ";" || operator === "&" || operator === "?";
}
function getValues(context, operator, key, modifier) {
var value = context[key], result = [];
if (isDefined(value) && value !== "") {
if (typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean") {
value = value.toString();
if (modifier && modifier !== "*") {
value = value.substring(0, parseInt(modifier, 10));
}
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
}
else {
if (modifier === "*") {
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : ""));
});
}
else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
result.push(encodeValue(operator, value[k], k));
}
});
}
}
else {
const tmp = [];
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
tmp.push(encodeValue(operator, value));
});
}
else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
tmp.push(encodeUnreserved(k));
tmp.push(encodeValue(operator, value[k].toString()));
}
});
}
if (isKeyOperator(operator)) {
result.push(encodeUnreserved(key) + "=" + tmp.join(","));
}
else if (tmp.length !== 0) {
result.push(tmp.join(","));
}
}
}
}
else {
if (operator === ";") {
if (isDefined(value)) {
result.push(encodeUnreserved(key));
}
}
else if (value === "" && (operator === "&" || operator === "?")) {
result.push(encodeUnreserved(key) + "=");
}
else if (value === "") {
result.push("");
}
}
return result;
}
function parseUrl(template) {
return {
expand: expand.bind(null, template)
};
}
function expand(template, context) {
var operators = ["+", "#", ".", "/", ";", "?", "&"];
return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) {
if (expression) {
let operator = "";
const values = [];
if (operators.indexOf(expression.charAt(0)) !== -1) {
operator = expression.charAt(0);
expression = expression.substr(1);
}
expression.split(/,/g).forEach(function (variable) {
var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
values.push(getValues(context, operator, tmp[1], tmp[2] || tmp[3]));
});
if (operator && operator !== "+") {
var separator = ",";
if (operator === "?") {
separator = "&";
}
else if (operator !== "#") {
separator = operator;
}
return (values.length !== 0 ? operator : "") + values.join(separator);
}
else {
return values.join(",");
}
}
else {
return encodeReserved(literal);
}
});
}
function parse(options) {
// https://fetch.spec.whatwg.org/#methods
let method = options.method.toUpperCase();
// replace :varname with {varname} to make it RFC 6570 compatible
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
let headers = Object.assign({}, options.headers);
let body;
let parameters = omit(options, [
"method",
"baseUrl",
"url",
"headers",
"request",
"mediaType"
]);
// extract variable names from URL to calculate remaining variables later
const urlVariableNames = extractUrlVariableNames(url);
url = parseUrl(url).expand(parameters);
if (!/^http/.test(url)) {
url = options.baseUrl + url;
}
const omittedParameters = Object.keys(options)
.filter(option => urlVariableNames.includes(option))
.concat("baseUrl");
const remainingParameters = omit(parameters, omittedParameters);
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
if (!isBinaryRequset) {
if (options.mediaType.format) {
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
headers.accept = headers.accept
.split(/,/)
.map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`))
.join(",");
}
if (options.mediaType.previews.length) {
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
headers.accept = previewsFromAcceptHeader
.concat(options.mediaType.previews)
.map(preview => {
const format = options.mediaType.format
? `.${options.mediaType.format}`
: "+json";
return `application/vnd.github.${preview}-preview${format}`;
})
.join(",");
}
}
// for GET/HEAD requests, set URL query parameters from remaining parameters
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
if (["GET", "HEAD"].includes(method)) {
url = addQueryParameters(url, remainingParameters);
}
else {
if ("data" in remainingParameters) {
body = remainingParameters.data;
}
else {
if (Object.keys(remainingParameters).length) {
body = remainingParameters;
}
else {
headers["content-length"] = 0;
}
}
}
// default content-type for JSON if body is set
if (!headers["content-type"] && typeof body !== "undefined") {
headers["content-type"] = "application/json; charset=utf-8";
}
// GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
// fetch does not allow to set `content-length` header, but we can set body to an empty string
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
body = "";
}
// Only return body/request keys if present
return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
}
function endpointWithDefaults(defaults, route, options) {
return parse(merge(defaults, route, options));
}
function withDefaults(oldDefaults, newDefaults) {
const DEFAULTS = merge(oldDefaults, newDefaults);
const endpoint = endpointWithDefaults.bind(null, DEFAULTS);
return Object.assign(endpoint, {
DEFAULTS,
defaults: withDefaults.bind(null, DEFAULTS),
merge: merge.bind(null, DEFAULTS),
parse
});
}
const VERSION = "0.0.0-development";
const userAgent = `octokit-endpoint.js/${VERSION} ${getUserAgent()}`;
const DEFAULTS = {
method: "GET",
baseUrl: "https://api.github.com",
headers: {
accept: "application/vnd.github.v3+json",
"user-agent": userAgent
},
mediaType: {
format: "",
previews: []
}
};
const endpoint = withDefaults(null, DEFAULTS);
export { endpoint };
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../dist-src/util/lowercase-keys.js","../dist-src/util/merge-deep.js","../dist-src/merge.js","../dist-src/util/add-query-parameters.js","../dist-src/util/extract-url-variable-names.js","../dist-src/util/omit.js","../dist-src/util/url-template.js","../dist-src/parse.js","../dist-src/endpoint-with-defaults.js","../dist-src/with-defaults.js","../dist-src/version.js","../dist-src/defaults.js","../dist-src/index.js"],"sourcesContent":["export function lowercaseKeys(object) {\n if (!object) {\n return {};\n }\n return Object.keys(object).reduce((newObj, key) => {\n newObj[key.toLowerCase()] = object[key];\n return newObj;\n }, {});\n}\n","import isPlainObject from \"is-plain-object\";\nexport function mergeDeep(defaults, options) {\n const result = Object.assign({}, defaults);\n Object.keys(options).forEach(key => {\n if (isPlainObject(options[key])) {\n if (!(key in defaults))\n Object.assign(result, { [key]: options[key] });\n else\n result[key] = mergeDeep(defaults[key], options[key]);\n }\n else {\n Object.assign(result, { [key]: options[key] });\n }\n });\n return result;\n}\n","import { lowercaseKeys } from \"./util/lowercase-keys\";\nimport { mergeDeep } from \"./util/merge-deep\";\nexport function merge(defaults, route, options) {\n if (typeof route === \"string\") {\n let [method, url] = route.split(\" \");\n options = Object.assign(url ? { method, url } : { url: method }, options);\n }\n else {\n options = route || {};\n }\n // lowercase header names before merging with defaults to avoid duplicates\n options.headers = lowercaseKeys(options.headers);\n const mergedOptions = mergeDeep(defaults || {}, options);\n // mediaType.previews arrays are merged, instead of overwritten\n if (defaults && defaults.mediaType.previews.length) {\n mergedOptions.mediaType.previews = defaults.mediaType.previews\n .filter(preview => !mergedOptions.mediaType.previews.includes(preview))\n .concat(mergedOptions.mediaType.previews);\n }\n mergedOptions.mediaType.previews = mergedOptions.mediaType.previews.map((preview) => preview.replace(/-preview/, \"\"));\n return mergedOptions;\n}\n","export function addQueryParameters(url, parameters) {\n const separator = /\\?/.test(url) ? \"&\" : \"?\";\n const names = Object.keys(parameters);\n if (names.length === 0) {\n return url;\n }\n return (url +\n separator +\n names\n .map(name => {\n if (name === \"q\") {\n return (\"q=\" +\n parameters\n .q.split(\"+\")\n .map(encodeURIComponent)\n .join(\"+\"));\n }\n return `${name}=${encodeURIComponent(parameters[name])}`;\n })\n .join(\"&\"));\n}\n","const urlVariableRegex = /\\{[^}]+\\}/g;\nfunction removeNonChars(variableName) {\n return variableName.replace(/^\\W+|\\W+$/g, \"\").split(/,/);\n}\nexport function extractUrlVariableNames(url) {\n const matches = url.match(urlVariableRegex);\n if (!matches) {\n return [];\n }\n return matches.map(removeNonChars).reduce((a, b) => a.concat(b), []);\n}\n","export function omit(object, keysToOmit) {\n return Object.keys(object)\n .filter(option => !keysToOmit.includes(option))\n .reduce((obj, key) => {\n obj[key] = object[key];\n return obj;\n }, {});\n}\n","// Based on https://github.com/bramstein/url-template, licensed under BSD\n// TODO: create separate package.\n//\n// Copyright (c) 2012-2014, Bram Stein\n// All rights reserved.\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n// 1. Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// 2. Redistributions in binary form must reproduce the above copyright\n// notice, this list of conditions and the following disclaimer in the\n// documentation and/or other materials provided with the distribution.\n// 3. The name of the author may not be used to endorse or promote products\n// derived from this software without specific prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFILine truncated
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+119
View File
@@ -0,0 +1,119 @@
# is-plain-object [![NPM version](https://img.shields.io/npm/v/is-plain-object.svg?style=flat)](https://www.npmjs.com/package/is-plain-object) [![NPM monthly downloads](https://img.shields.io/npm/dm/is-plain-object.svg?style=flat)](https://npmjs.org/package/is-plain-object) [![NPM total downloads](https://img.shields.io/npm/dt/is-plain-object.svg?style=flat)](https://npmjs.org/package/is-plain-object) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/is-plain-object.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/is-plain-object)
> Returns true if an object was created by the `Object` constructor.
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
## Install
Install with [npm](https://www.npmjs.com/):
```sh
$ npm install --save is-plain-object
```
Use [isobject](https://github.com/jonschlinkert/isobject) if you only want to check if the value is an object and not an array or null.
## Usage
```js
import isPlainObject from 'is-plain-object';
```
**true** when created by the `Object` constructor.
```js
isPlainObject(Object.create({}));
//=> true
isPlainObject(Object.create(Object.prototype));
//=> true
isPlainObject({foo: 'bar'});
//=> true
isPlainObject({});
//=> true
```
**false** when not created by the `Object` constructor.
```js
isPlainObject(1);
//=> false
isPlainObject(['foo', 'bar']);
//=> false
isPlainObject([]);
//=> false
isPlainObject(new Foo);
//=> false
isPlainObject(null);
//=> false
isPlainObject(Object.create(null));
//=> false
```
## About
<details>
<summary><strong>Contributing</strong></summary>
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
</details>
<details>
<summary><strong>Running Tests</strong></summary>
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
```sh
$ npm install && npm test
```
</details>
<details>
<summary><strong>Building docs</strong></summary>
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
To generate the readme, run the following command:
```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```
</details>
### Related projects
You might also be interested in these projects:
* [is-number](https://www.npmjs.com/package/is-number): Returns true if a number or string value is a finite number. Useful for regex… [more](https://github.com/jonschlinkert/is-number) | [homepage](https://github.com/jonschlinkert/is-number "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.")
* [isobject](https://www.npmjs.com/package/isobject): Returns true if the value is an object and not an array or null. | [homepage](https://github.com/jonschlinkert/isobject "Returns true if the value is an object and not an array or null.")
* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of "Get the native type of a value.")
### Contributors
| **Commits** | **Contributor** |
| --- | --- |
| 19 | [jonschlinkert](https://github.com/jonschlinkert) |
| 6 | [TrySound](https://github.com/TrySound) |
| 6 | [stevenvachon](https://github.com/stevenvachon) |
| 3 | [onokumus](https://github.com/onokumus) |
| 1 | [wtgtybhertgeghgtwtg](https://github.com/wtgtybhertgeghgtwtg) |
### Author
**Jon Schlinkert**
* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
### License
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
***
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
@@ -0,0 +1,48 @@
'use strict';
/*!
* isobject <https://github.com/jonschlinkert/isobject>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false;
}
/*!
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
function isObjectObject(o) {
return isObject(o) === true
&& Object.prototype.toString.call(o) === '[object Object]';
}
function isPlainObject(o) {
var ctor,prot;
if (isObjectObject(o) === false) return false;
// If has modified constructor
ctor = o.constructor;
if (typeof ctor !== 'function') return false;
// If has modified prototype
prot = ctor.prototype;
if (isObjectObject(prot) === false) return false;
// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}
// Most likely a plain Object
return true;
}
module.exports = isPlainObject;
@@ -0,0 +1,3 @@
declare function isPlainObject(o: any): boolean;
export default isPlainObject;
+35
View File
@@ -0,0 +1,35 @@
/*!
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
import isObject from 'isobject';
function isObjectObject(o) {
return isObject(o) === true
&& Object.prototype.toString.call(o) === '[object Object]';
}
export default function isPlainObject(o) {
var ctor,prot;
if (isObjectObject(o) === false) return false;
// If has modified constructor
ctor = o.constructor;
if (typeof ctor !== 'function') return false;
// If has modified prototype
prot = ctor.prototype;
if (isObjectObject(prot) === false) return false;
// If constructor does not have an Object-specific method
if (prot.hasOwnProperty('isPrototypeOf') === false) {
return false;
}
// Most likely a plain Object
return true;
};
@@ -0,0 +1,127 @@
{
"_args": [
[
"is-plain-object@3.0.0",
"/Users/dougtangren/code/rust/action-gh-release"
]
],
"_from": "is-plain-object@3.0.0",
"_id": "is-plain-object@3.0.0",
"_inBundle": false,
"_integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
"_location": "/@octokit/endpoint/is-plain-object",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "is-plain-object@3.0.0",
"name": "is-plain-object",
"escapedName": "is-plain-object",
"rawSpec": "3.0.0",
"saveSpec": null,
"fetchSpec": "3.0.0"
},
"_requiredBy": [
"/@octokit/endpoint"
],
"_resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
"_spec": "3.0.0",
"_where": "/Users/dougtangren/code/rust/action-gh-release",
"author": {
"name": "Jon Schlinkert",
"url": "https://github.com/jonschlinkert"
},
"bugs": {
"url": "https://github.com/jonschlinkert/is-plain-object/issues"
},
"contributors": [
{
"name": "Jon Schlinkert",
"url": "http://twitter.com/jonschlinkert"
},
{
"name": "Osman Nuri Okumuş",
"url": "http://onokumus.com"
},
{
"name": "Steven Vachon",
"url": "https://svachon.com"
},
{
"url": "https://github.com/wtgtybhertgeghgtwtg"
}
],
"dependencies": {
"isobject": "^4.0.0"
},
"description": "Returns true if an object was created by the `Object` constructor.",
"devDependencies": {
"chai": "^4.2.0",
"esm": "^3.2.22",
"gulp-format-md": "^1.0.0",
"mocha": "^6.1.4",
"mocha-headless-chrome": "^2.0.2",
"rollup": "^1.10.1",
"rollup-plugin-node-resolve": "^4.2.3"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.d.ts",
"index.js",
"index.cjs.js"
],
"homepage": "https://github.com/jonschlinkert/is-plain-object",
"keywords": [
"check",
"is",
"is-object",
"isobject",
"javascript",
"kind",
"kind-of",
"object",
"plain",
"type",
"typeof",
"value"
],
"license": "MIT",
"main": "index.cjs.js",
"module": "index.js",
"name": "is-plain-object",
"repository": {
"type": "git",
"url": "git+https://github.com/jonschlinkert/is-plain-object.git"
},
"scripts": {
"build": "rollup -c",
"prepare": "rollup -c",
"test": "npm run test_node && npm run build && npm run test_browser",
"test_browser": "mocha-headless-chrome --args=disable-web-security -f test/browser.html",
"test_node": "mocha -r esm"
},
"types": "index.d.ts",
"verb": {
"toc": false,
"layout": "default",
"tasks": [
"readme"
],
"plugins": [
"gulp-format-md"
],
"related": {
"list": [
"is-number",
"isobject",
"kind-of"
]
},
"lint": {
"reflinks": true
}
},
"version": "3.0.0"
}
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+127
View File
@@ -0,0 +1,127 @@
# isobject [![NPM version](https://img.shields.io/npm/v/isobject.svg?style=flat)](https://www.npmjs.com/package/isobject) [![NPM monthly downloads](https://img.shields.io/npm/dm/isobject.svg?style=flat)](https://npmjs.org/package/isobject) [![NPM total downloads](https://img.shields.io/npm/dt/isobject.svg?style=flat)](https://npmjs.org/package/isobject) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/isobject.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/isobject)
> Returns true if the value is an object and not an array or null.
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
## Install
Install with [npm](https://www.npmjs.com/):
```sh
$ npm install --save isobject
```
Use [is-plain-object](https://github.com/jonschlinkert/is-plain-object) if you want only objects that are created by the `Object` constructor.
## Install
Install with [npm](https://www.npmjs.com/):
```sh
$ npm install isobject
```
## Usage
```js
import isObject from 'isobject';
```
**True**
All of the following return `true`:
```js
isObject({});
isObject(Object.create({}));
isObject(Object.create(Object.prototype));
isObject(Object.create(null));
isObject({});
isObject(new Foo);
isObject(/foo/);
```
**False**
All of the following return `false`:
```js
isObject();
isObject(function () {});
isObject(1);
isObject([]);
isObject(undefined);
isObject(null);
```
## About
<details>
<summary><strong>Contributing</strong></summary>
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
</details>
<details>
<summary><strong>Running Tests</strong></summary>
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
```sh
$ npm install && npm test
```
</details>
<details>
<summary><strong>Building docs</strong></summary>
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
To generate the readme, run the following command:
```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```
</details>
### Related projects
You might also be interested in these projects:
* [extend-shallow](https://www.npmjs.com/package/extend-shallow): Extend an object with the properties of additional objects. node.js/javascript util. | [homepage](https://github.com/jonschlinkert/extend-shallow "Extend an object with the properties of additional objects. node.js/javascript util.")
* [is-plain-object](https://www.npmjs.com/package/is-plain-object): Returns true if an object was created by the `Object` constructor. | [homepage](https://github.com/jonschlinkert/is-plain-object "Returns true if an object was created by the `Object` constructor.")
* [kind-of](https://www.npmjs.com/package/kind-of): Get the native type of a value. | [homepage](https://github.com/jonschlinkert/kind-of "Get the native type of a value.")
* [merge-deep](https://www.npmjs.com/package/merge-deep): Recursively merge values in a javascript object. | [homepage](https://github.com/jonschlinkert/merge-deep "Recursively merge values in a javascript object.")
### Contributors
| **Commits** | **Contributor** |
| --- | --- |
| 30 | [jonschlinkert](https://github.com/jonschlinkert) |
| 8 | [doowb](https://github.com/doowb) |
| 7 | [TrySound](https://github.com/TrySound) |
| 3 | [onokumus](https://github.com/onokumus) |
| 1 | [LeSuisse](https://github.com/LeSuisse) |
| 1 | [tmcw](https://github.com/tmcw) |
| 1 | [ZhouHansen](https://github.com/ZhouHansen) |
### Author
**Jon Schlinkert**
* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
### License
Copyright © 2019, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
***
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on April 28, 2019._
+14
View File
@@ -0,0 +1,14 @@
'use strict';
/*!
* isobject <https://github.com/jonschlinkert/isobject>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false;
}
module.exports = isObject;
+3
View File
@@ -0,0 +1,3 @@
declare function isObject(val: any): boolean;
export default isObject;
+10
View File
@@ -0,0 +1,10 @@
/*!
* isobject <https://github.com/jonschlinkert/isobject>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
export default function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false;
};
+128
View File
@@ -0,0 +1,128 @@
{
"_args": [
[
"isobject@4.0.0",
"/Users/dougtangren/code/rust/action-gh-release"
]
],
"_from": "isobject@4.0.0",
"_id": "isobject@4.0.0",
"_inBundle": false,
"_integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==",
"_location": "/@octokit/endpoint/isobject",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "isobject@4.0.0",
"name": "isobject",
"escapedName": "isobject",
"rawSpec": "4.0.0",
"saveSpec": null,
"fetchSpec": "4.0.0"
},
"_requiredBy": [
"/@octokit/endpoint/is-plain-object"
],
"_resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
"_spec": "4.0.0",
"_where": "/Users/dougtangren/code/rust/action-gh-release",
"author": {
"name": "Jon Schlinkert",
"url": "https://github.com/jonschlinkert"
},
"bugs": {
"url": "https://github.com/jonschlinkert/isobject/issues"
},
"contributors": [
{
"url": "https://github.com/LeSuisse"
},
{
"name": "Brian Woodward",
"url": "https://twitter.com/doowb"
},
{
"name": "Jon Schlinkert",
"url": "http://twitter.com/jonschlinkert"
},
{
"name": "Magnús Dæhlen",
"url": "https://github.com/magnudae"
},
{
"name": "Tom MacWright",
"url": "https://macwright.org"
}
],
"dependencies": {},
"description": "Returns true if the value is an object and not an array or null.",
"devDependencies": {
"esm": "^3.2.22",
"gulp-format-md": "^0.1.9",
"mocha": "^2.4.5",
"rollup": "^1.10.1"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.d.ts",
"index.cjs.js",
"index.js"
],
"homepage": "https://github.com/jonschlinkert/isobject",
"keywords": [
"check",
"is",
"is-object",
"isobject",
"kind",
"kind-of",
"kindof",
"native",
"object",
"type",
"typeof",
"value"
],
"license": "MIT",
"main": "index.cjs.js",
"module": "index.js",
"name": "isobject",
"repository": {
"type": "git",
"url": "git+https://github.com/jonschlinkert/isobject.git"
},
"scripts": {
"build": "rollup -i index.js -o index.cjs.js -f cjs",
"prepublish": "npm run build",
"test": "mocha -r esm"
},
"types": "index.d.ts",
"verb": {
"related": {
"list": [
"extend-shallow",
"is-plain-object",
"kind-of",
"merge-deep"
]
},
"toc": false,
"layout": "default",
"tasks": [
"readme"
],
"plugins": [
"gulp-format-md"
],
"lint": {
"reflinks": true
},
"reflinks": [
"verb"
]
},
"version": "4.0.0"
}
@@ -0,0 +1,7 @@
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,25 @@
# universal-user-agent
> Get a user agent string in both browser and node
[![@latest](https://img.shields.io/npm/v/universal-user-agent.svg)](https://www.npmjs.com/package/universal-user-agent)
[![Build Status](https://travis-ci.com/gr2m/universal-user-agent.svg?branch=master)](https://travis-ci.com/gr2m/universal-user-agent)
[![Greenkeeper](https://badges.greenkeeper.io/gr2m/universal-user-agent.svg)](https://greenkeeper.io/)
```js
const { getUserAgent } = require("universal-user-agent");
// or import { getUserAgent } from "universal-user-agent";
const userAgent = getUserAgent();
// userAgent will look like this
// in browser: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0"
// in node: Node.js/v8.9.4 (macOS High Sierra; x64)
```
## Credits
The Node implementation was originally inspired by [default-user-agent](https://www.npmjs.com/package/default-user-agent).
## License
[ISC](LICENSE.md)
@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var osName = _interopDefault(require('os-name'));
function getUserAgent() {
try {
return `Node.js/${process.version.substr(1)} (${osName()}; ${process.arch})`;
} catch (error) {
if (/wmic os get Caption/.test(error.message)) {
return "Windows <version undetectable>";
}
throw error;
}
}
exports.getUserAgent = getUserAgent;
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../dist-src/node.js"],"sourcesContent":["import osName from \"os-name\";\nexport function getUserAgent() {\n try {\n return `Node.js/${process.version.substr(1)} (${osName()}; ${process.arch})`;\n }\n catch (error) {\n if (/wmic os get Caption/.test(error.message)) {\n return \"Windows <version undetectable>\";\n }\n throw error;\n }\n}\n"],"names":["getUserAgent","process","version","substr","osName","arch","error","test","message"],"mappings":";;;;;;;;AACO,SAASA,YAAT,GAAwB;MACvB;WACQ,WAAUC,OAAO,CAACC,OAAR,CAAgBC,MAAhB,CAAuB,CAAvB,CAA0B,KAAIC,MAAM,EAAG,KAAIH,OAAO,CAACI,IAAK,GAA1E;GADJ,CAGA,OAAOC,KAAP,EAAc;QACN,sBAAsBC,IAAtB,CAA2BD,KAAK,CAACE,OAAjC,CAAJ,EAA+C;aACpC,gCAAP;;;UAEEF,KAAN;;;;;;"}
Loaded 100 of 476 files, more files were not shown because too many files have changed in this diff. Show more