UNPKG

opinionated-ci-pipeline

Version:

CI/CD on AWS with feature-branch builds, developer-environment deployments, and build status notifications.

182 lines (175 loc) 7.03 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/lambda/setupWebhooks/index.ts var setupWebhooks_exports = {}; __export(setupWebhooks_exports, { handler: () => handler }); module.exports = __toCommonJS(setupWebhooks_exports); var import_logger2 = require("@aws-lambda-powertools/logger"); // src/lambda/shared/api.ts var githubApiCall = async (token, path, method, body) => { return await fetch(`https://api.github.com/${path}`, { method, headers: { "Authorization": `Bearer ${token}`, "Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" }, body: body ? JSON.stringify(body) : void 0 }); }; var bitbucketApiCall = async (token, path, method, body) => { return await fetch(`https://api.bitbucket.org/2.0/${path}`, { method, headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }, body: body ? JSON.stringify(body) : void 0 }); }; // src/lambda/setupWebhooks/createWebhook.ts var createWebhook = async (repositoryHost, repositoryToken, repositoryName, webhookUrl, description) => { switch (repositoryHost.toLowerCase()) { case "github": return createGitHubWebhook(repositoryToken, repositoryName, webhookUrl); case "bitbucket": return createBitbucketWebhook(repositoryToken, repositoryName, webhookUrl, description); default: throw new Error(`Unsupported repository host: ${repositoryHost}`); } }; var createGitHubWebhook = async (repositoryToken, repositoryName, webhookUrl) => { const response = await githubApiCall(repositoryToken, `repos/${repositoryName}/hooks`, "POST", { name: "web", active: true, events: ["push"], config: { url: webhookUrl, content_type: "json" } }); if (response.status === 201) { return (await response.json()).id.toString(); } throw new Error(`Unable to create GitHub webhook. Status: ${response.status}, response: ${await response.text()}`); }; var createBitbucketWebhook = async (repositoryToken, repositoryName, webhookUrl, description) => { const response = await bitbucketApiCall(repositoryToken, `repositories/${repositoryName}/hooks`, "POST", { description, url: webhookUrl, active: true, events: ["repo:push"] }); if (response.status === 201) { return (await response.json()).uuid; } throw new Error(`Unable to create Bitbucket webhook. Status: ${response.status}, response: ${await response.text()}`); }; // src/lambda/setupWebhooks/deleteWebhook.ts var import_logger = require("@aws-lambda-powertools/logger"); var logger = new import_logger.Logger(); var deleteWebhook = async (repositoryHost, repositoryToken, repositoryName, webhookId) => { switch (repositoryHost.toLowerCase()) { case "github": return deleteGitHubWebhook(repositoryToken, repositoryName, webhookId); case "bitbucket": return deleteBitbucketWebhook(repositoryToken, repositoryName, webhookId); default: throw new Error(`Unsupported repository host: ${repositoryHost}`); } }; var deleteGitHubWebhook = async (repositoryToken, repositoryName, webhookId) => { const response = await githubApiCall(repositoryToken, `repos/${repositoryName}/hooks/${webhookId}`, "DELETE"); if (response.status === 204) { logger.info("Webhook deleted", { webhookId }); } else if (response.status == 404) { logger.info("Webhook not found", { webhookId }); } else { throw new Error(`Unable to delete GitHub webhook. Status: ${response.status}, response: ${await response.text()}`); } }; var deleteBitbucketWebhook = async (repositoryToken, repositoryName, webhookId) => { const response = await bitbucketApiCall(repositoryToken, `repositories/${repositoryName}/hooks/${webhookId}`, "DELETE"); if (response.status === 204) { logger.info("Webhook deleted", { webhookId }); } else if (response.status == 404) { logger.info("Webhook not found", { webhookId }); } else { throw new Error(`Unable to delete Bitbucket webhook. Status: ${response.status}, response: ${await response.text()}`); } }; // src/lambda/shared/ssm.ts var import_client_ssm = require("@aws-sdk/client-ssm"); var ssm = new import_client_ssm.SSMClient({}); var getSSMParameter = async (name) => { const repositoryToken = (await ssm.send(new import_client_ssm.GetParameterCommand({ Name: name, WithDecryption: true }))).Parameter?.Value; if (!repositoryToken) { throw new Error(`Unable to retrieve SSM parameter "${name}"`); } return repositoryToken; }; // src/lambda/setupWebhooks/index.ts var logger2 = new import_logger2.Logger(); var handler = async (event) => { logger2.info("Event", { event }); const properties = event.ResourceProperties; const repositoryToken = await getSSMParameter(properties.RepositoryTokenParamName); switch (event.RequestType) { case "Create": return await onCreate(properties, repositoryToken); case "Update": return await onUpdate(event.PhysicalResourceId, properties, repositoryToken); case "Delete": return await onDelete(event.PhysicalResourceId, properties, repositoryToken); default: throw new Error("Unsupported request type"); } }; var onCreate = async (properties, repositoryToken) => { logger2.info("Creating webhook"); const webhookId = await createWebhook(properties.RepositoryHost, repositoryToken, properties.RepositoryName, properties.WebhookUrl, `${properties.StackName} Mirror to AWS S3 Bucket`); logger2.info("Webhook created", { webhookId }); return { PhysicalResourceId: webhookId }; }; var onUpdate = async (webhookId, properties, repositoryToken) => { logger2.info("Updating webhook", { webhookId }); try { await onDelete(webhookId, properties, repositoryToken); } catch (e) { logger2.warn("Failed to delete webhook", { error: e }); } return await onCreate(properties, repositoryToken); }; var onDelete = async (webhookId, properties, repositoryToken) => { logger2.info("Deleting webhook", { webhookId }); await deleteWebhook(properties.RepositoryHost, repositoryToken, properties.RepositoryName, webhookId); return { PhysicalResourceId: webhookId }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { handler });