add persist handler

Signed-off-by: Frank Jogeleit <frank.jogeleit@lovoo.com>
This commit is contained in:
Frank Jogeleit 2023-02-04 13:28:08 +01:00
parent 0f4905efb7
commit 2c712a0557
10 changed files with 1266 additions and 720 deletions

View file

@ -132,6 +132,17 @@ jobs:
data: '{ "key": "value" }' data: '{ "key": "value" }'
files: '{ "file": "${{ github.workspace }}/testfile.txt" }' files: '{ "file": "${{ github.workspace }}/testfile.txt" }'
- name: Request Postman Echo POST and persist response
uses: ./
with:
url: 'https://postman-echo.com/post'
method: 'POST'
file: "${{ github.workspace }}/testfile.txt"
responseFile: "${{ github.workspace }}/response.json"
- name: Output responseFile
run: |
cat "${{ github.workspace }}/response.json"
- name: Request Postman Echo POST Multipart without data - name: Request Postman Echo POST Multipart without data
uses: ./ uses: ./
with: with:

View file

@ -42,6 +42,7 @@ jobs:
|preventFailureOnNoResponse| Prevent this Action to fail if the request respond without an response. 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' || |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 || |httpsCA| Certificate authority as string in PEM format ||
|responseFile| Persist the response data to the specified file path ||
### Response ### Response

View file

@ -50,6 +50,9 @@ inputs:
httpsCA: httpsCA:
description: 'Certificate authority as string in PEM format' description: 'Certificate authority as string in PEM format'
required: false required: false
responseFile:
description: 'Persist the response data to the specified file path'
required: false
outputs: outputs:
response: response:
description: 'HTTP Response Content' description: 'HTTP Response Content'

1888
dist/index.js vendored

File diff suppressed because it is too large Load diff

14
package-lock.json generated
View file

