Compare commits

..

No commits in common. "develop" and "1.0.0" have entirely different histories.

27 changed files with 51 additions and 54794 deletions

View File

@ -1,2 +0,0 @@
dist
node_nodules

View File

@ -1,33 +0,0 @@
{
"env": {
"node": true,
"es6": true,
"jest": true
},
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": [
"jest",
"@typescript-eslint"
],
"extends": [
"plugin:github/recommended",
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"github/no-then": "off",
"import/no-namespace": "off",
"i18n-text/no-en": "off"
}
}

View File

@ -1,9 +0,0 @@
version: 2
updates:
# Enable version updates for npm
- package-ecosystem: "npm"
# Look for `package.json` and `lock` files in the `root` directory
directory: "/"
# Check the npm registry for updates every day (weekdays)
schedule:
interval: "weekly"

View File

@ -1,40 +0,0 @@
name: Tests
on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
release:
types:
- created
jobs:
tests:
name: Tests
runs-on: ubuntu-20.04
strategy:
fail-fast: true
matrix:
node-version: [20.x]
stability: [prefer-stable]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile --${{ matrix.stability }}
- name: Execute tests
run: yarn test

1
.gitignore vendored
View File

@ -1 +0,0 @@
node_modules/*

View File

@ -1,3 +0,0 @@
dist/
lib/
node_modules/

View File

@ -1,10 +0,0 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid"
}

20
Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM debian:9.8-slim
LABEL "version"="1.0.0"
LABEL "repository"="https://github.com/joelwmale/webhook-action"
LABEL "homepage"="https://github.com/joelwmale/webhook-action"
LABEL "maintainer"="Joel Male <joel@joelmale.com>"
LABEL "com.github.actions.name"="Webhook Action"
LABEL "com.github.actions.description"="Posts data to an endpoint on any event"
LABEL "com.github.actions.icon"="message-square"
LABEL "com.github.actions.color"="gray-dark"
# Install curl
RUN apt-get update && apt-get install -y curl
# Add the entry point
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Load the entry point
ENTRYPOINT ["/entrypoint.sh"]

103
README.md
View File

@ -3,7 +3,7 @@
[![GitHub Release][ico-release]][link-github-release]
[![License][ico-license]](LICENSE)
A Github Action for sending a webhook event any endpoint
A Github Action for sending data to an endpoint
Supports all [workflow event types](https://developer.github.com/webhooks/#events)
@ -11,96 +11,47 @@ Supports all [workflow event types](https://developer.github.com/webhooks/#event
## Usage
Example:
Sending a string:
```yml
- name: Webhook
uses: joelwmale/webhook-action@master
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
with:
url: ${{ secrets.WEBHOOK_URL }}
headers: '{"repository": "joelwmale/webhook-action"}'
body: '{"event": "deployment", "repository": "joelwmale/webhook-action"}'
github_event_payload: true
data: "Hello from github actions!"
```
Sending a body of data:
```yml
- name: Webhook
uses: joelwmale/webhook-action@master
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
with:
data: "{'deployment': 'finished', 'project': 'actions'}"
```
It is **highly** recommended to use the action is an explicit commit SHA-1:
`uses = "joelwmale/webhook-action@{SHA-1}"` to find a commit click [here.](https://github.com/joelwmale/webhook-action/commits/master)
`uses = "joelwmale/webhook-action@master@{SHA-1}"` to find a commit click here: https://github.com/joelwmale/webhook-action/commits/master
## Action Input
### Arguments
The action has support for the following input variables (arguments):
* ```yml
data: "Hello from github actions!"
```
* **`url`** (**required**): The url to send the webhook to
* **`headers`** (**optional**): Any headers you want to be sent with the webhook
* **`body`** (**optional**): The body of data send with the webhook
* **`insecure`** (**optional**): Enables calling to known self-signed or invalid SSL certificates
* **`github_event_payload`** (**optional**): Enables forwarding the Github event payload to your webhook.
* ```yml
data: "{'deployment': 'finished', 'project': 'actions'}"
```
You can find more information on how to use these input variables below.
### Environment
## Arguments
The action is expecting a single environment variable of your data. This can be pre-encoded json string, or just a message. Format it to how your API is expecting.
#### URL
**Required:** true
The URL to send the webhook to
```yml
url: ${{ secrets.WEBHOOK_URL }}
```
or
```yml
url: https://webhook.site/8b1b1b1b-8b1b-8b1b-8b1b-8b1b1b1b1b1b
```
#### Headers
**Required:** false
Allows you to send custom headers with the request
```yml
headers: '{"repository": "joelwmale/webhook-action"}'
```
#### Body
**Required:** false
**Must be a stringified JSON payload**
Allows you to send a custom JSON object to the webhook
```yml
body: '{"event": "deployment", "repository": "joelwmale/webhook-action"}'
```
#### Insecure
**Required:** false
**Default:** false
Allows you to send a webhook to a known self-signed or invalid SSL certificate
```yml
insecure: true
```
#### Github Event Payload
**Required:** false
**Default:** false
Allows you to send the Github event payload to your webhook
The payload will be sent as a JSON object under the key `githubEventPayload` on the root of the payload sent to your webhook
```yml
github_event_payload: true
```
* **`WEBHOOK_URL`** (**required**): This is the webhook url to send the payload to.
## Issues

View File

@ -1,31 +0,0 @@
import {http} from '../src/http'
import {expect, test} from '@jest/globals'
test('it makes a post request', async () => {
const url = 'https://httpbin.org/post'
const body = '{"hello": "world"}'
const res = await http.make(url, body)
expect(res.status).toBe(200)
})
test('it makes a post request with insecure', async () => {
const url = 'https://httpbin.org/post'
const body = '{"hello": "world"}'
const insecure = true
const res = await http.make(url, body, null, insecure)
expect(res.status).toBe(200)
})
test('it makes a post request with headers', async () => {
const url = 'https://httpbin.org/post'
const body = '{"hello": "world"}'
const headers = '{"Content-Type": "application/json"}'
const res = await http.make(url, body, headers)
expect(res.status).toBe(200)
})
test('it doesnt require a body', async () => {
const url = 'https://httpbin.org/post'
const res = await http.make(url, null)
expect(res.status).toBe(200)
})

View File

@ -1,28 +0,0 @@
name: 'Webhook Action'
author: "Joel Male"
description: 'Send a webhook event to anywhere!'
branding:
icon: 'alert-octagon'
color: 'gray-dark'
inputs:
url:
description: 'The url to send the webhook event to'
required: true
headers:
description: 'Additional headers to send alongside the defaults'
required: false
body:
description: 'The data sent to the webhook'
required: false
insecure:
description: 'Enables calling to known self-signed or invalid SSL certificates'
required: false
github_event_payload:
description: 'Include the github event payload that triggered the action in the payload'
required: false
outputs:
status:
description: 'The status of the webhook event'
runs:
using: 'node20'
main: 'dist/index.js'

View File

@ -1 +0,0 @@
module.exports = {presets: ['@babel/preset-env']}

452
dist/37.index.js vendored
View File

@ -1,452 +0,0 @@
"use strict";
exports.id = 37;
exports.ids = [37];
exports.modules = {
/***/ 4037:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "toFormData": () => (/* binding */ toFormData)
/* harmony export */ });
/* harmony import */ var fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2777);
/* harmony import */ var formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8010);
let s = 0;
const S = {
START_BOUNDARY: s++,
HEADER_FIELD_START: s++,
HEADER_FIELD: s++,
HEADER_VALUE_START: s++,
HEADER_VALUE: s++,
HEADER_VALUE_ALMOST_DONE: s++,
HEADERS_ALMOST_DONE: s++,
PART_DATA_START: s++,
PART_DATA: s++,
END: s++
};
let f = 1;
const F = {
PART_BOUNDARY: f,
LAST_BOUNDARY: f *= 2
};
const LF = 10;
const CR = 13;
const SPACE = 32;
const HYPHEN = 45;
const COLON = 58;
const A = 97;
const Z = 122;
const lower = c => c | 0x20;
const noop = () => {};
class MultipartParser {
/**
* @param {string} boundary
*/
constructor(boundary) {
this.index = 0;
this.flags = 0;
this.onHeaderEnd = noop;
this.onHeaderField = noop;
this.onHeadersEnd = noop;
this.onHeaderValue = noop;
this.onPartBegin = noop;
this.onPartData = noop;
this.onPartEnd = noop;
this.boundaryChars = {};
boundary = '\r\n--' + boundary;
const ui8a = new Uint8Array(boundary.length);
for (let i = 0; i < boundary.length; i++) {
ui8a[i] = boundary.charCodeAt(i);
this.boundaryChars[ui8a[i]] = true;
}
this.boundary = ui8a;
this.lookbehind = new Uint8Array(this.boundary.length + 8);
this.state = S.START_BOUNDARY;
}
/**
* @param {Uint8Array} data
*/
write(data) {
let i = 0;
const length_ = data.length;
let previousIndex = this.index;
let {lookbehind, boundary, boundaryChars, index, state, flags} = this;
const boundaryLength = this.boundary.length;
const boundaryEnd = boundaryLength - 1;
const bufferLength = data.length;
let c;
let cl;
const mark = name => {
this[name + 'Mark'] = i;
};
const clear = name => {
delete this[name + 'Mark'];
};
const callback = (callbackSymbol, start, end, ui8a) => {
if (start === undefined || start !== end) {
this[callbackSymbol](ui8a && ui8a.subarray(start, end));
}
};
const dataCallback = (name, clear) => {
const markSymbol = name + 'Mark';
if (!(markSymbol in this)) {
return;
}
if (clear) {
callback(name, this[markSymbol], i, data);
delete this[markSymbol];
} else {
callback(name, this[markSymbol], data.length, data);
this[markSymbol] = 0;
}
};
for (i = 0; i < length_; i++) {
c = data[i];
switch (state) {
case S.START_BOUNDARY:
if (index === boundary.length - 2) {
if (c === HYPHEN) {
flags |= F.LAST_BOUNDARY;
} else if (c !== CR) {
return;
}
index++;
break;
} else if (index - 1 === boundary.length - 2) {
if (flags & F.LAST_BOUNDARY && c === HYPHEN) {
state = S.END;
flags = 0;
} else if (!(flags & F.LAST_BOUNDARY) && c === LF) {
index = 0;
callback('onPartBegin');
state = S.HEADER_FIELD_START;
} else {
return;
}
break;
}
if (c !== boundary[index + 2]) {
index = -2;
}
if (c === boundary[index + 2]) {
index++;
}
break;
case S.HEADER_FIELD_START:
state = S.HEADER_FIELD;
mark('onHeaderField');
index = 0;
// falls through
case S.HEADER_FIELD:
if (c === CR) {
clear('onHeaderField');
state = S.HEADERS_ALMOST_DONE;
break;
}
index++;
if (c === HYPHEN) {
break;
}
if (c === COLON) {
if (index === 1) {
// empty header field
return;
}
dataCallback('onHeaderField', true);
state = S.HEADER_VALUE_START;
break;
}
cl = lower(c);
if (cl < A || cl > Z) {
return;
}
break;
case S.HEADER_VALUE_START:
if (c === SPACE) {
break;
}
mark('onHeaderValue');
state = S.HEADER_VALUE;
// falls through
case S.HEADER_VALUE:
if (c === CR) {
dataCallback('onHeaderValue', true);
callback('onHeaderEnd');
state = S.HEADER_VALUE_ALMOST_DONE;
}
break;
case S.HEADER_VALUE_ALMOST_DONE:
if (c !== LF) {
return;
}
state = S.HEADER_FIELD_START;
break;
case S.HEADERS_ALMOST_DONE:
if (c !== LF) {
return;
}
callback('onHeadersEnd');
state = S.PART_DATA_START;
break;
case S.PART_DATA_START:
state = S.PART_DATA;
mark('onPartData');
// falls through
case S.PART_DATA:
previousIndex = index;
if (index === 0) {
// boyer-moore derrived algorithm to safely skip non-boundary data
i += boundaryEnd;
while (i < bufferLength && !(data[i] in boundaryChars)) {
i += boundaryLength;
}
i -= boundaryEnd;
c = data[i];
}
if (index < boundary.length) {
if (boundary[index] === c) {
if (index === 0) {
dataCallback('onPartData', true);
}
index++;
} else {
index = 0;
}
} else if (index === boundary.length) {
index++;
if (c === CR) {
// CR = part boundary
flags |= F.PART_BOUNDARY;
} else if (c === HYPHEN) {
// HYPHEN = end boundary
flags |= F.LAST_BOUNDARY;
} else {
index = 0;
}
} else if (index - 1 === boundary.length) {
if (flags & F.PART_BOUNDARY) {
index = 0;
if (c === LF) {
// unset the PART_BOUNDARY flag
flags &= ~F.PART_BOUNDARY;
callback('onPartEnd');
callback('onPartBegin');
state = S.HEADER_FIELD_START;
break;
}
} else if (flags & F.LAST_BOUNDARY) {
if (c === HYPHEN) {
callback('onPartEnd');
state = S.END;
flags = 0;
} else {
index = 0;
}
} else {
index = 0;
}
}
if (index > 0) {
// when matching a possible boundary, keep a lookbehind reference
// in case it turns out to be a false lead
lookbehind[index - 1] = c;
} else if (previousIndex > 0) {
// if our boundary turned out to be rubbish, the captured lookbehind
// belongs to partData
const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength);
callback('onPartData', 0, previousIndex, _lookbehind);
previousIndex = 0;
mark('onPartData');
// reconsider the current character even so it interrupted the sequence
// it could be the beginning of a new sequence
i--;
}
break;
case S.END:
break;
default:
throw new Error(`Unexpected state entered: ${state}`);
}
}
dataCallback('onHeaderField');
dataCallback('onHeaderValue');
dataCallback('onPartData');
// Update properties for the next call
this.index = index;
this.state = state;
this.flags = flags;
}
end() {
if ((this.state === S.HEADER_FIELD_START && this.index === 0) ||
(this.state === S.PART_DATA && this.index === this.boundary.length)) {
this.onPartEnd();
} else if (this.state !== S.END) {
throw new Error('MultipartParser.end(): stream ended unexpectedly');
}
}
}
function _fileName(headerValue) {
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);
if (!m) {
return;
}
const match = m[2] || m[3] || '';
let filename = match.slice(match.lastIndexOf('\\') + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#(\d{4});/g, (m, code) => {
return String.fromCharCode(code);
});
return filename;
}
async function toFormData(Body, ct) {
if (!/multipart/i.test(ct)) {
throw new TypeError('Failed to fetch');
}
const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
if (!m) {
throw new TypeError('no or bad content-type header, no multipart boundary');
}
const parser = new MultipartParser(m[1] || m[2]);
let headerField;
let headerValue;
let entryValue;
let entryName;
let contentType;
let filename;
const entryChunks = [];
const formData = new formdata_polyfill_esm_min_js__WEBPACK_IMPORTED_MODULE_1__/* .FormData */ .Ct();
const onPartData = ui8a => {
entryValue += decoder.decode(ui8a, {stream: true});
};
const appendToFile = ui8a => {
entryChunks.push(ui8a);
};
const appendFileToFormData = () => {
const file = new fetch_blob_from_js__WEBPACK_IMPORTED_MODULE_0__/* .File */ .$B(entryChunks, filename, {type: contentType});
formData.append(entryName, file);
};
const appendEntryToFormData = () => {
formData.append(entryName, entryValue);
};
const decoder = new TextDecoder('utf-8');
decoder.decode();
parser.onPartBegin = function () {
parser.onPartData = onPartData;
parser.onPartEnd = appendEntryToFormData;
headerField = '';
headerValue = '';
entryValue = '';
entryName = '';
contentType = '';
filename = null;
entryChunks.length = 0;
};
parser.onHeaderField = function (ui8a) {
headerField += decoder.decode(ui8a, {stream: true});
};
parser.onHeaderValue = function (ui8a) {
headerValue += decoder.decode(ui8a, {stream: true});
};
parser.onHeaderEnd = function () {
headerValue += decoder.decode();
headerField = headerField.toLowerCase();
if (headerField === 'content-disposition') {
// matches either a quoted-string or a token (RFC 2616 section 19.5.1)
const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);
if (m) {
entryName = m[2] || m[3] || '';
}
filename = _fileName(headerValue);
if (filename) {
parser.onPartData = appendToFile;
parser.onPartEnd = appendFileToFormData;
}
} else if (headerField === 'content-type') {
contentType = headerValue;
}
headerValue = '';
headerField = '';
};
for await (const chunk of Body) {
parser.write(chunk);
}
parser.end();
return formData;
}
/***/ })
};
;

