mirror of
https://github.com/fjogeleit/http-request-action.git
synced 2025-04-23 23:24:32 +00:00
Compare commits
192 commits
Author | SHA1 | Date | |
---|---|---|---|
|
50734d6ff5 | ||
|
e5f229f068 | ||
|
1709f318cd | ||
|
5c400e2bc4 | ||
|
b12240f543 | ||
|
90fd7d3206 | ||
|
18930d9c3a | ||
|
73373685ae | ||
|
5419a58b02 | ||
|
75020ad6eb | ||
|
465f4de861 | ||
|
cfb5583910 | ||
|
23ad54bcd1 | ||
|
1f693e5f61 | ||
|
4ea8974961 | ||
|
4d0fdb4907 | ||
|
93461a85b6 | ||
|
6b27404bb5 | ||
|
bc28d96e05 | ||
|
2f69e39476 | ||
|
9fa4000143 | ||
|
9803f436f3 | ||
|
bf78da1411 | ||
|
c54053fb4a | ||
|
46e3792733 | ||
|
4a50afee6f | ||
|
04043b9aef | ||
|
07eceb44a4 | ||
|
5cfc483290 | ||
|
53f5db2650 | ||
|
97bb93c5b1 | ||
|
64c456606f | ||
|
62761453c7 | ||
|
aeef78bb14 | ||
|
44816be1ea | ||
|
dea4657059 | ||
|
ae65a272d9 | ||
|
6cbe966de9 | ||
|
1e440b8b8c | ||
|
7d4a18ad25 | ||
|
ed8a1c36db | ||
|
8af2803109 | ||
|
8537e58734 | ||
|
74e0e96181 | ||
|
2bb8059d00 | ||
|
bfbe4dd6af | ||
|
7c708e96af | ||
|
f9dc1a8d4b | ||
|
33a4d079d7 | ||
|
0b6ec5eadd | ||
|
897b6a3c96 | ||
|
363da44e0a | ||
|
1a131d17cc | ||
|
72a0a5b93e | ||
|
606bb16fb9 | ||
|
517601f732 | ||
|
c9a231b621 | ||
|
2e6550f5bd | ||
|
caab55e3d8 | ||
|
997aeb8de8 | ||
|
0bd00a33db | ||
|
a665541d9c | ||
|
e23645bd9b | ||
|
897543ff26 | ||
|
3fee944184 | ||
|
c23f0d6631 | ||
|
6dd87961de | ||
|
d81c81a128 | ||
|
2d6a2f17dc | ||
|
25a5a55111 | ||
|
e1affb38cd | ||
|
3abafba399 | ||
|
17b52dc74f | ||
|
04de458128 | ||
|
6769207b0b | ||
|
37cfb73c02 | ||
|
7273a89218 | ||
|
d08c0d1c88 | ||
|
9580c192fd | ||
|
41c615e3c0 | ||
|
845e3400a7 | ||
|
6871522388 | ||
|
17c1694300 | ||
|
baf3fe8b8b | ||
|
3d8af5c847 | ||
|
35986be8f9 | ||
|
3c98f6caf2 | ||
|
389f30ee3a | ||
|
e9345a1e67 | ||
|
894ad39332 | ||
|
25fb88fa43 | ||
|
eab8015483 | ||
|
f62db86b8d | ||
|
ef8ec33f46 | ||
|
c431724973 | ||
|
a9fc010566 | ||
|
8cbbec6c93 | ||
|
20c7f757a1 | ||
|
5e4203c2ac | ||
|
6659346e66 | ||
|
fc0207c5aa | ||
|
394beeafea | ||
|
e8dd067b83 | ||
|
a7bd4f21e5 | ||
|
2e2dec74b5 | ||
|
5f7d5f7c54 | ||
|
991c07d6d9 | ||
|
5500a62817 | ||
|
81ecdf1750 | ||
|
04b426e25f | ||
|
fc435761fc | ||
|
12f71e545a | ||
|
edf33a9d70 | ||
|
4ae1dfba85 | ||
|
2c712a0557 | ||
|
0f4905efb7 | ||
|
dfc2f7ac6f | ||
|
52919e91b0 | ||
|
21b59cc25d | ||
|
39d8207c44 | ||
|
74e83dd964 | ||
|
00ffa5ecd5 | ||
|
d724e04050 | ||
|
cb13434243 | ||
|
e7440a202a | ||
|
d06672e4c2 | ||
|
322dbb7bdb | ||
|
3da643f26a | ||
|
a9b5bad232 | ||
|
9e40d70ab2 | ||
|
e55086ca3f | ||
|
86014825e9 | ||
|
575a0b6560 | ||
|
56da042223 | ||
|
cc3aff9cbe | ||
|
c4ec44ca3e | ||
|
b497d195dc | ||
|
d00a8759d6 | ||
|
05a08b70e2 | ||
|
6c12bc1f79 | ||
|
6796716641 | ||
|
dac2a9ae42 | ||
|
79a8b8af48 | ||
|
5bbd839c3e | ||
|
cf482a5e80 | ||
|
76415c3c59 | ||
|
3a818e40e8 | ||
|
daa3a7f756 | ||
|
7f60d0a379 | ||
|
9adf34b765 | ||
|
0d5a8b7b31 | ||
|
a8547fbde9 | ||
|
a8bcd97403 | ||
|
ce3525d612 | ||
|
50750c1420 | ||
|
fd5cf60c69 | ||
|
2214f2de10 | ||
|
9e07856983 | ||
|
df4c18fdd5 | ||
|
4cbc7a46b2 | ||
|
cce3f3d779 | ||
|
52ba495021 | ||
|
df00cdf429 | ||
|
e3313c1a5f | ||
|
d4c0bee13c | ||
|
435fe1dbc8 | ||
|
35336be18d | ||
|
f986377e36 | ||
|
046e838b3a | ||
|
31fad16908 | ||
|
5c4179dc69 | ||
|
d45f6649f6 | ||
|
f683177370 | ||
|
a6980b2ca5 | ||
|
70ee000b97 | ||
|
5e30e204fc | ||
|
82d22dd60f | ||
|
1ea54adf35 | ||
|
8e939c608a | ||
|
7c5a3f2e70 | ||
|
78bba76cbe | ||
|
3e3e6b3eec | ||
|
0929a0c636 | ||
|
bd043fe286 | ||
|
7626a13e42 | ||
|
48dc3972df | ||
|
84e61f1a56 | ||
|
42677b964e | ||
|
b6bb4fa030 | ||
|
de202bb090 | ||
|
eff73a48f7 | ||
|
f91c5933c4 |
19 changed files with 35913 additions and 2410 deletions
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
35
.github/workflows/build-action.yml
vendored
Normal file
35
.github/workflows/build-action.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
name: Build Action
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: The branch
|
||||
type: string
|
||||
default: main
|
||||
required: true
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
- name: Build Action
|
||||
run: |
|
||||
npm run build
|
||||
- name: Update dist
|
||||
run: |
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add ./dist &&
|
||||
git commit -m "Update dist"
|
||||
git push origin HEAD:${{ inputs.ref }}
|
71
.github/workflows/ci.yml
vendored
Normal file
71
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'releases/*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: >
|
||||
github.event_name == 'pull_request' &&
|
||||
github.event.pull_request.user.login == 'dependabot[bot]'
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: ref
|
||||
run: |
|
||||
if [[ -n '${{ github.event.ref }}' ]]; then
|
||||
branch="${{ github.event.ref }}"
|
||||
echo "branch=$branch" >> $GITHUB_OUTPUT
|
||||
else
|
||||
branch="${{ github.event.pull_request.head.ref }}"
|
||||
echo "branch=$branch" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.branch }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
npm ci
|
||||
- name: Build Action
|
||||
run: |
|
||||
npm run build
|
||||
- name: Update dist
|
||||
run: |
|
||||
git config user.name 'github-actions[bot]'
|
||||
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add ./dist
|
||||
if ! git diff --quiet dist; then
|
||||
git commit -m "Update dist"
|
||||
git push origin HEAD:${{ steps.ref.outputs.branch }}
|
||||
fi
|
||||
integrity:
|
||||
if: >
|
||||
!failure() &&
|
||||
!cancelled()
|
||||
needs:
|
||||
- build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.17.0'
|
||||
- name: Build action
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
- name: Repository Integrity Check
|
||||
run: |
|
||||
git diff --quiet dist
|
337
.github/workflows/it-tests.yml
vendored
Normal file
337
.github/workflows/it-tests.yml
vendored
Normal file
|
@ -0,0 +1,337 @@
|
|||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
|
||||
test-method-get-on-existing-url:
|
||||
name: "IT Test - Request Postman Echo GET"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with GET and a valid URL
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/get'
|
||||
method: 'GET'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-method-post-on-existing-url:
|
||||
name: "IT Test - Request Postman Echo POST"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with POST using valid data
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: "https://postman-echo.com/post"
|
||||
method: 'POST'
|
||||
data: '{ "key": "value" }'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-method-post-on-existing-url-with-unescaped-newline:
|
||||
name: "IT Test - Request Postman Echo POST with Unescaped Newline"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with POST using unescaped new line within data
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: "https://postman-echo.com/post"
|
||||
method: 'POST'
|
||||
escapeData: 'true'
|
||||
data: >-
|
||||
{
|
||||
"key":"multi line\ntest
|
||||
text"
|
||||
}
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-basic-auth:
|
||||
name: "IT Test - Request Postman Echo BasicAuth"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with valid BasicAuth parameters
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/basic-auth'
|
||||
method: 'GET'
|
||||
username: 'postman'
|
||||
password: 'password'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200 as this URL exists
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-input-ignore-failure-code-404:
|
||||
name: "IT Test - Request Postman Echo with 404 Response and ignore failure code"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with unknown URL and ignoreStatusCode 404 for it
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/status/404'
|
||||
method: 'GET'
|
||||
ignoreStatusCodes: '404'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must 404
|
||||
with:
|
||||
expected: '404'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then the outcome value must be success as the error 404 is ignored
|
||||
with:
|
||||
expected: 'success'
|
||||
actual: ${{ steps.execution.outcome }}
|
||||
comparison: exact
|
||||
|
||||
test-input-ignore-failure-multiple-codes-401-404:
|
||||
name: "IT Test - Request Postman Echo with 404 Response and ignore failure code"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with unknown URL and ignore status codes 401,404
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/status/404'
|
||||
method: 'GET'
|
||||
ignoreStatusCodes: '401,404'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 404
|
||||
with:
|
||||
expected: '404'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then the outcome value must be success as the error 404 is ignored
|
||||
with:
|
||||
expected: 'success'
|
||||
actual: ${{ steps.execution.outcome }}
|
||||
comparison: exact
|
||||
|
||||
test-input-files:
|
||||
name: "IT Test - Request Postman Echo POST Multipart"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Create Test File
|
||||
run: |
|
||||
echo "test" > testfile.txt
|
||||
- name: Given the gh-action is used with file and data
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
data: '{ "key": "value" }'
|
||||
files: '{ "file": "${{ github.workspace }}/testfile.txt" }'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-input-responseFile:
|
||||
name: "IT Test - Request Postman Echo POST and persist response"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Create Test File
|
||||
run: |
|
||||
echo "test" > testfile2.txt
|
||||
- name: Given the gh-action is used with file and responseFile
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
file: "${{ github.workspace }}/testfile2.txt"
|
||||
responseFile: "${{ github.workspace }}/response.json"
|
||||
|
||||
- name: Output responseFile
|
||||
id: execution-response-file
|
||||
run: |
|
||||
echo "response_content=$(cat ${{ github.workspace }}/response.json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.response_content value must include
|
||||
with:
|
||||
expected: '{"args":{},"data":"test\n","files":{},"form":{},"headers":{"host":"postman-echo.com",'
|
||||
actual: ${{ steps.execution-response-file.outputs.response_content }}
|
||||
comparison: contains
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.response_content value must include
|
||||
with:
|
||||
expected: '"accept":"application/json, text/plain, */*","content-type":"application/json","user-agent"'
|
||||
actual: ${{ steps.execution-response-file.outputs.response_content }}
|
||||
comparison: contains
|
||||
|
||||
test-input-files-without-data:
|
||||
name: "IT Test - Request Postman Echo POST Multipart without data"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Create Test File
|
||||
run: |
|
||||
echo "test" > testfile3.txt
|
||||
- name: Given the gh-action is used with file
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
files: '{ "file": "${{ github.workspace }}/testfile3.txt" }'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-input-file-with-single-file:
|
||||
name: "IT Test - Request Postman Echo POST single file"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Create Test File
|
||||
run: |
|
||||
echo "test" > testfile4.txt
|
||||
- name: Given the gh-action is used with file
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
file: "${{ github.workspace }}/testfile4.txt"
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-input-data-with-url-encoded-string:
|
||||
name: "IT Test - Request Postman Echo POST URLEncoded string data"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with data form url encoded
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
contentType : 'application/x-www-form-urlencoded'
|
||||
method: 'POST'
|
||||
data: 'key=value'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-input-data-with-url-encoded-json-data:
|
||||
name: "IT Test - Request Postman Echo POST URLEncoded json data"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with json data
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
contentType : 'application/x-www-form-urlencoded'
|
||||
method: 'POST'
|
||||
data: '{"key":"value"}'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
test-delete-http-method:
|
||||
name: "IT Test - Request Postman Echo DELETE"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- name: Given the gh-action is used with method DELETE
|
||||
id: execution
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/delete'
|
||||
contentType : 'application/json'
|
||||
method: 'DELETE'
|
||||
data: '{"key":"value"}'
|
||||
|
||||
- uses: nick-fields/assert-action@aa0067e01f0f6545c31755d6ca128c5a3a14f6bf # v2
|
||||
name: Then outputs.status value must be 200
|
||||
with:
|
||||
expected: '200'
|
||||
actual: ${{ steps.execution.outputs.status }}
|
||||
comparison: exact
|
||||
|
||||
it-tests:
|
||||
name: "All IT Tests have to pass"
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
needs:
|
||||
# Add your tests here so that they prevent the merge of broken changes
|
||||
- test-method-get-on-existing-url
|
||||
- test-method-post-on-existing-url
|
||||
- test-method-post-on-existing-url-with-unescaped-newline
|
||||
- test-basic-auth
|
||||
- test-input-ignore-failure-code-404
|
||||
- test-input-ignore-failure-multiple-codes-401-404
|
||||
- test-input-files
|
||||
- test-input-responseFile
|
||||
- test-input-files-without-data
|
||||
- test-input-file-with-single-file
|
||||
- test-input-data-with-url-encoded-string
|
||||
- test-input-data-with-url-encoded-json-data
|
||||
- test-delete-http-method
|
||||
steps:
|
||||
- uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
44
.github/workflows/test.yml
vendored
44
.github/workflows/test.yml
vendored
|
@ -1,44 +0,0 @@
|
|||
name: Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
request:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: Request Postment Echo GET
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/get'
|
||||
method: 'GET'
|
||||
|
||||
- name: Request Postment Echo POST
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
data: '{ "key": "value" }'
|
||||
|
||||
- name: Request Postment Echo POST with Unescaped Newline
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/post'
|
||||
method: 'POST'
|
||||
escapeData: 'true'
|
||||
data: >-
|
||||
{
|
||||
"key":"multi line\ntest
|
||||
text"
|
||||
}
|
||||
|
||||
- name: Request Postment Echo BasicAuth
|
||||
uses: ./
|
||||
with:
|
||||
url: 'https://postman-echo.com/basic-auth'
|
||||
method: 'GET'
|
||||
username: 'postman'
|
||||
password: 'password'
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
node_modules
|
||||
.vscode
|
98
README.md
98
README.md
|
@ -1,44 +1,106 @@
|
|||
# HTTP Request Action
|
||||
|
||||
Create any kind of HTTP Requests in your GitHub actions to trigger Tools like Ansible AWX
|
||||
**Create HTTP Requests from GitHub Actions.** This action allows GitHub events to engage with tools like Ansible AWX that use HTTP APIs.
|
||||
|
||||
Example Usage:
|
||||
```
|
||||
### Example
|
||||
```yaml
|
||||
jobs:
|
||||
deployment
|
||||
- name: Deploy Stage
|
||||
uses: fjogeleit/http-request-action@master
|
||||
with:
|
||||
url: 'https://ansible.io/api/v2/job_templates/84/launch/'
|
||||
method: 'POST'
|
||||
username: ${{ secrets.AWX_USER }}
|
||||
password: ${{ secrets.AWX_PASSWORD }}
|
||||
deployment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy Stage
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: 'https://ansible.io/api/v2/job_templates/84/launch/'
|
||||
method: 'POST'
|
||||
username: ${{ secrets.AWX_USER }}
|
||||
password: ${{ secrets.AWX_PASSWORD }}
|
||||
customHeaders: '{"Content-Type": "application/json"}'
|
||||
data: '{"key_1": "value_1", "key_2": "value_2"}'
|
||||
```
|
||||
|
||||
### Input Arguments
|
||||
### Versioning
|
||||
|
||||
`master` branch is deprecated. Please use `main` or `v1` to get the latest version of this action. It is recommended to use a fixed version.
|
||||
|
||||
### Request Configuration
|
||||
|
||||
|Argument| Description | Default |
|
||||
|--------|---------------|-----------|
|
||||
|url | Request URL | _required_ Field |
|
||||
|method | Request Method| POST |
|
||||
|contentType | Request ContentType| application/json |
|
||||
|data | Request Body Content as JSON String, only for POST / PUT / PATCH Requests | '{}' |
|
||||
|data | Request Body Content:<br>- text content like JSON or XML<br>- key=value pairs separated by '&' or JSON data and contentType: application/x-www-form-urlencoded<br><br>only for POST / PUT / PATCH Requests | '{}' |
|
||||
|files | Map of key / absolute file paths send as multipart/form-data request to the API, if set the contentType is set to multipart/form-data, values provided by data will be added as additional FormData values, nested objects are not supported. **Example provided in the _test_ Workflow of this Action** | '{}' |
|
||||
|file | Single absolute file path send as `application/octet-stream` request to the API, if set the contentType is set to `application/octet-stream`. This input will be ignored if either `data` or `files` input is present. **Example provided in the _test_ Workflow of this Action** ||
|
||||
|timeout| Request Timeout in ms | 5000 (5s) |
|
||||
|username| Username for Basic Auth ||
|
||||
|password| Password for Basic Auth ||
|
||||
|bearerToken| Bearer Authentication Token (without Bearer Prefix) ||
|
||||
|customHeaders| Additional header values as JSON string, keys in this object overwrite default headers like Content-Type |'{}'|
|
||||
|preventFailureOnNoResponse| Prevent this Action to fail if the request respond without an response. Use 'true' (string) as value to enable it ||
|
||||
|escapeData| Escape newlines in data string content. Use 'true' (string) as value to enable it ||
|
||||
|preventFailureOnNoResponse| Prevent this Action to fail if the request respond without an response. Use 'true' (string) as value to enable it ||
|
||||
|ignoreStatusCodes| Prevent this Action to fail if the request respond with one of the configured Status Codes. Example: '404,401' ||
|
||||
|httpsCA| Certificate authority as string in PEM format ||
|
||||
|httpsCert| Client Certificate as string ||
|
||||
|httpsKey| Client Certificate Key as string ||
|
||||
|responseFile| Persist the response data to the specified file path ||
|
||||
|maskResponse| If set to true, the response will be masked in the logs of the action |'false'|
|
||||
|retry| optional amount of retries if the request is failing, does not retry if the status code is ignored ||
|
||||
|retryWait| time between each retry in millseconds | 3000 |
|
||||
|ignoreSsl| ignore ssl verify (rejectUnauthorized: false) | false |
|
||||
|
||||
### Output
|
||||
### Response
|
||||
|
||||
- `response` Request Response as JSON String
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
`response` | Response as JSON String
|
||||
`headers` | Headers
|
||||
`status` | HTTP status message
|
||||
|
||||
To display HTTP response data in the GitHub Actions log give the request an `id` and access its `outputs`. You can also access specific field from the response data using [fromJson()](https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson) expression.
|
||||
|
||||
### Debug Informations
|
||||
```yaml
|
||||
steps:
|
||||
- name: Make Request
|
||||
id: myRequest
|
||||
uses: fjogeleit/http-request-action@v1
|
||||
with:
|
||||
url: "http://yoursite.com/api"
|
||||
- name: Show Response
|
||||
run: |
|
||||
echo ${{ steps.myRequest.outputs.response }}
|
||||
echo ${{ steps.myRequest.outputs.headers }}
|
||||
echo ${{ steps.myRequest.outputs.status }}
|
||||
echo ${{ fromJson(steps.myRequest.outputs.response).field_you_want_to_access }}
|
||||
```
|
||||
|
||||
Enable Debug mode to get informations about
|
||||
### Additional Information
|
||||
|
||||
Additional information is available if debug logging is enabled:
|
||||
- Instance Configuration (Url / Timeout / Headers)
|
||||
- Request Data (Body / Auth / Method)
|
||||
|
||||
To [enable debug logging in GitHub Actions](https://docs.github.com/en/actions/managing-workflow-runs/enabling-debug-logging) create a secret `ACTIONS_RUNNER_DEBUG` with a value of `true`
|
||||
|
||||
#### Local Usage
|
||||
|
||||
* You can execute this tool locally with the provided CLI `bin/http-action`.
|
||||
|
||||
```bash
|
||||
bin/http-action --help
|
||||
Positionals:
|
||||
url request URL [string]
|
||||
|
||||
Optionen:
|
||||
--help helper text [boolean]
|
||||
-d, --data request body data [string] [default: "{}"]
|
||||
-f, --files request files, send as multipart/form-data [string] [default: "{}"]
|
||||
--file single file, send as application/octet-stream [string]
|
||||
-h, --customHeaders custom request headers [string] [default: "{}"]
|
||||
-m, --method request method (GET, POST, PATCH, PUT, DELETE) [string] [default: "POST"]
|
||||
-t, --contentType request content type [string] [default: "application/json"]
|
||||
--bearerToken bearer token without Bearer prefix, added as
|
||||
Authorization header [string]
|
||||
--timeout request timeout [number] [default: 5000]
|
||||
```
|
||||
|
|
44
action.yml
44
action.yml
|
@ -11,11 +11,17 @@ inputs:
|
|||
contentType:
|
||||
description: 'Content Type'
|
||||
required: false
|
||||
default: 'application/json'
|
||||
data:
|
||||
description: 'Request Body as JSON String'
|
||||
required: false
|
||||
default: '{}'
|
||||
files:
|
||||
description: 'Map of absolute file paths as JSON String'
|
||||
required: false
|
||||
default: '{}'
|
||||
file:
|
||||
description: 'A single absolute file path'
|
||||
required: false
|
||||
username:
|
||||
description: 'Auth Username'
|
||||
required: false
|
||||
|
@ -23,7 +29,7 @@ inputs:
|
|||
description: 'Auth Password'
|
||||
required: false
|
||||
timeout:
|
||||
description: 'Request Timeout in Sec'
|
||||
description: 'Request Timeout in milliseconds'
|
||||
required: false
|
||||
default: '5000'
|
||||
bearerToken:
|
||||
|
@ -35,12 +41,44 @@ inputs:
|
|||
preventFailureOnNoResponse:
|
||||
description: 'Prevent this Action to fail if the request respond without an response'
|
||||
required: false
|
||||
ignoreStatusCodes:
|
||||
description: 'Prevent this Action to fail if the request respond with one of the configured StatusCodes'
|
||||
required: false
|
||||
escapeData:
|
||||
description: 'Escape newlines in data string content'
|
||||
required: false
|
||||
httpsCA:
|
||||
description: 'Certificate authority as string in PEM format'
|
||||
required: false
|
||||
httpsCert:
|
||||
description: 'Client Certificate as string'
|
||||
required: false
|
||||
httpsKey:
|
||||
description: 'Client Certificate Key as string'
|
||||
required: false
|
||||
responseFile:
|
||||
description: 'Persist the response data to the specified file path'
|
||||
required: false
|
||||
maskResponse:
|
||||
description: 'Allows to mark your response as secret and hide the output in the action logs'
|
||||
required: false
|
||||
default: 'false'
|
||||
retry:
|
||||
description: 'optional amount of retries if the request fails'
|
||||
required: false
|
||||
retryWait:
|
||||
description: 'wait time between retries in milliseconds'
|
||||
required: false
|
||||
ignoreSsl:
|
||||
description: 'ignore ssl verify (rejectUnauthorized: false)'
|
||||
default: 'false'
|
||||
outputs:
|
||||
response:
|
||||
description: 'HTTP Response Content'
|
||||
headers:
|
||||
description: 'HTTP Response Headers'
|
||||
status:
|
||||
description: 'HTTP status message'
|
||||
runs:
|
||||
using: 'node12'
|
||||
using: 'node20'
|
||||
main: 'dist/index.js'
|
||||
|
|
55
bin/http-action
Executable file
55
bin/http-action
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env node
|
||||
const yargs = require('yargs/yargs')
|
||||
const { hideBin } = require('yargs/helpers')
|
||||
const { LogActions } = require('../src/githubActions.js')
|
||||
const { request } = require('../src/httpClient');
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option('data', { alias: 'd', type: 'string', description: 'request body data', default: '{}' })
|
||||
.option('files', { alias: 'f', type: 'string', description: 'request files, send as multipart/form-data', default: '{}' })
|
||||
.option('file', { type: 'string', description: 'single file, send as application/octet-stream' })
|
||||
.option('customHeaders', { alias: 'h', type: 'string', description: 'custom request headers', default: '{}' })
|
||||
.option('method', { alias: 'm', type: 'string', description: 'request method (GET, POST, PATCH, PUT, DELETE)', default: 'POST' })
|
||||
.option('contentType', { alias: 't', type: 'string', description: 'request content type', default: 'application/json' })
|
||||
.option('bearerToken', { type: 'string', description: 'bearer token without Bearer prefix, added as Authorization header' })
|
||||
.option('timeout', { type: 'number', description: 'request timeout', default: 5000 })
|
||||
.positional('url', { type: 'string', description: 'URL', description: 'request URL' })
|
||||
.parse()
|
||||
|
||||
let customHeaders = {}
|
||||
|
||||
if (!!argv.customHeaders) {
|
||||
try {
|
||||
customHeaders = JSON.parse(argv.customHeaders);
|
||||
} catch(error) {
|
||||
console.error('Could not parse customHeaders string value')
|
||||
}
|
||||
}
|
||||
|
||||
const headers = { 'Content-Type': argv.contentType || 'application/json' }
|
||||
|
||||
if (!!argv.bearerToken) {
|
||||
headers['Authorization'] = `Bearer ${argv.bearerToken}`;
|
||||
}
|
||||
|
||||
const instanceConfig = {
|
||||
baseURL: argv._[0],
|
||||
timeout: parseInt(argv.timeout || 5000, 10),
|
||||
headers: { ...headers, ...customHeaders }
|
||||
}
|
||||
|
||||
request({
|
||||
data: argv.data,
|
||||
method: argv.method,
|
||||
instanceConfig,
|
||||
files: argv.files,
|
||||
file: argv.file,
|
||||
actions: new LogActions(),
|
||||
options: {
|
||||
ignoredCodes: [],
|
||||
escapeData: false,
|
||||
preventFailureOnNoResponse: false,
|
||||
retry: 0,
|
||||
retryWait: 0
|
||||
}
|
||||
})
|
36560
dist/index.js
vendored
36560
dist/index.js
vendored
File diff suppressed because one or more lines are too long
610
package-lock.json
generated
610
package-lock.json
generated
|
@ -1,32 +1,594 @@
|
|||
{
|
||||
"name": "http-request-action",
|
||||
"version": "1.4.2",
|
||||
"lockfileVersion": 1,
|
||||
"version": "1.16.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==",
|
||||
"dev": true
|
||||
},
|
||||
"@zeit/ncc": {
|
||||
"version": "0.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.22.3.tgz",
|
||||
"integrity": "sha512-jnCLpLXWuw/PAiJiVbLjA8WBC0IJQbFeUwF4I9M+23MvIxTxk5pD4Q8byQBSPmHQjz5aBoA7AKAElQxMpjrCLQ=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz",
|
||||
"integrity": "sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "http-request-action",
|
||||
"version": "1.16.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"axios": "^1.8",
|
||||
"form-data": "^4.0.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
|
||||
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
|
||||
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/http-client": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/exec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/io": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
|
||||
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6",
|
||||
"undici": "^5.25.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.38.3",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.3.tgz",
|
||||
"integrity": "sha512-rnK6hJBS6mwc+Bkab+PGPs9OiS0i/3kdTO+CkI8V0/VrW3vmz7O2Pxjw/owOlmo6PKEIxRSeZKv/kuL9itnpYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
|
||||
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.0",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.28.5",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
|
||||
"integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
package.json
15
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "http-request-action",
|
||||
"version": "1.4.2",
|
||||
"version": "1.16.4",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"private": false,
|
||||
|
@ -13,16 +13,21 @@
|
|||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fjogeleit/http-request-action/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fjogeleit/http-request-action#readme",
|
||||
"devDependencies": {
|
||||
"@actions/core": "^1.2.6"
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"axios": "^1.8",
|
||||
"form-data": "^4.0.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit/ncc": "^0.22",
|
||||
"axios": "^0.21"
|
||||
"@actions/core": "^1.11.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict'
|
||||
|
||||
const core = require("@actions/core");
|
||||
|
||||
class GithubActions {
|
||||
|
@ -5,6 +7,10 @@ class GithubActions {
|
|||
core.debug(message)
|
||||
}
|
||||
|
||||
info(message) {
|
||||
core.info(message)
|
||||
}
|
||||
|
||||
warning(message) {
|
||||
core.warning(message)
|
||||
}
|
||||
|
@ -13,12 +19,20 @@ class GithubActions {
|
|||
core.setOutput(name, output)
|
||||
}
|
||||
|
||||
setSecret(value) {
|
||||
core.setSecret(value)
|
||||
}
|
||||
|
||||
setFailed(message) {
|
||||
core.setFailed(message)
|
||||
}
|
||||
}
|
||||
|
||||
class LogActions {
|
||||
info(message) {
|
||||
console.info(message)
|
||||
}
|
||||
|
||||
debug(message) {
|
||||
console.info(message)
|
||||
}
|
||||
|
|
15
src/handler/mask.js
Normal file
15
src/handler/mask.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
const axios = require('axios');
|
||||
const { GithubActions } = require('../githubActions');
|
||||
|
||||
/**
|
||||
* @param {GithubActions} actions
|
||||
*
|
||||
* @returns {(response: axios.AxiosResponse) => void}
|
||||
*/
|
||||
const createMaskHandler = (actions) => (response) => {
|
||||
actions.setSecret(JSON.stringify(response.data))
|
||||
}
|
||||
|
||||
module.exports = { createMaskHandler }
|
17
src/handler/output.js
Normal file
17
src/handler/output.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
'use strict'
|
||||
|
||||
const axios = require('axios');
|
||||
const { GithubActions } = require('../githubActions');
|
||||
|
||||
/**
|
||||
* @param {GithubActions} actions
|
||||
*
|
||||
* @returns {(response: axios.AxiosResponse) => void}
|
||||
*/
|
||||
const createOutputHandler = (actions) => (response) => {
|
||||
actions.setOutput('response', JSON.stringify(response.data))
|
||||
actions.setOutput('headers', response.headers)
|
||||
actions.setOutput('status', response.status)
|
||||
}
|
||||
|
||||
module.exports = { createOutputHandler }
|
30
src/handler/persist.js
Normal file
30
src/handler/persist.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
'use strict'
|
||||
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
const { GithubActions } = require('../githubActions');
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @param {GithubActions} actions
|
||||
*
|
||||
* @returns {(response: axios.AxiosResponse) => void}
|
||||
*/
|
||||
const createPersistHandler = (filePath, actions) => (response) => {
|
||||
let data = response.data
|
||||
|
||||
if (typeof data == 'object') {
|
||||
data = JSON.stringify(data)
|
||||
}
|
||||
|
||||
fs.writeFile(filePath, data, error => {
|
||||
if (!error) {
|
||||
actions.info(`response persisted successfully at ${filePath}`)
|
||||
return
|
||||
}
|
||||
|
||||
actions.warning(JSON.stringify({ message: error.message, data: response.data }))
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { createPersistHandler }
|
77
src/helper.js
Normal file
77
src/helper.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
'use strict';
|
||||
|
||||
const { GithubActions } = require('./githubActions');
|
||||
const FormData = require('form-data');
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
const convertToJSON = (value) => {
|
||||
try {
|
||||
return JSON.parse(value) || {};
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{ [key: string]: string }} data
|
||||
* @param {{ [key: string]: string }} files
|
||||
* @param {boolean} convertPaths
|
||||
*
|
||||
* @returns {FormData}
|
||||
*/
|
||||
const convertToFormData = (data, files) => {
|
||||
const formData = new FormData();
|
||||
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(files)) {
|
||||
formData.append(key, fs.createReadStream(value));
|
||||
}
|
||||
|
||||
return formData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {() => Promise} callback
|
||||
* @param {{ retry: number; sleep: number; actions: GithubActions }} options
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const retry = async (callback, options) => {
|
||||
let lastErr = null;
|
||||
let i = 0;
|
||||
|
||||
do {
|
||||
try {
|
||||
return await callback();
|
||||
} catch (err) {
|
||||
lastErr = err;
|
||||
}
|
||||
|
||||
if (i < options.retry) {
|
||||
options.actions.warning(`#${i + 1} request failed: ${lastErr}`);
|
||||
await sleep(options.sleep);
|
||||
}
|
||||
|
||||
i++;
|
||||
} while (i <= options.retry);
|
||||
|
||||
throw lastErr;
|
||||
};
|
||||
|
||||
function sleep(milliseconds) {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
convertToJSON,
|
||||
convertToFormData,
|
||||
retry,
|
||||
};
|
|
@ -1,15 +1,44 @@
|
|||
const axios = require("axios");
|
||||
'use strict'
|
||||
|
||||
const axios = require('axios');
|
||||
const FormData = require('form-data');
|
||||
const fs = require('fs');
|
||||
const url = require('url');
|
||||
const { GithubActions } = require('./githubActions');
|
||||
const { convertToJSON, convertToFormData, retry } = require('./helper');
|
||||
|
||||
const METHOD_GET = 'GET'
|
||||
const METHOD_POST = 'POST'
|
||||
|
||||
const request = async({ method, instanceConfig, data, auth, actions, preventFailureOnNoResponse, escapeData }) => {
|
||||
try {
|
||||
const instance = axios.create(instanceConfig);
|
||||
const HEADER_CONTENT_TYPE = 'Content-Type'
|
||||
|
||||
if (escapeData) {
|
||||
const CONTENT_TYPE_URLENCODED = 'application/x-www-form-urlencoded'
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} param0.method HTTP Method
|
||||
* @param {axios.AxiosRequestConfig} param0.instanceConfig
|
||||
* @param {string} param0.data Request Body as string, default {}
|
||||
* @param {string} param0.files Map of Request Files (name: absolute path) as JSON String, default: {}
|
||||
* @param {string} param0.file Single request file (absolute path)
|
||||
* @param {GithubActions} param0.actions
|
||||
* @param {{
|
||||
* ignoredCodes: number[];
|
||||
* preventFailureOnNoResponse: boolean,
|
||||
* escapeData: boolean;
|
||||
* retry: number;
|
||||
* retryWait: number;
|
||||
* }} param0.options
|
||||
*
|
||||
* @returns {Promise<axios.AxiosResponse>}
|
||||
*/
|
||||
const request = async({ method, instanceConfig, data, files, file, actions, options }) => {
|
||||
actions.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
try {
|
||||
if (options.escapeData) {
|
||||
data = data.replace(/"[^"]*"/g, (match) => {
|
||||
return match.replace(/[\n\r]\s*/g, "\\n");
|
||||
return match.replace(/[\n\r]\s*/g, "\\n");
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -17,34 +46,165 @@ const request = async({ method, instanceConfig, data, auth, actions, preventFail
|
|||
data = undefined;
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
auth,
|
||||
method,
|
||||
data
|
||||
if (files && files !== '{}') {
|
||||
let filesJson = convertToJSON(files)
|
||||
let dataJson = convertToJSON(data)
|
||||
|
||||
if (Object.keys(filesJson).length > 0) {
|
||||
try {
|
||||
data = convertToFormData(dataJson, filesJson)
|
||||
} catch(error) {
|
||||
actions.setFailed(JSON.stringify({ message: `Unable to convert Data and Files into FormData: ${error.message}`, data: dataJson, files: filesJson }))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
instanceConfig = await updateConfig(instanceConfig, data)
|
||||
} catch(error) {
|
||||
actions.setFailed(JSON.stringify({ message: `Unable to read Content-Length: ${error.message}` }))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only consider file if neither data nor files provided
|
||||
if ((!data || data === '{}') && (!files || files === '{}') && file) {
|
||||
data = fs.createReadStream(file)
|
||||
updateConfigForFile(instanceConfig, file, actions)
|
||||
}
|
||||
|
||||
if (instanceConfig.headers[HEADER_CONTENT_TYPE] === CONTENT_TYPE_URLENCODED) {
|
||||
let dataJson = convertToJSON(data)
|
||||
if (typeof dataJson === 'object' && Object.keys(dataJson).length) {
|
||||
data = (new url.URLSearchParams(dataJson)).toString();
|
||||
}
|
||||
}
|
||||
|
||||
const requestData = {
|
||||
method,
|
||||
data,
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity
|
||||
}
|
||||
|
||||
actions.debug('Instance Configuration: ' + JSON.stringify(instanceConfig))
|
||||
|
||||
/** @type {axios.AxiosInstance} */
|
||||
const instance = axios.create(instanceConfig);
|
||||
|
||||
actions.debug('Request Data: ' + JSON.stringify(requestData))
|
||||
|
||||
const response = await instance.request(requestData)
|
||||
const execRequest = async () => {
|
||||
try {
|
||||
return await instance.request(requestData)
|
||||
} catch(error) {
|
||||
if (error.response && options.ignoredCodes.includes(error.response.status)) {
|
||||
actions.warning(`ignored status code: ${JSON.stringify({ code: error.response.status, message: error.response.data })}`)
|
||||
|
||||
actions.setOutput('response', JSON.stringify(response.data))
|
||||
return error.response
|
||||
}
|
||||
|
||||
if (!error.response && error.request && options.preventFailureOnNoResponse) {
|
||||
actions.warning(`no response received: ${JSON.stringify(error)}`);
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {axios.AxiosResponse|null} */
|
||||
const response = await retry(execRequest, {
|
||||
actions,
|
||||
retry: options.retry || 0,
|
||||
sleep: options.retryWait // wait time after each retry
|
||||
})
|
||||
|
||||
if (!response) {
|
||||
return null
|
||||
}
|
||||
|
||||
return response
|
||||
} catch (error) {
|
||||
if (error.toJSON) {
|
||||
actions.setOutput(JSON.stringify(error.toJSON()));
|
||||
if ((typeof error === 'object') && (error.isAxiosError === true)) {
|
||||
const { name, message, code, response } = error
|
||||
actions.setOutput('requestError', JSON.stringify({ name, message, code, status: response && response.status ? response.status : null }));
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
actions.setFailed(JSON.stringify({ code: error.response.code, message: error.response.data }))
|
||||
} else if (error.request && !preventFailureOnNoResponse) {
|
||||
actions.setFailed(JSON.stringify({ error: "no response received" }));
|
||||
} else if (error.request && preventFailureOnNoResponse) {
|
||||
actions.warning(JSON.stringify(error));
|
||||
actions.setFailed(JSON.stringify({ code: error.response.status, message: error.response.data }))
|
||||
} else if (error.request) {
|
||||
actions.setFailed(JSON.stringify({ error: "no response received", message: error.message }));
|
||||
} else {
|
||||
actions.setFailed(JSON.stringify({ message: error.message, data }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ baseURL: string; timeout: number; headers: { [name: string]: string } }} instanceConfig
|
||||
* @param {FormData} formData
|
||||
*
|
||||
* @returns {Promise<{ baseURL: string; timeout: number; headers: { [name: string]: string } }>}
|
||||
*/
|
||||
const updateConfig = async (instanceConfig, formData) => {
|
||||
const formHeaders = formData.getHeaders()
|
||||
const contentType = formHeaders['content-type']
|
||||
|
||||
delete formHeaders['content-type']
|
||||
|
||||
return {
|
||||
...instanceConfig,
|
||||
headers: {
|
||||
...instanceConfig.headers,
|
||||
...formHeaders,
|
||||
'Content-Length': await contentLength(formData),
|
||||
'Content-Type': contentType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param instanceConfig
|
||||
* @param filePath
|
||||
* @param {*} actions
|
||||
*
|
||||
* @returns {{ baseURL: string; timeout: number; headers: { [name: string]: string } }}
|
||||
*/
|
||||
const updateConfigForFile = (instanceConfig, filePath, actions) => {
|
||||
try {
|
||||
const { size } = fs.statSync(filePath)
|
||||
|
||||
return {
|
||||
...instanceConfig,
|
||||
headers: {
|
||||
...instanceConfig.headers,
|
||||
'Content-Length': size,
|
||||
'Content-Type': 'application/octet-stream'
|
||||
}
|
||||
}
|
||||
} catch(error) {
|
||||
actions.setFailed({ message: `Unable to read Content-Length: ${error.message}`, data, files })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FormData} formData
|
||||
*
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
const contentLength = (formData) => new Promise((resolve, reject) => {
|
||||
formData.getLength((error, length) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
return
|
||||
}
|
||||
|
||||
resolve(length)
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
request,
|
||||
METHOD_POST,
|
||||
|
|
92
src/index.js
92
src/index.js
|
@ -1,44 +1,108 @@
|
|||
const core = require("@actions/core");
|
||||
'use strict'
|
||||
|
||||
const core = require('@actions/core');
|
||||
const axios = require('axios');
|
||||
const https = require('https');
|
||||
const { request, METHOD_POST } = require('./httpClient');
|
||||
const { GithubActions } = require('./githubActions');
|
||||
|
||||
let auth = undefined
|
||||
const { createPersistHandler } = require('./handler/persist');
|
||||
const { createOutputHandler } = require('./handler/output');
|
||||
const { createMaskHandler } = require('./handler/mask');
|
||||
|
||||
let customHeaders = {}
|
||||
|
||||
if (!!core.getInput('customHeaders')) {
|
||||
try {
|
||||
customHeaders = JSON.parse(core.getInput('customHeaders'));
|
||||
} catch(error) {
|
||||
core.error('Could not parse customHeaders string value')
|
||||
core.debug(`Invalid customHeaders string: ${core.getInput('customHeaders')}`)
|
||||
core.error(`Could not parse customHeaders string value: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
const headers = { 'Content-Type': core.getInput('contentType') || 'application/json' }
|
||||
|
||||
if (!!core.getInput('username') || !!core.getInput('password')) {
|
||||
core.debug('Add BasicHTTP Auth config')
|
||||
|
||||
auth = {
|
||||
username: core.getInput('username'),
|
||||
password: core.getInput('password')
|
||||
}
|
||||
}
|
||||
|
||||
if (!!core.getInput('bearerToken')) {
|
||||
headers['Authorization'] = `Bearer ${core.getInput('bearerToken')}`;
|
||||
}
|
||||
|
||||
/** @type {axios.AxiosRequestConfig} */
|
||||
const instanceConfig = {
|
||||
httpsAgent: new https.Agent({
|
||||
rejectUnauthorized: core.getInput('ignoreSsl') !== 'true',
|
||||
}),
|
||||
baseURL: core.getInput('url', { required: true }),
|
||||
timeout: parseInt(core.getInput('timeout') || 5000, 10),
|
||||
headers: { ...headers, ...customHeaders }
|
||||
}
|
||||
|
||||
core.debug('Instance Configuration: ' + JSON.stringify(instanceConfig))
|
||||
if (!!core.getInput('httpsCA') || !!core.getInput('httpsCert')) {
|
||||
instanceConfig.httpsAgent = new https.Agent({
|
||||
ca: core.getInput('httpsCA') || undefined,
|
||||
cert: core.getInput('httpsCert') || undefined,
|
||||
key: core.getInput('httpsKey') || undefined
|
||||
})
|
||||
}
|
||||
|
||||
if (!!core.getInput('username') || !!core.getInput('password')) {
|
||||
core.debug('Add BasicHTTP Auth config')
|
||||
|
||||
instanceConfig.auth = {
|
||||
username: core.getInput('username'),
|
||||
password: core.getInput('password')
|
||||
}
|
||||
}
|
||||
|
||||
let retry = 0
|
||||
if (!!core.getInput('retry')) {
|
||||
retry = parseInt(core.getInput('retry'))
|
||||
}
|
||||
|
||||
let retryWait = 3000
|
||||
if (!!core.getInput('retryWait')) {
|
||||
retryWait = parseInt(core.getInput('retryWait'))
|
||||
}
|
||||
|
||||
const data = core.getInput('data') || '{}';
|
||||
const files = core.getInput('files') || '{}';
|
||||
const file = core.getInput('file')
|
||||
const responseFile = core.getInput('responseFile')
|
||||
const method = core.getInput('method') || METHOD_POST;
|
||||
const preventFailureOnNoResponse = core.getInput('preventFailureOnNoResponse') === 'true';
|
||||
const escapeData = core.getInput('escapeData') === 'true';
|
||||
|
||||
request({ data, method, instanceConfig, auth, preventFailureOnNoResponse, escapeData, actions: new GithubActions() })
|
||||
const ignoreStatusCodes = core.getInput('ignoreStatusCodes');
|
||||
let ignoredCodes = [];
|
||||
|
||||
if (typeof ignoreStatusCodes === 'string' && ignoreStatusCodes.length > 0) {
|
||||
ignoredCodes = ignoreStatusCodes.split(',').map(statusCode => parseInt(statusCode.trim()))
|
||||
}
|
||||
|
||||
const actions = new GithubActions();
|
||||
|
||||
const handler = [];
|
||||
|
||||
if (core.getBooleanInput('maskResponse')) {
|
||||
handler.push(createMaskHandler(actions))
|
||||
}
|
||||
|
||||
handler.push(createOutputHandler(actions))
|
||||
|
||||
if (!!responseFile) {
|
||||
handler.push(createPersistHandler(responseFile, actions))
|
||||
}
|
||||
|
||||
const options = {
|
||||
ignoredCodes,
|
||||
preventFailureOnNoResponse,
|
||||
escapeData,
|
||||
retry,
|
||||
retryWait
|
||||
}
|
||||
|
||||
request({ data, method, instanceConfig, files, file, actions, options }).then(response => {
|
||||
if (response && typeof response == 'object') {
|
||||
handler.forEach(h => h(response))
|
||||
}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue