Convert action to ts

- Add optional header support
- Add optional body support
This commit is contained in:
Joel Male 2020-08-26 09:36:04 +10:00
parent 749e2dcbc6
commit 00f958821e
18 changed files with 1836 additions and 46 deletions

1
.eslintignore Normal file
View file

@ -0,0 +1 @@
dist/

18
.eslintrc.json Normal file
View file

@ -0,0 +1,18 @@
{
"env": {
"commonjs": true,
"es6": true,
"jest": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
}
}

56
.gitignore vendored Normal file
View file

@ -0,0 +1,56 @@
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
__tests__/runner/*
lib/**/*

3
.prettierignore Normal file
View file

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

10
.prettierrc.json Normal file
View file

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

View file

@ -1,20 +0,0 @@
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"]

View file

@ -11,24 +11,15 @@ Supports all [workflow event types](https://developer.github.com/webhooks/#event
## Usage
Sending a string:
Example:
```yml
- name: Webhook
uses: joelwmale/webhook-action@master
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
data: "Hello from github actions!"
```
Sending a body of data:
```yml
- name: Webhook
uses: joelwmale/webhook-action@master
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
data: "{'deployment': 'finished', 'project': 'actions'}"
with:
url: ${{ secrets.WEBHOOK_URL }}
headers: "{Content-Type: 'application/json'}"
body: "{event: 'Deployment', project: 'joelwmale/webhook-action'}"
```
It is **highly** recommended to use the action is an explicit commit SHA-1:
@ -37,19 +28,29 @@ It is **highly** recommended to use the action is an explicit commit SHA-1:
### Arguments
* ```yml
data: "Hello from github actions!"
```
### Headers
* ```yml
data: "{'deployment': 'finished', 'project': 'actions'}"
```
Allows you to send custom headers with the request
```yml
headers: "{Repository: 'joelwmale/webhook-action'}"
```
### Body
Allows you to send a json payload in a string format
```yml
body: "{event: 'Deployment', project: 'joelwmale/webhook-action'}"
```
### Environment
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.
The action is expecpecting a few environmental variables:
* **`WEBHOOK_URL`** (**required**): This is the webhook url to send the payload to.
* **`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
## Issues

13
action.yml Normal file
View file

@ -0,0 +1,13 @@
name: 'Webhook'
description: 'Wait a designated number of milliseconds'
inputs:
milliseconds: # id of input
description: 'number of milliseconds to wait'
required: true
default: '1000'
outputs:
time: # output will be available to future steps
description: 'The message to output'
runs:
using: 'node12'
main: 'dist/index.js'

67
dist/http.js vendored Normal file
View file

@ -0,0 +1,67 @@
"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());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.http = void 0;
var Http = (function () {
function Http() {
}
Http.prototype.make = function (url, headers, body) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2, new Promise(function (resolve, reject) {
fetch(url, _this.getOptions('post', headers, body))
.then(function (res) { return resolve(res.body); })
.catch(function (res) { return reject(res.body); });
})];
});
});
};
Http.prototype.getOptions = function (method, headers, body) {
var options = {
headers: JSON.parse(headers),
method: method
};
options.body = JSON.stringify(body);
options.headers['content-type'] = 'application/json';
return options;
};
return Http;
}());
exports.http = new Http();
//# sourceMappingURL=http.js.map

1
dist/http.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;IAAA;IAuBA,CAAC;IAtBO,mBAAI,GAAV,UAAW,GAAW,EAAE,OAAe,EAAE,IAAY;;;;gBACnD,WAAO,IAAI,OAAO,CAAC,UAAC,OAAO,EAAE,MAAM;wBACjC,KAAK,CAAC,GAAG,EAAE,KAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;6BAC/C,IAAI,CAAC,UAAC,GAAG,IAAK,OAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAjB,CAAiB,CAAC;6BAChC,KAAK,CAAC,UAAC,GAAG,IAAK,OAAA,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAhB,CAAgB,CAAC,CAAC;oBACtC,CAAC,CAAC,EAAC;;;KACJ;IAED,yBAAU,GAAV,UAAW,MAAc,EAAE,OAAe,EAAE,IAAY;QACtD,IAAM,OAAO,GAAQ;YACnB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YAC5B,MAAM,QAAA;SACP,CAAC;QAGF,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAGpC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAErD,OAAO,OAAO,CAAC;IACjB,CAAC;IACH,WAAC;AAAD,CAAC,AAvBD,IAuBC;AAEY,QAAA,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC"}

64
dist/main.js vendored Normal file
View file

@ -0,0 +1,64 @@
"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());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var core = require("@actions/core");
var http_1 = require("./http");
function run() {
var _a;
return __awaiter(this, void 0, void 0, function () {
var url, headers, body;
return __generator(this, function (_b) {
try {
url = core.getInput('url');
headers = (_a = core.getInput('headers')) !== null && _a !== void 0 ? _a : {};
body = core.getInput('body');
core.info("Sending webhook request to " + url + "...");
core.debug((new Date()).toTimeString());
http_1.http.make(url, headers, body).then(function (res) { return console.log('hi'); });
core.info((new Date()).toTimeString());
core.setOutput('time', new Date().toTimeString());
}
catch (error) {
core.setFailed(error.message);
}
return [2];
});
});
}
run();
//# sourceMappingURL=main.js.map

1
dist/main.js.map vendored Normal file
View file

@ -0,0 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,oCAAsC;AACtC,+BAA8B;AAG9B,SAAe,GAAG;;;;;YAChB,IAAI;gBACI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC3B,OAAO,SAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,mCAAI,EAAE,CAAC;gBACzC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAGnC,IAAI,CAAC,IAAI,CAAC,gCAA8B,GAAG,QAAK,CAAC,CAAC;gBAGlD,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;gBAGxC,WAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,UAAC,GAAG,IAAK,OAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAjB,CAAiB,CAAC,CAAC;gBAG/D,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;gBAGvC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;aACnD;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAC/B;;;;CACF;AAED,GAAG,EAAE,CAAC"}

View file

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

41
package.json Normal file
View file

@ -0,0 +1,41 @@
{
"name": "webhook-action",
"version": "1.0.1",
"private": true,
"description": "Github Webhook Action",
"main": "dist/main.js",
"scripts": {
"build": "tsc",
"format": "prettier --write **/*.ts",
"lint": "eslint src/**/*.ts",
"package": "ncc build --source-map"
},
"repository": {
"type": "git",
"url": "git+https://github.com/joelwmale/webhook-action.git"
},
"keywords": [
"actions",
"node",
"webhook",
"action"
],
"author": "Joel Male",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.2.4",
"fetch": "^1.1.0"
},
"devDependencies": {
"@types/jest": "^26.0.10",
"@types/node": "^14.6.0",
"@typescript-eslint/parser": "^3.9.1",
"@vercel/ncc": "^0.23.0",
"eslint": "^7.5.0",
"eslint-plugin-github": "^4.1.1",
"eslint-plugin-jest": "^23.20.0",
"js-yaml": "^3.14.0",
"prettier": "2.0.5",
"typescript": "^3.9.7"
}
}

26
src/http.ts Normal file
View file

@ -0,0 +1,26 @@
class Http {
async make(url: string, headers: string, body: string): Promise<any> {
return new Promise((resolve, reject) => {
fetch(url, this.getOptions('post', headers, body))
.then((res) => resolve(res.body))
.catch((res) => reject(res.body));
});
}
getOptions(method: string, headers: string, body: string) {
const options: any = {
headers: JSON.parse(headers),
method
};
// stringify the body
options.body = JSON.stringify(body);
// set these headers
options.headers['content-type'] = 'application/json';
return options;
}
}
export const http = new Http();

30
src/main.ts Normal file
View file

@ -0,0 +1,30 @@
import * as core from '@actions/core';
import { http } from './http';
// most @actions toolkit packages have async methods
async function run() {
try {
const url = core.getInput('url');
const headers = core.getInput('headers') ?? '';
const body = core.getInput('body') ?? '';
// initial info
core.info(`Sending webhook request to ${url}...`);
// debug start
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
// make the request
http.make(url, headers, body).then((res) => console.log('hi'));
// debug end
core.info((new Date()).toTimeString());
// output the time it took
core.setOutput('time', new Date().toTimeString());
} catch (error) {
core.setFailed(error.message);
}
}
run();

21
tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"strictPropertyInitialization": false,
"jsx": "react",
"lib": [
"dom",
"es7"
],
"module": "commonjs",
"noImplicitReturns": true,
"noImplicitAny": false,
"outDir": "./dist/",
"removeComments": true,
"sourceMap": true,
"strict": true,
"target": "es5"
},
"exclude": ["node_modules"]
}

1461
yarn.lock Normal file

File diff suppressed because it is too large Load diff