28
dist/http.js vendored
View File

@ -1,28 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.http = void 0;
const node_fetch_1 = require("node-fetch");
const https = require("https");
class Http {
make(url, body, headers = null, ignoreCertificate = false) {
return new Promise(resolve => {
(0, node_fetch_1.default)(url, this.getOptions('post', headers, body, ignoreCertificate)).then((res) => resolve(res));
});
}
getOptions(method, headers, body, ignoreCertificate) {
const options = {
headers: headers ? JSON.parse(headers) : {},
method
};
if (body) {
options.body = body;
}
if (ignoreCertificate) {
options.agent = new https.Agent({ rejectUnauthorized: false });
}
options.headers['content-type'] = 'application/json';
return options;
}
}
exports.http = new Http();
//# sourceMappingURL=http.js.map

1
dist/http.js.map vendored
View File

@ -1 +0,0 @@
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";;;AAAA,2CAA8B;AAC9B,+BAA+B;AAE/B,MAAM,IAAI;IACR,IAAI,CACF,GAAW,EACX,IAAmB,EACnB,UAAyB,IAAI,EAC7B,oBAAoC,KAAK;QAEzC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC3B,IAAA,oBAAK,EACH,GAAG,EACH,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAC1D,CAAC,IAAI,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,UAAU,CACR,MAAc,EACd,OAAsB,EACtB,IAAmB,EACnB,iBAAiC;QAEjC,MAAM,OAAO,GAAQ;YACnB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;YAC3C,MAAM;SACP,CAAA;QAED,IAAI,IAAI,EAAE,CAAC;YAET,OAAO,CAAC,IAAI,GAAG,IAAI,CAAA;QACrB,CAAC;QAED,IAAI,iBAAiB,EAAE,CAAC;YAEtB,OAAO,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,EAAC,kBAAkB,EAAE,KAAK,EAAC,CAAC,CAAA;QAC9D,CAAC;QAGD,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;QAEpD,OAAO,OAAO,CAAA;IAChB,CAAC;CACF;AAEY,QAAA,IAAI,GAAG,IAAI,IAAI,EAAE,CAAA"}

