aws-delivlib
Version:
A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.
113 lines • 13.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (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.handler = exports.codePipeline = void 0;
const https = __importStar(require("https"));
// eslint-disable-next-line import/no-extraneous-dependencies
const client_codepipeline_1 = require("@aws-sdk/client-codepipeline");
// export for tests
exports.codePipeline = new client_codepipeline_1.CodePipeline();
/**
* Lambda handler for the codepipeline state change events
*
* {
* "version": "0",
* "id": event_Id,
* "detail-type": "CodePipeline Pipeline Execution State Change",
* "source": "aws.codepipeline",
* "account": Pipeline_Account,
* "time": TimeStamp,
* "region": "us-east-1",
* "resources": [
* "arn:aws:codepipeline:us-east-1:account_ID:myPipeline"
* ],
* "detail": {
* "pipeline": "myPipeline",
* "version": "1",
* "state": "STARTED",
* "execution-id": execution_Id
* }
* }
*/
async function handler(event) {
// Log the event so we can have a look in CloudWatch logs
process.stdout.write(`${JSON.stringify(event)}\n`);
const webhookUrls = event.webhookUrls || [];
if (webhookUrls.length === 0) {
throw new Error("Expected event field 'webhookUrls'");
}
const messageTemplate = event.message;
if (!messageTemplate) {
throw new Error("Expected event field 'message'");
}
const details = event.detail || {};
const pipelineName = details.pipeline;
const pipelineExecutionId = details['execution-id'];
if (!pipelineName || !pipelineExecutionId) {
process.stderr.write('Malformed event!\n');
return;
}
// Describe the revision that caused the pipeline to fail
const response = await exports.codePipeline.getPipelineExecution({ pipelineName, pipelineExecutionId });
process.stdout.write(`${JSON.stringify(response)}\n`);
const firstArtifact = (response.pipelineExecution?.artifactRevisions ?? [])[0];
const revisionSummary = firstArtifact?.revisionSummary ?? firstArtifact?.revisionId ?? `execution ${pipelineExecutionId}`;
// Find the action that caused the pipeline to fail (no pagination for now)
const actionResponse = await exports.codePipeline.listActionExecutions({ pipelineName, filter: { pipelineExecutionId } });
process.stdout.write(`${JSON.stringify(actionResponse)}\n`);
const failingActionDetails = actionResponse.actionExecutionDetails?.find(d => d.status === 'Failed');
const failingAction = failingActionDetails?.actionName || 'UNKNOWN';
const failureUrl = failingActionDetails?.output?.executionResult?.externalExecutionUrl || '???';
const message = messageTemplate
.replace(/\$PIPELINE/g, pipelineName)
.replace(/\$REVISION/g, revisionSummary)
.replace(/\$ACTION/g, failingAction)
.replace(/\$URL/g, failureUrl);
// Post the failure to all given Chime webhook URLs
await Promise.all(webhookUrls.map(url => sendChimeNotification(url, message)));
}
exports.handler = handler;
async function sendChimeNotification(url, message) {
return new Promise((ok, ko) => {
const req = https.request(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
}, (res) => {
if (res.statusCode !== 200) {
ko(new Error(`Server responded with ${res.statusCode}: ${JSON.stringify(res.headers)}`));
}
res.setEncoding('utf8');
res.on('data', () => { });
res.on('error', ko);
res.on('end', ok);
});
req.on('error', ko);
req.write(JSON.stringify({ Content: message }));
req.end();
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpZXItaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm5vdGlmaWVyLWhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSw2Q0FBK0I7QUFDL0IsNkRBQTZEO0FBQzdELHNFQUE4RTtBQUc5RSxtQkFBbUI7QUFDTixRQUFBLFlBQVksR0FBRyxJQUFJLGtDQUFZLEVBQUUsQ0FBQztBQUUvQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBQ0ksS0FBSyxVQUFVLE9BQU8sQ0FBQyxLQUFVO0lBQ3RDLHlEQUF5RDtJQUN6RCxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRW5ELE1BQU0sV0FBVyxHQUFhLEtBQUssQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO0lBQ3RELElBQUksV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxDQUFDLENBQUM7S0FBRTtJQUV4RixNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO0lBQ3RDLElBQUksQ0FBQyxlQUFlLEVBQUU7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7S0FBRTtJQUU1RSxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztJQUNuQyxNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDO0lBQ3RDLE1BQU0sbUJBQW1CLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBRXBELElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxtQkFBbUIsRUFBRTtRQUN6QyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQzNDLE9BQU87S0FDUjtJ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QUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3BCLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDaEQsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ1osQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgaHR0cHMgZnJvbSAnaHR0cHMnO1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgQXJ0aWZhY3RSZXZpc2lvbiwgQ29kZVBpcGVsaW5lIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNvZGVwaXBlbGluZSc7XG5cblxuLy8gZXhwb3J0IGZvciB0ZXN0c1xuZXhwb3J0IGNvbnN0IGNvZGVQaXBlbGluZSA9IG5ldyBDb2RlUGlwZWxpbmUoKTtcblxuLyoqXG4gKiBMYW1iZGEgaGFuZGxlciBmb3IgdGhlIGNvZGVwaXBlbGluZSBzdGF0ZSBjaGFuZ2UgZXZlbnRzXG4gKlxuICoge1xuICogICAgIFwidmVyc2lvblwiOiBcIjBcIixcbiAqICAgICBcImlkXCI6IGV2ZW50X0lkLFxuICogICAgIFwiZGV0YWlsLXR5cGVcIjogXCJDb2RlUGlwZWxpbmUgUGlwZWxpbmUgRXhlY3V0aW9uIFN0YXRlIENoYW5nZVwiLFxuICogICAgIFwic291cmNlXCI6IFwiYXdzLmNvZGVwaXBlbGluZVwiLFxuICogICAgIFwiYWNjb3VudFwiOiBQaXBlbGluZV9BY2NvdW50LFxuICogICAgIFwidGltZVwiOiBUaW1lU3RhbXAsXG4gKiAgICAgXCJyZWdpb25cIjogXCJ1cy1lYXN0LTFcIixcbiAqICAgICBcInJlc291cmNlc1wiOiBbXG4gKiAgICAgICAgIFwiYXJuOmF3czpjb2RlcGlwZWxpbmU6dXMtZWFzdC0xOmFjY291bnRfSUQ6bXlQaXBlbGluZVwiXG4gKiAgICAgXSxcbiAqICAgICBcImRldGFpbFwiOiB7XG4gKiAgICAgICAgIFwicGlwZWxpbmVcIjogXCJteVBpcGVsaW5lXCIsXG4gKiAgICAgICAgIFwidmVyc2lvblwiOiBcIjFcIixcbiAqICAgICAgICAgXCJzdGF0ZVwiOiBcIlNUQVJURURcIixcbiAqICAgICAgICAgXCJleGVjdXRpb24taWRcIjogZXhlY3V0aW9uX0lkXG4gKiAgICAgfVxuICogfVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihldmVudDogYW55KSB7XG4gIC8vIExvZyB0aGUgZXZlbnQgc28gd2UgY2FuIGhhdmUgYSBsb29rIGluIENsb3VkV2F0Y2ggbG9nc1xuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShldmVudCl9XFxuYCk7XG5cbiAgY29uc3Qgd2ViaG9va1VybHM6IHN0cmluZ1tdID0gZXZlbnQud2ViaG9va1VybHMgfHwgW107XG4gIGlmICh3ZWJob29rVXJscy5sZW5ndGggPT09IDApIHsgdGhyb3cgbmV3IEVycm9yKFwiRXhwZWN0ZWQgZXZlbnQgZmllbGQgJ3dlYmhvb2tVcmxzJ1wiKTsgfVxuXG4gIGNvbnN0IG1lc3NhZ2VUZW1wbGF0ZSA9IGV2ZW50Lm1lc3NhZ2U7XG4gIGlmICghbWVzc2FnZVRlbXBsYXRlKSB7IHRocm93IG5ldyBFcnJvcihcIkV4cGVjdGVkIGV2ZW50IGZpZWxkICdtZXNzYWdlJ1wiKTsgfVxuXG4gIGNvbnN0IGRldGFpbHMgPSBldmVudC5kZXRhaWwgfHwge307XG4gIGNvbnN0IHBpcGVsaW5lTmFtZSA9IGRldGFpbHMucGlwZWxpbmU7XG4gIGNvbnN0IHBpcGVsaW5lRXhlY3V0aW9uSWQgPSBkZXRhaWxzWydleGVjdXRpb24taWQnXTtcblxuICBpZiAoIXBpcGVsaW5lTmFtZSB8fCAhcGlwZWxpbmVFeGVjdXRpb25JZCkge1xuICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKCdNYWxmb3JtZWQgZXZlbnQhXFxuJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gRGVzY3JpYmUgdGhlIHJldmlzaW9uIHRoYXQgY2F1c2VkIHRoZSBwaXBlbGluZSB0byBmYWlsXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY29kZVBpcGVsaW5lLmdldFBpcGVsaW5lRXhlY3V0aW9uKHsgcGlwZWxpbmVOYW1lLCBwaXBlbGluZUV4ZWN1dGlvbklkIH0pO1xuICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShyZXNwb25zZSl9XFxuYCk7XG4gIGNvbnN0IGZpcnN0QXJ0aWZhY3Q6IEFydGlmYWN0UmV2aXNpb24gfCB1bmRlZmluZWQgPSAocmVzcG9uc2UucGlwZWxpbmVFeGVjdXRpb24/LmFydGlmYWN0UmV2aXNpb25zID8/IFtdKVswXTtcbiAgY29uc3QgcmV2aXNpb25TdW1tYXJ5ID0gZmlyc3RBcnRpZmFjdD8ucmV2aXNpb25TdW1tYXJ5ID8/IGZpcnN0QXJ0aWZhY3Q/LnJldmlzaW9uSWQgPz8gYGV4ZWN1dGlvbiAke3BpcGVsaW5lRXhlY3V0aW9uSWR9YDtcblxuICAvLyBGaW5kIHRoZSBhY3Rpb24gdGhhdCBjYXVzZWQgdGhlIHBpcGVsaW5lIHRvIGZhaWwgKG5vIHBhZ2luYXRpb24gZm9yIG5vdylcbiAgY29uc3QgYWN0aW9uUmVzcG9uc2UgPSBhd2FpdCBjb2RlUGlwZWxpbmUubGlzdEFjdGlvbkV4ZWN1dGlvbnMoeyBwaXBlbGluZU5hbWUsIGZpbHRlcjogeyBwaXBlbGluZUV4ZWN1dGlvbklkIH0gfSk7XG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KGFjdGlvblJlc3BvbnNlKX1cXG5gKTtcbiAgY29uc3QgZmFpbGluZ0FjdGlvbkRldGFpbHMgPSBhY3Rpb25SZXNwb25zZS5hY3Rpb25FeGVjdXRpb25EZXRhaWxzPy5maW5kKGQgPT4gZC5zdGF0dXMgPT09ICdGYWlsZWQnKTtcbiAgY29uc3QgZmFpbGluZ0FjdGlvbiA9IGZhaWxpbmdBY3Rpb25EZXRhaWxzPy5hY3Rpb25OYW1lIHx8ICdVTktOT1dOJztcbiAgY29uc3QgZmFpbHVyZVVybCA9IGZhaWxpbmdBY3Rpb25EZXRhaWxzPy5vdXRwdXQ/LmV4ZWN1dGlvblJlc3VsdD8uZXh0ZXJuYWxFeGVjdXRpb25VcmwgfHwgJz8/Pyc7XG5cbiAgY29uc3QgbWVzc2FnZSA9IG1lc3NhZ2VUZW1wbGF0ZVxuICAgIC5yZXBsYWNlKC9cXCRQSVBFTElORS9nLCBwaXBlbGluZU5hbWUpXG4gICAgLnJlcGxhY2UoL1xcJFJFVklTSU9OL2csIHJldmlzaW9uU3VtbWFyeSlcbiAgICAucmVwbGFjZSgvXFwkQUNUSU9OL2csIGZhaWxpbmdBY3Rpb24pXG4gICAgLnJlcGxhY2UoL1xcJFVSTC9nLCBmYWlsdXJlVXJsKTtcblxuICAvLyBQb3N0IHRoZSBmYWlsdXJlIHRvIGFsbCBnaXZlbiBDaGltZSB3ZWJob29rIFVSTHNcbiAgYXdhaXQgUHJvbWlzZS5hbGwod2ViaG9va1VybHMubWFwKHVybCA9PiBzZW5kQ2hpbWVOb3RpZmljYXRpb24odXJsLCBtZXNzYWdlKSkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzZW5kQ2hpbWVOb3RpZmljYXRpb24odXJsOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZykge1xuICByZXR1cm4gbmV3IFByb21pc2UoKG9rLCBrbykgPT4ge1xuICAgIGNvbnN0IHJlcSA9IGh0dHBzLnJlcXVlc3QodXJsLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgIH0sXG4gICAgfSwgKHJlcykgPT4ge1xuICAgICAgaWYgKHJlcy5zdGF0dXNDb2RlICE9PSAyMDApIHtcbiAgICAgICAga28obmV3IEVycm9yKGBTZXJ2ZXIgcmVzcG9uZGVkIHdpdGggJHtyZXMuc3RhdHVzQ29kZX06ICR7SlNPTi5zdHJpbmdpZnkocmVzLmhlYWRlcnMpfWApKTtcbiAgICAgIH1cblxuICAgICAgcmVzLnNldEVuY29kaW5nKCd1dGY4Jyk7XG4gICAgICByZXMub24oJ2RhdGEnLCAoKSA9PiB7IC8qIGdvYmJsZSBnb2JibGUgYW5kIGlnbm9yZSAqLyB9KTtcbiAgICAgIHJlcy5vbignZXJyb3InLCBrbyk7XG4gICAgICByZXMub24oJ2VuZCcsIG9rKTtcbiAgICB9KTtcblxuICAgIHJlcS5vbignZXJyb3InLCBrbyk7XG4gICAgcmVxLndyaXRlKEpTT04uc3RyaW5naWZ5KHsgQ29udGVudDogbWVzc2FnZSB9KSk7XG4gICAgcmVxLmVuZCgpO1xuICB9KTtcbn1cbiJdfQ==