renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
384 lines (383 loc) • 15.2 kB
JavaScript
import { __exportAll } from "../../../_virtual/_rolldown/runtime.js";
import { PLATFORM_BAD_CREDENTIALS, REPOSITORY_EMPTY, REPOSITORY_NOT_FOUND } from "../../../constants/error-messages.js";
import { regEx } from "../../../util/regex.js";
import { sanitize } from "../../../util/sanitize.js";
import { logger } from "../../../logger/index.js";
import { parseJson } from "../../../util/common.js";
import { coerceArray } from "../../../util/array.js";
import { initRepo as initRepo$1 } from "../../../util/git/index.js";
import { getNewBranchName, repoFingerprint } from "../util.js";
import { smartTruncate } from "../utils/pr-body.js";
import { buildCodeCommitClient, createPr as createPr$1, createPrApprovalRule, createPrComment, deleteComment, getCodeCommitUrl, getFile, getPr as getPr$1, getPrComments, getRepositoryInfo, listPullRequests, listRepositories, updateComment, updatePrDescription, updatePrStatus, updatePrTitle } from "./codecommit-client.js";
import { Buffer } from "node:buffer";
import { PullRequestStatusEnum } from "@aws-sdk/client-codecommit";
//#region lib/modules/platform/codecommit/index.ts
var codecommit_exports = /* @__PURE__ */ __exportAll({
addAssignees: () => addAssignees,
addReviewers: () => addReviewers,
createPr: () => createPr,
deleteLabel: () => deleteLabel,
ensureComment: () => ensureComment,
ensureCommentRemoval: () => ensureCommentRemoval,
ensureIssue: () => ensureIssue,
ensureIssueClosing: () => ensureIssueClosing,
experimental: () => true,
findIssue: () => findIssue,
findPr: () => findPr,
getBranchPr: () => getBranchPr,
getBranchStatus: () => getBranchStatus,
getBranchStatusCheck: () => getBranchStatusCheck,
getIssueList: () => getIssueList,
getJsonFile: () => getJsonFile,
getPr: () => getPr,
getPrList: () => getPrList,
getRawFile: () => getRawFile,
getRepos: () => getRepos,
id: () => id,
initPlatform: () => initPlatform,
initRepo: () => initRepo,
massageMarkdown: () => massageMarkdown,
maxBodyLength: () => maxBodyLength,
mergePr: () => mergePr,
setBranchStatus: () => setBranchStatus,
updatePr: () => updatePr
});
const id = "codecommit";
const platformConfig = { endpoint: "https://git-codecommit.us-east-1.amazonaws.com" };
let config = {};
async function initPlatform({ endpoint, username, password, token: awsToken }) {
const accessKeyId = username;
const secretAccessKey = password;
const env = process.env;
let region;
if (accessKeyId) env.AWS_ACCESS_KEY_ID = accessKeyId;
if (secretAccessKey) env.AWS_SECRET_ACCESS_KEY = secretAccessKey;
if (awsToken) env.AWS_SESSION_TOKEN = awsToken;
if (endpoint) {
region = regEx(/.*codecommit\.(?<region>.+)\.amazonaws\.com/).exec(endpoint)?.groups?.region;
if (region) env.AWS_REGION = region;
else logger.warn("Can't parse region, make sure your endpoint is correct");
}
buildCodeCommitClient();
await listRepositories();
platformConfig.endpoint = endpoint ?? `https://git-codecommit.${env.AWS_REGION ?? "us-east-1"}.amazonaws.com/`;
return { endpoint: platformConfig.endpoint };
}
async function initRepo({ repository }) {
logger.debug(`initRepo("${repository}")`);
config = { repository };
let repo;
try {
repo = await getRepositoryInfo(repository);
} catch (err) {
logger.error({ err }, "Could not find repository");
throw new Error(REPOSITORY_NOT_FOUND);
}
if (!repo?.repositoryMetadata) {
logger.error({ repository }, "Could not find repository");
throw new Error(REPOSITORY_NOT_FOUND);
}
logger.debug({ repositoryDetails: repo }, "Repository details");
const metadata = repo.repositoryMetadata;
const url = getCodeCommitUrl(metadata, repository);
try {
await initRepo$1({ url });
} catch (err) {
logger.debug({ err }, "Failed to git init");
throw new Error(PLATFORM_BAD_CREDENTIALS);
}
if (!metadata.defaultBranch || !metadata.repositoryId) {
logger.debug("Repo is empty");
throw new Error(REPOSITORY_EMPTY);
}
const defaultBranch = metadata.defaultBranch;
config.defaultBranch = defaultBranch;
logger.debug(`${repository} default branch = ${defaultBranch}`);
return {
repoFingerprint: repoFingerprint(metadata.repositoryId, platformConfig.endpoint),
defaultBranch,
isFork: false
};
}
async function getPrList() {
logger.debug("getPrList()");
if (config.prList) return config.prList;
const listPrsResponse = await listPullRequests(config.repository);
const fetchedPrs = [];
if (listPrsResponse && !listPrsResponse.pullRequestIds) return fetchedPrs;
const prIds = coerceArray(listPrsResponse.pullRequestIds);
for (const prId of prIds) {
const prRes = await getPr$1(prId);
if (!prRes?.pullRequest) continue;
const prInfo = prRes.pullRequest;
const pr = {
targetBranch: prInfo.pullRequestTargets[0].destinationReference,
sourceBranch: prInfo.pullRequestTargets[0].sourceReference,
destinationCommit: prInfo.pullRequestTargets[0].destinationCommit,
sourceCommit: prInfo.pullRequestTargets[0].sourceCommit,
state: prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN ? "open" : "closed",
number: Number.parseInt(prId, 10),
title: prInfo.title,
body: prInfo.description,
createdAt: prInfo.creationDate?.toISOString()
};
fetchedPrs.push(pr);
}
config.prList = fetchedPrs;
logger.debug(`Retrieved Pull Requests, count: ${fetchedPrs.length}`);
return fetchedPrs;
}
async function findPr({ branchName, prTitle, state = "all" }) {
let prsFiltered = [];
try {
const prs = await getPrList();
const refsHeadBranchName = getNewBranchName(branchName);
prsFiltered = prs.filter((item) => item.sourceBranch === refsHeadBranchName);
if (prTitle) prsFiltered = prsFiltered.filter((item) => item.title.toUpperCase() === prTitle.toUpperCase());
switch (state) {
case "all": break;
case "!open":
prsFiltered = prsFiltered.filter((item) => item.state !== "open");
break;
default:
prsFiltered = prsFiltered.filter((item) => item.state === "open");
break;
}
} catch (err) {
logger.error({ err }, "findPr error");
}
if (prsFiltered.length === 0) return null;
return prsFiltered[0];
}
async function getBranchPr(branchName) {
logger.debug(`getBranchPr(${branchName})`);
const existingPr = await findPr({
branchName,
state: "open"
});
return existingPr ? getPr(existingPr.number) : null;
}
async function getPr(pullRequestId) {
logger.debug(`getPr(${pullRequestId})`);
const prRes = await getPr$1(`${pullRequestId}`);
if (!prRes?.pullRequest) return null;
const prInfo = prRes.pullRequest;
let prState;
if (prInfo.pullRequestTargets[0].mergeMetadata?.isMerged) prState = "merged";
else prState = prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN ? "open" : "closed";
return {
sourceBranch: prInfo.pullRequestTargets[0].sourceReference,
sourceCommit: prInfo.pullRequestTargets[0].sourceCommit,
state: prState,
number: pullRequestId,
title: prInfo.title,
targetBranch: prInfo.pullRequestTargets[0].destinationReference,
destinationCommit: prInfo.pullRequestTargets[0].destinationCommit,
body: prInfo.description
};
}
async function getRepos() {
logger.debug("Autodiscovering AWS CodeCommit repositories");
let reposRes;
try {
reposRes = await listRepositories();
} catch (error) {
logger.error({ error }, "Could not retrieve repositories");
return [];
}
const res = [];
const repoNames = coerceArray(reposRes?.repositories);
for (const repo of repoNames)
// v8 ignore else -- TODO: add test #40625
if (repo.repositoryName) res.push(repo.repositoryName);
return res;
}
function massageMarkdown(input) {
return input.replace("you tick the rebase/retry checkbox", "PR is renamed to start with \"rebase!\"").replace("checking the rebase/retry box above", "renaming the PR to start with \"rebase!\"").replace(regEx(/<\/?summary>/g), "**").replace(regEx(/<\/?details>/g), "").replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), "").replace(regEx(/\]\(\.\.\/issues\//g), "](#").replace(regEx(/\]\(\.\.\/pull\//g), "](../../pull-requests/").replace(regEx(/(?<hiddenComment><!--renovate-(?:debug|config-hash):.*?-->)/g), "[//]: # ($<hiddenComment>)");
}
/**
* Unsed, no Dashboard
*/
function maxBodyLength() {
return Infinity;
}
async function getJsonFile(fileName, repoName, branchOrTag) {
return parseJson(await getRawFile(fileName, repoName, branchOrTag), fileName);
}
async function getRawFile(fileName, repoName, branchOrTag) {
const fileRes = await getFile(repoName ?? config.repository, fileName, branchOrTag);
if (!fileRes?.fileContent) return null;
return Buffer.from(fileRes.fileContent).toString();
}
const AMAZON_MAX_BODY_LENGTH = 10239;
async function createPr({ sourceBranch, targetBranch, prTitle: title, prBody: body }) {
const prCreateRes = await createPr$1(title, sanitize(smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH)), sourceBranch, targetBranch, config.repository);
if (!prCreateRes.pullRequest?.title || !prCreateRes.pullRequest?.pullRequestId || !prCreateRes.pullRequest?.description || !prCreateRes.pullRequest?.pullRequestTargets?.length) throw new Error("Could not create pr, missing PR info");
return {
number: Number.parseInt(prCreateRes.pullRequest.pullRequestId, 10),
state: "open",
title: prCreateRes.pullRequest.title,
sourceBranch,
targetBranch,
sourceCommit: prCreateRes.pullRequest.pullRequestTargets[0].sourceCommit,
destinationCommit: prCreateRes.pullRequest.pullRequestTargets[0].destinationCommit,
sourceRepo: config.repository,
body: prCreateRes.pullRequest.description
};
}
async function updatePr({ number: prNo, prTitle: title, prBody: body, state }) {
logger.debug(`updatePr(${prNo}, ${title}, body)`);
let cachedPr = void 0;
const cachedPrs = config.prList ?? [];
for (const p of cachedPrs)
// v8 ignore else -- TODO: add test #40625
if (p.number === prNo) cachedPr = p;
// v8 ignore else -- TODO: add test #40625
if (body && cachedPr?.body !== body) await updatePrDescription(`${prNo}`, smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH));
// v8 ignore else -- TODO: add test #40625
if (title && cachedPr?.title !== title) await updatePrTitle(`${prNo}`, title);
const prStatusInput = state === "closed" ? PullRequestStatusEnum.CLOSED : PullRequestStatusEnum.OPEN;
// v8 ignore else -- TODO: add test #40625
if (cachedPr?.state !== prStatusInput) try {
await updatePrStatus(`${prNo}`, prStatusInput);
} catch {}
}
/* v8 ignore next */
async function mergePr({ branchName, id: prNo }) {
logger.debug(`mergePr(${prNo}, ${branchName})`);
await getPr$1(`${prNo}`);
return Promise.resolve(false);
}
async function addReviewers(prNo, reviewers) {
const approvalRuleContents = `{"Version":"2018-11-08","Statements": [{"Type": "Approvers","NumberOfApprovalsNeeded":${reviewers.length},"ApprovalPoolMembers": ${JSON.stringify(reviewers)}}]}`;
const res = await createPrApprovalRule(`${prNo}`, approvalRuleContents);
// v8 ignore else -- TODO: add test #40625
if (res) {
const approvalRule = res.approvalRule;
logger.debug({ approvalRule }, `Approval Rule Added to PR #${prNo}:`);
}
}
/* v8 ignore next */
function addAssignees(_iid, _assignees) {
return Promise.resolve();
}
/* v8 ignore next */
function findIssue(_title) {
return Promise.resolve(null);
}
/* v8 ignore next */
function ensureIssue(_cfg) {
return Promise.resolve(null);
}
/* v8 ignore next */
function getIssueList() {
return Promise.resolve([]);
}
/* v8 ignore next */
function ensureIssueClosing(_title) {
return Promise.resolve();
}
/* v8 ignore next */
function deleteLabel(_prNumber, _label) {
return Promise.resolve();
}
/* v8 ignore next */
function getBranchStatus(branchName) {
logger.debug(`getBranchStatus(${branchName})`);
logger.debug("returning branch status yellow, because getBranchStatus isnt supported on aws yet");
return Promise.resolve("yellow");
}
/* v8 ignore next */
function getBranchStatusCheck(branchName, context) {
logger.debug(`getBranchStatusCheck(${branchName}, context=${context})`);
logger.debug("returning null, because getBranchStatusCheck is not supported on aws yet");
return Promise.resolve(null);
}
/* v8 ignore next */
function setBranchStatus(_cfg) {
return Promise.resolve();
}
async function ensureComment({ number, topic, content }) {
logger.debug(`ensureComment(${number}, ${topic}, content)`);
const header = topic ? `### ${topic}\n\n` : "";
const body = `${header}${sanitize(content)}`;
let prCommentsResponse;
try {
prCommentsResponse = await getPrComments(`${number}`);
} catch (err) {
logger.debug({ err }, "Unable to retrieve pr comments");
return false;
}
let commentId = void 0;
let commentNeedsUpdating = false;
if (!prCommentsResponse?.commentsForPullRequestData) return false;
for (const commentObj of prCommentsResponse.commentsForPullRequestData) {
if (!commentObj?.comments) continue;
const firstCommentContent = commentObj.comments[0].content;
if ((topic && firstCommentContent?.startsWith(header)) === true || !topic && firstCommentContent === body) {
commentId = commentObj.comments[0].commentId;
commentNeedsUpdating = firstCommentContent !== body;
break;
}
}
if (!commentId) {
const thisPr = (await getPrList()).filter((item) => item.number === number);
if (!thisPr[0].sourceCommit || !thisPr[0].destinationCommit) return false;
await createPrComment(`${number}`, config.repository, body, thisPr[0].destinationCommit, thisPr[0].sourceCommit);
logger.info({
repository: config.repository,
prNo: number,
topic
}, "Comment added");
} else if (commentNeedsUpdating && commentId) {
await updateComment(commentId, body);
logger.debug({
repository: config.repository,
prNo: number,
topic
}, "Comment updated");
} else logger.debug({
repository: config.repository,
prNo: number,
topic
}, "Comment is already up-to-date");
return true;
}
async function ensureCommentRemoval(removeConfig) {
const { number: prNo } = removeConfig;
const key = removeConfig.type === "by-topic" ? removeConfig.topic : removeConfig.content;
logger.debug(`Ensuring comment "${key}" in #${prNo} is removed`);
let prCommentsResponse;
try {
prCommentsResponse = await getPrComments(`${prNo}`);
} catch (err) {
logger.debug({ err }, "Unable to retrieve pr comments");
return;
}
if (!prCommentsResponse?.commentsForPullRequestData) {
logger.debug("commentsForPullRequestData not found");
return;
}
let commentIdToRemove;
for (const commentObj of prCommentsResponse.commentsForPullRequestData) {
if (!commentObj?.comments) {
logger.debug("comments object not found under commentsForPullRequestData");
continue;
}
for (const comment of commentObj.comments)
// v8 ignore else -- TODO: add test #40625
if ((removeConfig.type === "by-topic" && comment.content?.startsWith(`### ${removeConfig.topic}\n\n`)) === true || removeConfig.type === "by-content" && removeConfig.content === comment.content?.trim()) {
commentIdToRemove = comment.commentId;
break;
}
// v8 ignore else -- TODO: add test #40625
if (commentIdToRemove) {
await deleteComment(commentIdToRemove);
logger.debug(`comment "${key}" in PR #${prNo} was removed`);
break;
}
}
}
//#endregion
export { codecommit_exports, id };
//# sourceMappingURL=index.js.map