38600
dist/index.js vendored

File diff suppressed because one or more lines are too long

23
dist/licenses.txt vendored
View File

@ -1,23 +0,0 @@
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 - 2020 Node Fetch Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

68
dist/main.js vendored
View File

@ -1,68 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const core = require("@actions/core");
const http_1 = require("./http");
const github_1 = require("@actions/github");
function run() {
return __awaiter(this, void 0, void 0, function* () {
const url = core.getInput('url')
? core.getInput('url')
: process.env.WEBHOOK_URL
? process.env.WEBHOOK_URL
: '';
const headers = core.getInput('headers')
? core.getInput('headers')
: process.env.headers
? process.env.headers
: null;
let body = core.getInput('body')
? core.getInput('body')
: process.env.data
? process.env.data
: null;
const insecure = core.getInput('insecure')
? core.getInput('insecure') === 'true'
: process.env.insecure
? process.env.insecure === 'true'
: false;
const githubEventPayload = core.getInput('github_event_payload') === 'true';
if (githubEventPayload) {
const decodedBody = JSON.parse(body || '{}');
decodedBody.githubEventPayload = github_1.context.payload || {};
body = JSON.stringify(decodedBody);
}
if (!url) {
core.setFailed('A url is required to run this action.');
throw new Error('A url is required to run this action.');
}
core.info(`Sending webhook request to ${url}`);
http_1.http
.make(url, body, headers, insecure)
.then(res => {
if (res.status >= 400) {
error(res.status);
return;
}
})
.catch(err => {
core.info(`Error: ${err}`);
error(err.status);
return;
});
});
}
function error(statusCode) {
core.setFailed(`Received status code: ${statusCode}`);
throw new Error(`Request failed with status code: ${statusCode}`);
}
run();
//# sourceMappingURL=main.js.map

