From 14166d2b5549da0e804fd7ae3579e8cee5151901 Mon Sep 17 00:00:00 2001 From: dothq-robot <72629236+dothq-robot@users.noreply.github.com> Date: Tue, 16 Mar 2021 20:21:24 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20built=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/constants.js | 7 +++ lib/format.js | 34 +++++++++++ lib/input.js | 72 +++++++++++++++++++++++ lib/main.js | 149 +++++++++++++++++++++++++++++++++++++++++++++++ lib/utils.js | 44 ++++++++++++++ lib/validate.js | 60 +++++++++++++++++++ 6 files changed, 366 insertions(+) create mode 100644 lib/constants.js create mode 100644 lib/format.js create mode 100644 lib/input.js create mode 100644 lib/main.js create mode 100644 lib/utils.js create mode 100644 lib/validate.js diff --git a/lib/constants.js b/lib/constants.js new file mode 100644 index 00000000..d3f4105e --- /dev/null +++ b/lib/constants.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MAX_EMBED_FIELD_VALUE_LENGTH = exports.MAX_EMBED_FIELD_NAME_LENGTH = exports.MAX_EMBED_DESCRIPTION_LENGTH = exports.MAX_EMBED_TITLE_LENGTH = void 0; +exports.MAX_EMBED_TITLE_LENGTH = 256; +exports.MAX_EMBED_DESCRIPTION_LENGTH = 2048; +exports.MAX_EMBED_FIELD_NAME_LENGTH = 256; +exports.MAX_EMBED_FIELD_VALUE_LENGTH = 1024; diff --git a/lib/format.js b/lib/format.js new file mode 100644 index 00000000..361b162f --- /dev/null +++ b/lib/format.js @@ -0,0 +1,34 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.formatEvent = void 0; +const utils_1 = require("./utils"); +const formatters = { + push: pushFormatter, + pull_request: pullRequestFormatter, + release: releaseFormatter, +}; +function formatEvent(event, payload) { + utils_1.logDebug(JSON.stringify(payload, null, 2)); + let msg = "No further information"; + if (event in formatters) { + try { + return formatters[event](payload) || msg; + } + catch (e) { + utils_1.logDebug(`Failed to generate eventDetail for ${event}: ${e}\n${e.stack}`); + } + } + return msg; +} +exports.formatEvent = formatEvent; +function pushFormatter(payload) { + return `[\`${payload.head_commit.id.substring(0, 7)}\`](${payload.head_commit.url}) ${payload.head_commit.message}`; +} +function pullRequestFormatter(payload) { + return `[\`#${payload.pull_request.number}\`](${payload.pull_request.html_url}) ${payload.pull_request.title}`; +} +function releaseFormatter(payload) { + const { name, body } = payload.release; + const nameText = name ? `**${name}**` : ''; + return `${nameText}${(nameText && body) ? "\n" : ""}${body || ""}`; +} diff --git a/lib/input.js b/lib/input.js new file mode 100644 index 00000000..9ef9d7b8 --- /dev/null +++ b/lib/input.js @@ -0,0 +1,72 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getInputs = exports.statusOpts = void 0; +const core = __importStar(require("@actions/core")); +const utils_1 = require("./utils"); +exports.statusOpts = { + success: { + status: 'Success', + color: 0x28A745 + }, + failure: { + status: 'Failure', + color: 0xCB2431 + }, + cancelled: { + status: 'Cancelled', + color: 0xDBAB09 + } +}; +function getInputs() { + const webhook = core.getInput('webhook').trim() || process.env.DISCORD_WEBHOOK || ''; + const webhooks = webhook.split('\n').filter(x => x || false); + webhooks.forEach((w, i) => { + core.setSecret(w); + if (w.endsWith('/github')) { + utils_1.logWarning(`webhook ${i + 1}/${webhooks.length} has \`/github\` suffix! This may cause errors.`); + } + }); + const nodetail = utils_1.stob(core.getInput('nodetail')); + const nocontext = nodetail || utils_1.stob(core.getInput('nocontext')); + const noprefix = nodetail || utils_1.stob(core.getInput('noprefix')); + const inputs = { + webhooks: webhooks, + status: core.getInput('status').trim().toLowerCase(), + description: core.getInput('description').trim(), + content: core.getInput('content').trim(), + title: (core.getInput('title') || core.getInput('job')).trim(), + image: core.getInput('image').trim(), + color: parseInt(core.getInput('color')), + username: core.getInput('username').trim(), + avatar_url: core.getInput('avatar_url').trim(), + nocontext: nocontext, + noprefix: noprefix + }; + if (!inputs.webhooks.length) { + throw new Error("no webhook is given"); + } + if (!(inputs.status in exports.statusOpts)) { + throw new Error(`invalid status value: ${inputs.status}`); + } + return inputs; +} +exports.getInputs = getInputs; diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 00000000..1dede29e --- /dev/null +++ b/lib/main.js @@ -0,0 +1,149 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +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 __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getPayload = void 0; +const core_1 = require("@actions/core"); +const github = __importStar(require("@actions/github")); +const axios_1 = __importDefault(require("axios")); +const format_1 = require("./format"); +const input_1 = require("./input"); +const utils_1 = require("./utils"); +const validate_1 = require("./validate"); +function run() { + return __awaiter(this, void 0, void 0, function* () { + try { + utils_1.logInfo('Getting inputs...'); + const inputs = input_1.getInputs(); + utils_1.logInfo('Generating payload...'); + const payload = getPayload(inputs); + core_1.startGroup('Dump payload'); + utils_1.logInfo(JSON.stringify(payload, null, 2)); + core_1.endGroup(); + utils_1.logInfo(`Triggering ${inputs.webhooks.length} webhook${inputs.webhooks.length > 1 ? 's' : ''}...`); + yield Promise.all(inputs.webhooks.map(w => wrapWebhook(w.trim(), payload))); + } + catch (e) { + utils_1.logError(`Unexpected failure: ${e} (${e.message})`); + } + }); +} +function wrapWebhook(webhook, payload) { + return function () { + return __awaiter(this, void 0, void 0, function* () { + try { + yield axios_1.default.post(webhook, payload); + } + catch (e) { + if (e.response) { + utils_1.logError(`Webhook response: ${e.response.status}: ${JSON.stringify(e.response.data)}`); + } + else { + utils_1.logError(e); + } + } + }); + }(); +} +function getPayload(inputs) { + const ctx = github.context; + const { owner, repo } = ctx.repo; + const { eventName, sha, ref, workflow, actor, payload } = ctx; + const repoURL = `https://github.com/${owner}/${repo}`; + const workflowURL = `${repoURL}/commit/${sha}/checks`; + utils_1.logDebug(JSON.stringify(payload)); + const eventFieldTitle = `Event - ${eventName}`; + const eventDetail = format_1.formatEvent(eventName, payload); + let embed = { + color: inputs.color || input_1.statusOpts[inputs.status].color, + timestamp: (new Date()).toISOString() + }; + if (inputs.title) { + embed.title = inputs.title; + } + if (inputs.image) { + embed.image = { + url: inputs.image + }; + } + if (!inputs.noprefix) { + embed.title = input_1.statusOpts[inputs.status].status + (embed.title ? `: ${embed.title}` : ''); + } + if (inputs.description) { + embed.description = inputs.description; + } + if (!inputs.nocontext) { + embed.fields = [ + { + name: 'Repository', + value: `[${owner}/${repo}](${repoURL})`, + inline: true + }, + { + name: 'Ref', + value: ref, + inline: true + }, + { + name: eventFieldTitle, + value: eventDetail, + inline: false + }, + { + name: 'Triggered by', + value: actor, + inline: true + }, + { + name: 'Workflow', + value: `[${workflow}](${workflowURL})`, + inline: true + } + ]; + } + let discord_payload = { + embeds: [validate_1.fitEmbed(embed)] + }; + utils_1.logDebug(`embed: ${JSON.stringify(embed)}`); + if (inputs.username) { + discord_payload.username = inputs.username; + } + if (inputs.avatar_url) { + discord_payload.avatar_url = inputs.avatar_url; + } + if (inputs.content) { + discord_payload.content = inputs.content; + } + return discord_payload; +} +exports.getPayload = getPayload; +run(); diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 00000000..42a0c2fb --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,44 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.stob = exports.logWarning = exports.logInfo = exports.logDebug = exports.logError = void 0; +const core = __importStar(require("@actions/core")); +const NOFAIL = core.getInput('nofail').trim().toLowerCase() === 'true'; +function logError(msg) { + NOFAIL ? core.error(msg) : core.setFailed(msg); +} +exports.logError = logError; +function logDebug(msg) { + core.debug(msg); +} +exports.logDebug = logDebug; +function logInfo(msg) { + core.info(msg); +} +exports.logInfo = logInfo; +function logWarning(msg) { + core.warning(msg); +} +exports.logWarning = logWarning; +function stob(s) { + return s.trim().toLowerCase() === 'true'; +} +exports.stob = stob; diff --git a/lib/validate.js b/lib/validate.js new file mode 100644 index 00000000..d58f6bdd --- /dev/null +++ b/lib/validate.js @@ -0,0 +1,60 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fitEmbed = exports.truncStr = void 0; +const constants = __importStar(require("./constants")); +const utils_1 = require("./utils"); +function truncStr(msg, length) { + return msg.slice(0, length - 3) + '...'; +} +exports.truncStr = truncStr; +function fitEmbed(embed) { + if (embed.title) { + const titleLen = embed.title.length; + if (titleLen > constants.MAX_EMBED_TITLE_LENGTH) { + utils_1.logWarning(`embed title must be shorter than ${constants.MAX_EMBED_TITLE_LENGTH}, got ${titleLen}\n ${embed.title}`); + embed.title = truncStr(embed.title, constants.MAX_EMBED_TITLE_LENGTH); + } + } + if (embed.description) { + const descLen = embed.description.length; + if (descLen > constants.MAX_EMBED_DESCRIPTION_LENGTH) { + utils_1.logWarning(`embed description must be shorter than ${constants.MAX_EMBED_DESCRIPTION_LENGTH}, got ${descLen}\n ${embed.description}`); + embed.description = truncStr(embed.description, constants.MAX_EMBED_DESCRIPTION_LENGTH); + } + } + if (embed.fields) { + for (const field of embed.fields) { + const nameLen = field.name.length; + const valueLen = field.value.length; + if (nameLen > constants.MAX_EMBED_FIELD_NAME_LENGTH) { + utils_1.logWarning(`embed field name must be shorter than ${constants.MAX_EMBED_FIELD_NAME_LENGTH}, got ${nameLen}\n ${field.name}`); + field.name = truncStr(field.name, constants.MAX_EMBED_FIELD_NAME_LENGTH); + } + if (valueLen > constants.MAX_EMBED_FIELD_VALUE_LENGTH) { + utils_1.logWarning(`embed field value must be shorter than ${constants.MAX_EMBED_FIELD_VALUE_LENGTH}, got ${valueLen}\n ${field.value}`); + field.value = truncStr(field.value, constants.MAX_EMBED_FIELD_VALUE_LENGTH); + } + } + } + return embed; +} +exports.fitEmbed = fitEmbed;