@ -13,7 +13,7 @@
}, },
"devDependencies": { "devDependencies": {
"@vercel/ncc": "^0.36.1", "@vercel/ncc": "^0.36.1",
"axios": "^1.2.6", "axios": "^1.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"yargs": "^17.6.2" "yargs": "^17.6.2"
}, },
@ -78,9 +78,9 @@
"dev": true "dev": true
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.2.6", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.6.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.2.tgz",
"integrity": "sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==", "integrity": "sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.0", "follow-redirects": "^1.15.0",
@ -386,9 +386,9 @@
"dev": true "dev": true
}, },
"axios": { "axios": {
"version": "1.2.6", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.6.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.2.tgz",
"integrity": "sha512-rC/7F08XxZwjMV4iuWv+JpD3E0Ksqg9nac4IIg6RwNuF0JTeWoCo/mBNG54+tNhhI11G3/VDRbdDQTs9hGp4pQ==", "integrity": "sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==",
"dev": true, "dev": true,
"requires": { "requires": {
"follow-redirects": "^1.15.0", "follow-redirects": "^1.15.0",

View file

@ -20,7 +20,7 @@
"homepage": "https://github.com/fjogeleit/http-request-action#readme", "homepage": "https://github.com/fjogeleit/http-request-action#readme",
"devDependencies": { "devDependencies": {
"@vercel/ncc": "^0.36.1", "@vercel/ncc": "^0.36.1",
"axios": "^1.2.6", "axios": "^1.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"yargs": "^17.6.2" "yargs": "^17.6.2"
}, },

View file

@ -7,6 +7,10 @@ class GithubActions {
core.debug(message) core.debug(message)
} }
info(message) {
core.info(message)
}
warning(message) { warning(message) {
core.warning(message) core.warning(message)
} }
@ -21,6 +25,10 @@ class GithubActions {
} }
class LogActions { class LogActions {
info(message) {
console.info(message)
}
debug(message) { debug(message) {
console.info(message) console.info(message)
} }

30
src/handler/persist.js Normal file
View 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, err => {
if (!err) {
actions.info(`response persisted successfully at ${filePath}`)
return
}
actions.warning(JSON.stringify({ message: error.message, data: response.data }))
})
}
module.exports = { createPersistHandler }

View file

@ -4,6 +4,7 @@ const axios = require('axios');
const FormData = require('form-data') const FormData = require('form-data')
const fs = require('fs') const fs = require('fs')
const url = require('url'); const url = require('url');
const { GithubActions } = require('./githubActions');
const METHOD_GET = 'GET' const METHOD_GET = 'GET'
const METHOD_POST = 'POST' const METHOD_POST = 'POST'
@ -19,12 +20,12 @@ const CONTENT_TYPE_URLENCODED = 'application/x-www-form-urlencoded'
* @param {string} param0.data Request Body as string, default {} * @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.files Map of Request Files (name: absolute path) as JSON String, default: {}
* @param {string} param0.file Single request file (absolute path) * @param {string} param0.file Single request file (absolute path)
* @param {*} param0.actions * @param {GithubActions} param0.actions
* @param {number[]} param0.ignoredCodes Prevent Action to fail if the API response with one of this StatusCodes * @param {number[]} param0.ignoredCodes Prevent Action to fail if the API response with one of this StatusCodes
* @param {boolean} param0.preventFailureOnNoResponse Prevent Action to fail if the API respond without Response * @param {boolean} param0.preventFailureOnNoResponse Prevent Action to fail if the API respond without Response
* @param {boolean} param0.escapeData Escape unescaped JSON content in data * @param {boolean} param0.escapeData Escape unescaped JSON content in data
* *
* @returns {Promise<void>} * @returns {Promise<axios.AxiosResponse>}
*/ */
const request = async({ method, instanceConfig, data, files, file, actions, ignoredCodes, preventFailureOnNoResponse, escapeData }) => { const request = async({ method, instanceConfig, data, files, file, actions, ignoredCodes, preventFailureOnNoResponse, escapeData }) => {
try { try {
@ -47,7 +48,7 @@ const request = async({ method, instanceConfig, data, files, file, actions, igno
data = convertToFormData(dataJson, filesJson) data = convertToFormData(dataJson, filesJson)
instanceConfig = await updateConfig(instanceConfig, data, actions) instanceConfig = await updateConfig(instanceConfig, data, actions)
} catch(error) { } catch(error) {
actions.setFailed({ message: `Unable to convert Data and Files into FormData: ${error.message}`, data: dataJson, files: filesJson }) actions.setFailed(JSON.stringify({ message: `Unable to convert Data and Files into FormData: ${error.message}`, data: dataJson, files: filesJson }))
return return
} }
} }
@ -75,6 +76,7 @@ const request = async({ method, instanceConfig, data, files, file, actions, igno
actions.debug('Instance Configuration: ' + JSON.stringify(instanceConfig)) actions.debug('Instance Configuration: ' + JSON.stringify(instanceConfig))
/** @type {axios.AxiosInstance} */
const instance = axios.create(instanceConfig); const instance = axios.create(instanceConfig);
actions.debug('Request Data: ' + JSON.stringify(requestData)) actions.debug('Request Data: ' + JSON.stringify(requestData))
@ -84,6 +86,8 @@ const request = async({ method, instanceConfig, data, files, file, actions, igno
actions.setOutput('response', JSON.stringify(response.data)) actions.setOutput('response', JSON.stringify(response.data))
actions.setOutput('headers', response.headers) actions.setOutput('headers', response.headers)
return response
} catch (error) { } catch (error) {
if ((typeof error === 'object') && (error.isAxiosError === true)) { if ((typeof error === 'object') && (error.isAxiosError === true)) {
const { name, message, code, response } = error const { name, message, code, response } = error

View file

@ -5,6 +5,7 @@ const axios = require('axios');
const https = require('https'); const https = require('https');
const { request, METHOD_POST } = require('./httpClient'); const { request, METHOD_POST } = require('./httpClient');
const { GithubActions } = require('./githubActions'); const { GithubActions } = require('./githubActions');
const { createPersistHandler } = require('./handler/persist');
let customHeaders = {} let customHeaders = {}
@ -45,15 +46,27 @@ if (!!core.getInput('username') || !!core.getInput('password')) {
const data = core.getInput('data') || '{}'; const data = core.getInput('data') || '{}';
const files = core.getInput('files') || '{}'; const files = core.getInput('files') || '{}';
const file = core.getInput('file') const file = core.getInput('file')
const responseFile = core.getInput('responseFile')
const method = core.getInput('method') || METHOD_POST; const method = core.getInput('method') || METHOD_POST;
const preventFailureOnNoResponse = core.getInput('preventFailureOnNoResponse') === 'true'; const preventFailureOnNoResponse = core.getInput('preventFailureOnNoResponse') === 'true';
const escapeData = core.getInput('escapeData') === 'true'; const escapeData = core.getInput('escapeData') === 'true';
const ignoreStatusCodes = core.getInput('ignoreStatusCodes') const ignoreStatusCodes = core.getInput('ignoreStatusCodes');
let ignoredCodes = [] let ignoredCodes = [];
if (typeof ignoreStatusCodes === 'string' && ignoreStatusCodes.length > 0) { if (typeof ignoreStatusCodes === 'string' && ignoreStatusCodes.length > 0) {
ignoredCodes = ignoreStatusCodes.split(',').map(statusCode => parseInt(statusCode.trim())) ignoredCodes = ignoreStatusCodes.split(',').map(statusCode => parseInt(statusCode.trim()))
} }
request({ data, method, instanceConfig, preventFailureOnNoResponse, escapeData, files, file, ignoredCodes, actions: new GithubActions() }) const handler = [];
const actions = new GithubActions();
if (!!responseFile) {
handler.push(createPersistHandler(responseFile, actions))
}
request({ data, method, instanceConfig, preventFailureOnNoResponse, escapeData, files, file, ignoredCodes, actions }).then(response => {
if (typeof response == 'object') {
handler.forEach(h => h(response))
}
})