1
dist/main.js.map vendored
View File

@ -1 +0,0 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,sCAAqC;AACrC,iCAA2B;AAC3B,4CAAuC;AAEvC,SAAe,GAAG;;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC9B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACtB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW;gBACvB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW;gBACzB,CAAC,CAAC,EAAE,CAAA;QAER,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YACtC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAC1B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;gBACnB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO;gBACrB,CAAC,CAAC,IAAI,CAAA;QAEV,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC9B,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACvB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI;gBAChB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI;gBAClB,CAAC,CAAC,IAAI,CAAA;QAEV,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YACxC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,MAAM;YACtC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ;gBACpB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM;gBACjC,CAAC,CAAC,KAAK,CAAA;QAEX,MAAM,kBAAkB,GAAG,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,KAAK,MAAM,CAAA;QAG3E,IAAI,kBAAkB,EAAE,CAAC;YAEvB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAA;YAG5C,WAAW,CAAC,kBAAkB,GAAG,gBAAO,CAAC,OAAO,IAAI,EAAE,CAAA;YAGtD,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QACpC,CAAC;QAED,IAAI,CAAC,GAAG,EAAE,CAAC;YAET,IAAI,CAAC,SAAS,CAAC,uCAAuC,CAAC,CAAA;YAEvD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAA;QAC1D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,8BAA8B,GAAG,EAAE,CAAC,CAAA;QAG9C,WAAI;aACD,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC;aAClC,IAAI,CAAC,GAAG,CAAC,EAAE;YAEV,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;gBAEtB,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBACjB,OAAM;YACR,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,CAAC,EAAE;YACX,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,CAAA;YAC1B,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YACjB,OAAM;QACR,CAAC,CAAC,CAAA;IACN,CAAC;CAAA;AAED,SAAS,KAAK,CAAC,UAAU;IAEvB,IAAI,CAAC,SAAS,CAAC,yBAAyB,UAAU,EAAE,CAAC,CAAA;IAErD,MAAM,IAAI,KAAK,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAA;AACnE,CAAC;AAED,GAAG,EAAE,CAAA"}

