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
JavaScript
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
});