diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 0996fe6..a4d30cc 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -15,6 +15,9 @@ on:
- "action.yml"
pull_request:
+env:
+ httpbin: ${{ !github.event.act && 'https://httpbin.org' || 'http://192.168.1.25:8080' }}
+
jobs:
test:
name: "Test"
@@ -32,23 +35,54 @@ jobs:
GITHUB_CTX: ${{ toJSON(github) }}
run: echo "$GITHUB_CTX"
- - name: "Test Local Action"
- id: test
+ - name: "1: Test Data"
+ id: test1
uses: ./
with:
- url: https://httpbin.org/post
+ url: "${{ env.httpbin }}/post"
+ #insecure: true
#data: '{"key": "value"}'
data: |
key: value
params: |
param1: value1
+ config: |
+ timeout: 30000
- - name: "Verify Outputs"
+ - name: "1: Verify Data"
+ if: ${{ !github.event.act }}
+ run: |
+ echo 'status: ${{ steps.test1.outputs.status }}'
+ echo 'headers: ${{ steps.test1.outputs.headers }}'
+ echo 'data: ${{ steps.test1.outputs.data }}'
+ if [ '${{ fromJson(steps.test1.outputs.data).data }}' != '{"key":"value"}' ];then
+ echo "Output Invalid"
+ exit 1
+ fi
+
+ - name: "2: Test File"
+ if: ${{ !github.event.act }}
+ id: test2
+ uses: ./
+ with:
+ url: "${{ env.httpbin }}/post"
+ #insecure: true
+ #data: '{"key": "value"}'
+ data: |
+ key: value
+ params: |
+ param1: value1
+ file: event.json
+ filename: not-event.json
+
+ - name: "2: Verify File"
+ if: ${{ !github.event.act }}
run: |
- echo 'status: ${{ steps.test.outputs.status }}'
- echo 'headers: ${{ steps.test.outputs.headers }}'
- echo 'data: ${{ steps.test.outputs.data }}'
- if [ '${{ fromJson(steps.test.outputs.data).data }}' != '{"key":"value"}' ];then
+ echo 'status: ${{ steps.test2.outputs.status }}'
+ echo 'headers: ${{ steps.test2.outputs.headers }}'
+ echo 'data: ${{ steps.test2.outputs.data }}'
+ echo 'data.form: ${{ fromJson(steps.test2.outputs.data).form.key }}'
+ if [ '${{ fromJson(steps.test2.outputs.data).form.key }}' != 'value' ];then
echo "Output Invalid"
exit 1
fi
diff --git a/README.md b/README.md
index 576455d..10d51a8 100644
--- a/README.md
+++ b/README.md
@@ -45,11 +45,14 @@ Pass data/headers/params as JSON or YAML formatted strings.
{
"key": "value"
}
+ config: |
+ timeout: 1000
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
insecure: false
file: path/to/file.txt
name: file
+ filename: custom-name.txt
```
> [!NOTE]
@@ -58,18 +61,20 @@ Pass data/headers/params as JSON or YAML formatted strings.
## Inputs
-| Input | Default | Description of the Input Value |
-| :------- | :--------- | :------------------------------------------------- |
-| url | _Required_ | URL for Request [⤵️](#url) |
-| method | `POST` | Request Method [⤵️](#method) |
-| data | - | Request Data JSON/YAML [⤵️](#data) |
-| headers | - | Request Headers JSON/YAML [⤵️](#headers) |
-| params | - | Request Parameters JSON/YAML [⤵️](#params) |
-| username | - | Basic Auth Username |
-| password | - | Basic Auth Password |
-| insecure | `false` | Ignore SSL Errors |
-| file | - | File Path to Send [⤵️](#file) |
-| name | `file` | File Form Key Name |
+| Input | Default Value | Description of the Input Value |
+| :------- | :----------------- | :------------------------------------------------- |
+| url | _Required_ | URL for Request [⤵️](#url) |
+| method | `POST` | Request Method [⤵️](#method) |
+| data | - | Request Data JSON/YAML [⤵️](#data) |
+| headers | - | Request Headers JSON/YAML [⤵️](#headers) |
+| params | - | Request Parameters JSON/YAML [⤵️](#params) |
+| config | - | Axios Config JSON/YAML [⤵️](#config) |
+| username | - | Basic Auth Username |
+| password | - | Basic Auth Password |
+| insecure | `false` | Ignore SSL Errors |
+| file | - | File Path to Send [⤵️](#file) |
+| name | `file` | File Form Key Name |
+| filename | _Original Name_ | Set a Different File Name |
### url
@@ -77,18 +82,20 @@ The URL to send the request too. You may include params here or in the [params](
### method
-The request method, including custom methods.
+The request method, including custom methods. Case-insensitive.
Default: `POST`
### data
-Body JSON or YAML data. Only used for `PUT`, `POST`, `DELETE`, and `PATCH`.
+Body JSON/YAML data. Only used for `PUT`, `POST`, `DELETE`, and `PATCH`.
Data is parsed with `JSON.parse` or `yaml.load`, [js-yaml](https://github.com/nodeca/js-yaml).
View JSON/YAML Example
+This format works for `data`, `headers`, `params`, and `config`.
+
```yaml
data: |
key1: value1
@@ -103,15 +110,35 @@ data: |
}
```
+```yaml
+data: '{"key1": "value1", "key2": "value2"}'
+```
+
+Note: All these examples are identical.
+
### headers
-Headers JSON or YAML data.
+Headers JSON/YAML data.
### params
-Parameters, Query String, JSON or YAML data. These may also be provided in the [url](#url).
+Parameters (Query String) JSON/YAML data. These may also be provided in the [url](#url).
+
+### config
+
+Additional Axios Config JSON/YAML data. For example, set a 3-second timeout: `timeout: 3000`
+
+Reference: https://axios-http.com/docs/req_config
+
+Note: The config is spread last and overrides other keys.
+
+```javascript
+config = { url, method, headers, params, data, auth, httpsAgent, ...config }
+```
+
+
### file
@@ -120,12 +147,7 @@ key `name`. The file path is relative to the workspace/working directory.
For more information on inputs, see: https://axios-http.com/docs/req_config
-```yaml
-- name: 'Web Request'
- uses: cssnr/web-request-action@v1
- with:
- url: https://httpbin.org/post
-```
+See the [Examples](#examples) for more usage options...
## Outputs
@@ -135,6 +157,8 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
| headers | Response Headers |
| data | Response Data |
+Note: All outputs are run through `JSON.stringify` by default.
+
```yaml
- name: 'Web Request'
id: test
@@ -153,10 +177,20 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
💡 _Click on an example heading to expand or collapse the example._
-Algolia Start Crawl
+Trigger a Webhook
```yaml
-- name: 'Algolia Start Crawl'
+- name: 'Portainer Webhook'
+ uses: cssnr/web-request-action@v1
+ with:
+ url: ${{ secrets.PORTAINER_WEBHOOK }}
+```
+
+
+Start Algolia Crawl
+
+```yaml
+- name: 'Start Algolia Crawl'
uses: cssnr/web-request-action@v1
with:
url: https://crawler.algolia.com/api/1/crawlers/${{ secrets.CRAWLER_ID }}/reindex
@@ -168,7 +202,7 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
Deploy to Render
```yaml
-- name: 'Render Deploy'
+- name: 'Render Deploy Image'
uses: cssnr/web-request-action@v1
with:
url: ${{ secrets.RENDER_HOOK }}
@@ -196,8 +230,14 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
with:
url: https://httpbin.org/post
data: '{"key": "value"}'
+ data: |
+ '{"key": "value"}'
+ data: |
+ key: value
```
+Note: All data keys are identical as exemplar formats.
+
Send File
@@ -208,8 +248,24 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
url: https://httpbin.org/post
file: path/to/file.txt
name: file # Default - name of file key
+ filename: name.txt # Optional - file name
```
+
+Set Axios Config
+
+```yaml
+- name: 'Web Request'
+ uses: cssnr/web-request-action@v1
+ with:
+ url: https://httpbin.org/post
+ config: |
+ timeout: 1000
+ maxContentLength: 2000
+```
+
+Reference: https://axios-http.com/docs/req_config
+
All Inputs
@@ -226,11 +282,14 @@ For more information on inputs, see: https://axios-http.com/docs/req_config
{
"key": "value"
}
+ config: |
+ timeout: 5000
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORD }}
insecure: false
file: path/to/file.txt
name: file
+ filename: name.txt
```
diff --git a/action.yml b/action.yml
index 2b8229d..7e6a8ac 100644
--- a/action.yml
+++ b/action.yml
@@ -1,5 +1,5 @@
name: "Web Request"
-description: "Send Web Requests like POST and GET with Axios using GitHub Actions."
+description: "Easily Make Web Requests like GET/POST, Trigger Webhooks, and Send Files using Axios. Data inputs supports YAML/JSON format."
author: "Shane"
branding:
icon: "globe"
@@ -13,11 +13,13 @@ inputs:
description: "Request Method"
default: "POST"
data:
- description: "Request Data JSON"
+ description: "Request Data JSON/YAML"
headers:
- description: "Request Headers JSON"
+ description: "Request Headers JSON/YAML"
params:
- description: "Request Parameters JSON"
+ description: "Request Parameters JSON/YAML"
+ config:
+ description: "Axios Config JSON/YAML"
username:
description: "Basic Auth Username"
password:
@@ -30,6 +32,8 @@ inputs:
name:
description: "File Key Name"
default: "file"
+ filename:
+ description: "Custom File Name"
outputs:
status:
@@ -38,6 +42,8 @@ outputs:
description: "Response Headers"
data:
description: "Response Data"
+ #url:
+ # description: "Response URL"
runs:
using: "node24"
diff --git a/dist/index.js b/dist/index.js
index 261a81b..1552ec2 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -34475,6 +34475,22 @@ module.exports = require("node:events");
/***/ }),
+/***/ 3024:
+/***/ ((module) => {
+
+"use strict";
+module.exports = require("node:fs");
+
+/***/ }),
+
+/***/ 4708:
+/***/ ((module) => {
+
+"use strict";
+module.exports = require("node:https");
+
+/***/ }),
+
/***/ 7075:
/***/ ((module) => {
@@ -41533,14 +41549,21 @@ module.exports = /*#__PURE__*/JSON.parse('{"application/1d-interleaved-parityfec
/******/
/************************************************************************/
var __webpack_exports__ = {};
+const fs = __nccwpck_require__(3024)
+const https = __nccwpck_require__(4708)
+
const core = __nccwpck_require__(7484)
+
const axios = __nccwpck_require__(7269)
const src_FormData = __nccwpck_require__(6454)
-const fs = __nccwpck_require__(9896)
-const https = __nccwpck_require__(5692)
const yaml = __nccwpck_require__(4281)
async function main() {
+ const version = process.env.GITHUB_ACTION_REF
+ ? `${process.env.GITHUB_ACTION_REF}`
+ : 'Source'
+ core.info(`🏳️ Starting Web Request Action - \u001b[35;1m${version}`)
+
// Inputs
core.startGroup('Inputs')
const url = core.getInput('url', { required: true })
@@ -41553,6 +41576,8 @@ async function main() {
console.log('headers:', headers)
const params = parseData('params')
console.log('params:', params)
+ let config = parseData('config')
+ console.log('config:', config)
const username = core.getInput('username')
console.log('username:', username)
const password = core.getInput('password')
@@ -41563,44 +41588,51 @@ async function main() {
console.log('file:', file)
const name = core.getInput('name')
console.log('name:', name)
+ const filename = core.getInput('filename')
+ console.log('filename:', filename)
core.endGroup() // Inputs
// Options
- const auth = username && password ? { username, password } : {}
- console.log('auth:', auth)
+ core.startGroup('Options')
const httpsAgent = insecure
? new https.Agent({
rejectUnauthorized: false,
})
: null
console.log('httpsAgent:', httpsAgent)
+ const auth = username || password ? { username, password } : {}
+ console.log('auth:', auth)
+ const options = filename ? { filename } : {}
+ console.log('options:', options)
+ core.endGroup() // Options
// File
if (file) {
+ core.info('🔁 Converting Data to FormData')
const form = new src_FormData()
for (const [key, value] of Object.entries(data)) {
form.append(key, value)
}
- form.append(name, fs.createReadStream(file))
+ core.debug(`Adding file: ${file}`)
+ form.append(name, fs.createReadStream(file), options)
Object.assign(headers, form.getHeaders())
data = form
}
- // Request
- const config = {
- url,
- method,
- headers,
- params,
- data,
- auth,
- httpsAgent,
- }
+ // Config
+ config = { url, method, headers, params, data, auth, httpsAgent, ...config }
+ core.startGroup('Config')
console.log('config:', config)
+ core.endGroup() // Config
+
+ // Request
+ core.info('⌛ Processing Request')
const response = await axios.request(config)
console.log('response.status:', response.status)
// console.log('response:', response)
+ // console.log('responseUrl:', response.request?.res?.responseUrl)
// console.log('response.request._headers:', response.request._headers)
+
core.startGroup('Headers')
console.log('response.headers:', response.headers)
core.endGroup() // Headers
@@ -41610,11 +41642,13 @@ async function main() {
core.endGroup() // Data
// Outputs
+ core.info('📩 Setting Outputs')
core.setOutput('status', response.status)
core.setOutput('headers', response.headers)
core.setOutput('data', response.data)
+ // core.setOutput('url', response.request?.res?.responseUrl || '')
- core.info(`\u001b[32;1mFinished Success`)
+ core.info(`✅ \u001b[32;1mFinished Success`)
}
/**
diff --git a/src/index.js b/src/index.js
index a35a436..5564350 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,11 +1,18 @@
+const fs = require('node:fs')
+const https = require('node:https')
+
const core = require('@actions/core')
+
const axios = require('axios')
const FormData = require('form-data')
-const fs = require('fs')
-const https = require('https')
const yaml = require('js-yaml')
async function main() {
+ const version = process.env.GITHUB_ACTION_REF
+ ? `${process.env.GITHUB_ACTION_REF}`
+ : 'Source'
+ core.info(`🏳️ Starting Web Request Action - \u001b[35;1m${version}`)
+
// Inputs
core.startGroup('Inputs')
const url = core.getInput('url', { required: true })
@@ -18,6 +25,8 @@ async function main() {
console.log('headers:', headers)
const params = parseData('params')
console.log('params:', params)
+ let config = parseData('config')
+ console.log('config:', config)
const username = core.getInput('username')
console.log('username:', username)
const password = core.getInput('password')
@@ -28,44 +37,51 @@ async function main() {
console.log('file:', file)
const name = core.getInput('name')
console.log('name:', name)
+ const filename = core.getInput('filename')
+ console.log('filename:', filename)
core.endGroup() // Inputs
// Options
- const auth = username && password ? { username, password } : {}
- console.log('auth:', auth)
+ core.startGroup('Options')
const httpsAgent = insecure
? new https.Agent({
rejectUnauthorized: false,
})
: null
console.log('httpsAgent:', httpsAgent)
+ const auth = username || password ? { username, password } : {}
+ console.log('auth:', auth)
+ const options = filename ? { filename } : {}
+ console.log('options:', options)
+ core.endGroup() // Options
// File
if (file) {
+ core.info('🔁 Converting Data to FormData')
const form = new FormData()
for (const [key, value] of Object.entries(data)) {
form.append(key, value)
}
- form.append(name, fs.createReadStream(file))
+ core.debug(`Adding file: ${file}`)
+ form.append(name, fs.createReadStream(file), options)
Object.assign(headers, form.getHeaders())
data = form
}
- // Request
- const config = {
- url,
- method,
- headers,
- params,
- data,
- auth,
- httpsAgent,
- }
+ // Config
+ config = { url, method, headers, params, data, auth, httpsAgent, ...config }
+ core.startGroup('Config')
console.log('config:', config)
+ core.endGroup() // Config
+
+ // Request
+ core.info('⌛ Processing Request')
const response = await axios.request(config)
console.log('response.status:', response.status)
// console.log('response:', response)
+ // console.log('responseUrl:', response.request?.res?.responseUrl)
// console.log('response.request._headers:', response.request._headers)
+
core.startGroup('Headers')
console.log('response.headers:', response.headers)
core.endGroup() // Headers
@@ -75,11 +91,13 @@ async function main() {
core.endGroup() // Data
// Outputs
+ core.info('📩 Setting Outputs')
core.setOutput('status', response.status)
core.setOutput('headers', response.headers)
core.setOutput('data', response.data)
+ // core.setOutput('url', response.request?.res?.responseUrl || '')
- core.info(`\u001b[32;1mFinished Success`)
+ core.info(`✅ \u001b[32;1mFinished Success`)
}
/**