4
entrypoint.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/sh
set -eu
curl -X POST -H "Content-Type: application/json" --data "{ \"data\": \"$data\" }" $WEBHOOK_URL

View File

@ -1,7 +0,0 @@
module.exports = {
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
'^.+\\.(js)$': 'babel-jest'
},
transformIgnorePatterns: []
}

10235
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
{
"name": "webhook-action",
"version": "2.4.1",
"description": "Github Webhook Action",
"main": "dist/main.js",
"scripts": {
"build": "tsc && ncc build --license licenses.txt",
"format": "prettier --write '**/*.ts'",
"format-check": "prettier --check '**/*.ts'",
"lint": "eslint src/**/*.ts",
"test": "jest",
"all": "npm run format && npm run lint && npm run test&& npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/joelwmale/webhook-action.git"
},
"keywords": [
"github",
"actions",
"node",
"webhook",
"action"
],
"author": "Joel Male",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@vercel/ncc": "^0.38.1",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@babel/preset-env": "^7.20.2",
"@types/node": "^18.19.26",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^5.62.0",
"babel-jest": "^29.3.1",
"eslint": "^8.57.0",
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-jest": "^27.9.0",
"https": "^1.0.0",
"jest": "^29.7.0",
"js-yaml": "^4.1.0",
"prettier": "3.2.5",
"semver": "^7.6.0",
"ts-jest": "^29.0.3",
"typescript": "^5.4.3",
"uuid": "^9.0.0"
}
}

View File

@ -1,47 +0,0 @@
import fetch from 'node-fetch'
import https = require('https')
class Http {
make(
url: string,
body: string | null,
headers: string | null = null,
ignoreCertificate: boolean | null = false
): Promise<any> {
return new Promise(resolve => {
fetch(
url,
this.getOptions('post', headers, body, ignoreCertificate)
).then((res: any) => resolve(res))
})
}
getOptions(
method: string,
headers: string | null,
body: string | null,
ignoreCertificate: boolean | null
) {
const options: any = {
headers: headers ? JSON.parse(headers) : {},
method
}
if (body) {
// parse the body
options.body = body
}
if (ignoreCertificate) {
// ignore the certificate by not rejecting authorized servers
options.agent = new https.Agent({rejectUnauthorized: false})
}
// set these headers
options.headers['content-type'] = 'application/json'
return options
}
}
export const http = new Http()

View File

@ -1,78 +0,0 @@
import * as core from '@actions/core'
import {http} from './http'
import {context} from '@actions/github'
async function run() {
const url = core.getInput('url')
? core.getInput('url')
: process.env.WEBHOOK_URL
? process.env.WEBHOOK_URL
: ''
const headers = core.getInput('headers')
? core.getInput('headers')
: process.env.headers
? process.env.headers
: null
let body = core.getInput('body')
? core.getInput('body')
: process.env.data
? process.env.data
: null
const insecure = core.getInput('insecure')
? core.getInput('insecure') === 'true'
: process.env.insecure
? process.env.insecure === 'true'
: false
const githubEventPayload = core.getInput('github_event_payload') === 'true'
// if github_event is set to true, append it to the body
if (githubEventPayload) {
// decode the body
const decodedBody = JSON.parse(body || '{}')
// set the github event
decodedBody.githubEventPayload = context.payload || {}
// re-set the body
body = JSON.stringify(decodedBody)
}
if (!url) {
// validate a url
core.setFailed('A url is required to run this action.')
// error
throw new Error('A url is required to run this action.')
}
core.info(`Sending webhook request to ${url}`)
// make the request
http
.make(url, body, headers, insecure)
.then(res => {
// if the status code is not 2xx
if (res.status >= 400) {
// throw an error
error(res.status)
return
}
})
.catch(err => {
core.info(`Error: ${err}`)
error(err.status)
return
})
}
function error(statusCode) {
// set the action to failed
core.setFailed(`Received status code: ${statusCode}`)
// throw an error
throw new Error(`Request failed with status code: ${statusCode}`)
}
run()

View File

@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "es6",
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"strictPropertyInitialization": false,
"jsx": "react",
"lib": [
"dom",
"es6"
],
"module": "commonjs",
"noImplicitReturns": true,
"noImplicitAny": false,
"outDir": "./dist/",
"rootDir": "./src/",
"removeComments": true,
"sourceMap": true,
"strict": true,
"skipLibCheck": true
},
"exclude": ["node_modules", "**/*.test.ts"]
}

4946
yarn.lock

File diff suppressed because it is too large Load Diff