renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
753 lines • 34.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.updatePr = exports.setBranchStatus = exports.mergePr = exports.initRepo = exports.initPlatform = exports.getRepos = exports.getPrList = exports.massageMarkdown = exports.getPr = exports.getIssueList = exports.getJsonFile = exports.getRawFile = exports.getIssue = exports.getBranchStatusCheck = exports.getBranchStatus = exports.getBranchPr = exports.findPr = exports.findIssue = exports.ensureIssueClosing = exports.ensureIssue = exports.ensureCommentRemoval = exports.ensureComment = exports.deleteLabel = exports.createPr = exports.addReviewers = exports.addAssignees = exports.id = void 0;
exports.resetPlatform = resetPlatform;
exports.maxBodyLength = maxBodyLength;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const semver_1 = tslib_1.__importDefault(require("semver"));
const error_messages_1 = require("../../../constants/error-messages");
const logger_1 = require("../../../logger");
const array_1 = require("../../../util/array");
const common_1 = require("../../../util/common");
const env_1 = require("../../../util/env");
const git = tslib_1.__importStar(require("../../../util/git"));
const gitea_1 = require("../../../util/http/gitea");
const promises_1 = require("../../../util/promises");
const sanitize_1 = require("../../../util/sanitize");
const url_1 = require("../../../util/url");
const pr_body_1 = require("../pr-body");
const util_1 = require("../util");
const pr_body_2 = require("../utils/pr-body");
const helper = tslib_1.__importStar(require("./gitea-helper"));
const gitea_helper_1 = require("./gitea-helper");
const pr_cache_1 = require("./pr-cache");
const utils_1 = require("./utils");
exports.id = 'gitea';
const defaults = {
hostType: 'gitea',
endpoint: 'https://gitea.com/',
version: '0.0.0',
isForgejo: false,
};
let config = {};
let botUserID;
let botUserName;
function resetPlatform() {
config = {};
botUserID = undefined;
botUserName = undefined;
defaults.hostType = 'gitea';
defaults.endpoint = 'https://gitea.com/';
defaults.version = '0.0.0';
defaults.isForgejo = false;
(0, gitea_1.setBaseUrl)(defaults.endpoint);
}
function toRenovateIssue(data) {
return {
number: data.number,
state: data.state,
title: data.title,
body: data.body,
};
}
function matchesState(actual, expected) {
if (expected === 'all') {
return true;
}
if (expected.startsWith('!')) {
return actual !== expected.substring(1);
}
return actual === expected;
}
function findCommentByTopic(comments, topic) {
return comments.find((c) => c.body.startsWith(`### ${topic}\n\n`)) ?? null;
}
function findCommentByContent(comments, content) {
return comments.find((c) => c.body.trim() === content) ?? null;
}
function getLabelList() {
if (config.labelList === null) {
const repoLabels = helper
.getRepoLabels(config.repository, {
memCache: false,
})
.then((labels) => {
logger_1.logger.debug(`Retrieved ${labels.length} repo labels`);
return labels;
});
const orgLabels = helper
.getOrgLabels(config.repository.split('/')[0], {
memCache: false,
})
.then((labels) => {
logger_1.logger.debug(`Retrieved ${labels.length} org labels`);
return labels;
})
.catch((err) => {
// Will fail if owner of repo is not org or Gitea version < 1.12
logger_1.logger.debug(`Unable to fetch organization labels`);
return [];
});
config.labelList = Promise.all([repoLabels, orgLabels]).then((labels) => [].concat(...labels));
}
return config.labelList;
}
async function lookupLabelByName(name) {
logger_1.logger.debug(`lookupLabelByName(${name})`);
const labelList = await getLabelList();
return labelList.find((l) => l.name === name)?.id ?? null;
}
async function fetchRepositories({ topic, sort, order, }) {
const repos = await helper.searchRepos({
uid: botUserID,
archived: false,
...(topic && {
topic: true,
q: topic,
}),
...(sort && {
sort,
}),
...(order && {
order,
}),
});
return repos.filter(utils_1.usableRepo).map((r) => r.full_name);
}
const platform = {
async initPlatform({ endpoint, token, }) {
if (!token) {
throw new Error('Init: You must configure a Gitea personal access token');
}
if (endpoint) {
let baseEndpoint = (0, utils_1.trimTrailingApiPath)(endpoint);
baseEndpoint = (0, url_1.ensureTrailingSlash)(baseEndpoint);
defaults.endpoint = baseEndpoint;
}
else {
logger_1.logger.debug('Using default Gitea endpoint: ' + defaults.endpoint);
}
(0, gitea_1.setBaseUrl)(defaults.endpoint);
let gitAuthor;
try {
const user = await helper.getCurrentUser({ token });
gitAuthor = `${user.full_name ?? user.username} <${user.email}>`;
botUserID = user.id;
botUserName = user.username;
const env = (0, env_1.getEnv)();
/* v8 ignore start: experimental feature */
if (semver_1.default.valid(env.RENOVATE_X_PLATFORM_VERSION)) {
defaults.version = env.RENOVATE_X_PLATFORM_VERSION;
} /* v8 ignore stop */
else {
defaults.version = await helper.getVersion({ token });
}
if (defaults.version?.includes('gitea-')) {
defaults.isForgejo = true;
}
logger_1.logger.debug(`${defaults.isForgejo ? 'Forgejo' : 'Gitea'} version: ${defaults.version}`);
}
catch (err) {
logger_1.logger.debug({ err }, 'Error authenticating with Gitea. Check your token');
throw new Error('Init: Authentication failure');
}
return {
endpoint: defaults.endpoint,
gitAuthor,
};
},
async getRawFile(fileName, repoName, branchOrTag) {
const repo = repoName ?? config.repository;
const contents = await helper.getRepoContents(repo, fileName, branchOrTag);
return contents.contentString ?? null;
},
async getJsonFile(fileName, repoName, branchOrTag) {
// TODO #22198
const raw = await platform.getRawFile(fileName, repoName, branchOrTag);
return (0, common_1.parseJson)(raw, fileName);
},
async initRepo({ repository, cloneSubmodules, cloneSubmodulesFilter, gitUrl, ignorePrAuthor, }) {
let repo;
config = {};
config.repository = repository;
config.cloneSubmodules = !!cloneSubmodules;
config.cloneSubmodulesFilter = cloneSubmodulesFilter;
config.ignorePrAuthor = !!ignorePrAuthor;
// Try to fetch information about repository
try {
repo = await helper.getRepo(repository);
}
catch (err) {
logger_1.logger.debug({ err }, 'Unknown Gitea initRepo error');
throw err;
}
// Ensure appropriate repository state and permissions
if (repo.archived) {
logger_1.logger.debug('Repository is archived - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_ARCHIVED);
}
if (repo.mirror) {
logger_1.logger.debug('Repository is a mirror - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_MIRRORED);
}
if (repo.permissions.pull === false || repo.permissions.push === false) {
logger_1.logger.debug('Repository does not permit pull or push - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_ACCESS_FORBIDDEN);
}
if (repo.empty) {
logger_1.logger.debug('Repository is empty - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_EMPTY);
}
if (repo.has_pull_requests === false) {
logger_1.logger.debug('Repo has disabled pull requests - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_BLOCKED);
}
if (repo.allow_rebase) {
config.mergeMethod = 'rebase';
}
else if (repo.allow_rebase_explicit) {
config.mergeMethod = 'rebase-merge';
}
else if (repo.allow_squash_merge) {
config.mergeMethod = 'squash';
}
else if (repo.allow_merge_commits) {
config.mergeMethod = 'merge';
}
else if (repo.allow_fast_forward_only_merge) {
config.mergeMethod = 'fast-forward';
}
else {
logger_1.logger.debug('Repository has no allowed merge methods - aborting renovation');
throw new Error(error_messages_1.REPOSITORY_BLOCKED);
}
// Determine author email and branches
config.defaultBranch = repo.default_branch;
logger_1.logger.debug(`${repository} default branch = ${config.defaultBranch}`);
const url = (0, utils_1.getRepoUrl)(repo, gitUrl, defaults.endpoint);
// Initialize Git storage
await git.initRepo({
...config,
url,
});
// Reset cached resources
config.issueList = null;
config.labelList = null;
config.hasIssuesEnabled = !repo.external_tracker && repo.has_issues;
return {
defaultBranch: config.defaultBranch,
isFork: !!repo.fork,
repoFingerprint: (0, util_1.repoFingerprint)(repo.id, defaults.endpoint),
};
},
async getRepos(config) {
logger_1.logger.debug('Auto-discovering Gitea repositories');
try {
if (config?.topics) {
logger_1.logger.debug({ topics: config.topics }, 'Auto-discovering by topics');
const fetchRepoArgs = config.topics.map((topic) => {
return {
topic,
sort: config.sort,
order: config.order,
};
});
const repos = await (0, promises_1.map)(fetchRepoArgs, fetchRepositories);
return (0, array_1.deduplicateArray)(repos.flat());
}
else if (config?.namespaces) {
logger_1.logger.debug({ namespaces: config.namespaces }, 'Auto-discovering by organization');
const repos = await (0, promises_1.map)(config.namespaces, async (organization) => {
const orgRepos = await helper.orgListRepos(organization);
return orgRepos
.filter((r) => !r.mirror && !r.archived)
.map((r) => r.full_name);
});
return (0, array_1.deduplicateArray)(repos.flat());
}
else {
return await fetchRepositories({
sort: config?.sort,
order: config?.order,
});
}
}
catch (err) {
logger_1.logger.error({ err }, 'Gitea getRepos() error');
throw err;
}
},
async setBranchStatus({ branchName, context, description, state, url: target_url, }) {
try {
// Create new status for branch commit
const branchCommit = git.getBranchCommit(branchName);
// TODO: check branchCommit
await helper.createCommitStatus(config.repository, branchCommit, {
state: helper.renovateToGiteaStatusMapping[state] || 'pending',
context,
description,
...(target_url && { target_url }),
});
// Refresh caches by re-fetching commit status for branch
await helper.getCombinedCommitStatus(config.repository, branchName, {
memCache: false,
});
}
catch (err) {
logger_1.logger.warn({ err }, 'Failed to set branch status');
}
},
async getBranchStatus(branchName, internalChecksAsSuccess) {
let ccs;
try {
ccs = await helper.getCombinedCommitStatus(config.repository, branchName);
}
catch (err) {
if (err.statusCode === 404) {
logger_1.logger.debug('Received 404 when checking branch status, assuming branch deletion');
throw new Error(error_messages_1.REPOSITORY_CHANGED);
}
logger_1.logger.debug('Unknown error when checking branch status');
throw err;
}
logger_1.logger.debug({ ccs }, 'Branch status check result');
if (!internalChecksAsSuccess &&
ccs.worstStatus === 'success' &&
ccs.statuses.every((status) => status.context?.startsWith('renovate/'))) {
logger_1.logger.debug('Successful checks are all internal renovate/ checks, so returning "pending" branch status');
return 'yellow';
}
/* v8 ignore next */
return helper.giteaToRenovateStatusMapping[ccs.worstStatus] ?? 'yellow';
},
async getBranchStatusCheck(branchName, context) {
const ccs = await helper.getCombinedCommitStatus(config.repository, branchName);
const cs = ccs.statuses.find((s) => s.context === context);
if (!cs) {
return null;
} // no status check exists
const status = helper.giteaToRenovateStatusMapping[cs.status];
if (status) {
return status;
}
logger_1.logger.warn({ check: cs }, 'Could not map Gitea status value to Renovate status');
return 'yellow';
},
getPrList() {
return pr_cache_1.GiteaPrCache.getPrs(gitea_helper_1.giteaHttp, config.repository, config.ignorePrAuthor, botUserName);
},
async getPr(number) {
// Search for pull request in cached list or attempt to query directly
const prList = await platform.getPrList();
let pr = prList.find((p) => p.number === number) ?? null;
if (pr) {
logger_1.logger.debug('Returning from cached PRs');
}
else {
logger_1.logger.debug('PR not found in cached PRs - trying to fetch directly');
const gpr = await helper.getPR(config.repository, number);
pr = (0, utils_1.toRenovatePR)(gpr, botUserName);
// Add pull request to cache for further lookups / queries
if (pr) {
await pr_cache_1.GiteaPrCache.setPr(gitea_helper_1.giteaHttp, config.repository, config.ignorePrAuthor, botUserName, pr);
}
}
// Abort and return null if no match was found
if (!pr) {
return null;
}
return pr;
},
async findPr({ branchName, prTitle: title, state = 'all', includeOtherAuthors, targetBranch, }) {
logger_1.logger.debug(`findPr(${branchName}, ${title}, ${state})`);
if (includeOtherAuthors && is_1.default.string(targetBranch)) {
// do not use pr cache as it only fetches prs created by the bot account
const pr = await helper.getPRByBranch(config.repository, targetBranch, branchName);
if (!pr) {
return null;
}
return (0, utils_1.toRenovatePR)(pr, null);
}
const prList = await platform.getPrList();
const pr = prList.find((p) => p.sourceRepo === config.repository &&
p.sourceBranch === branchName &&
matchesState(p.state, state) &&
(!title || p.title === title));
if (pr) {
logger_1.logger.debug(`Found PR #${pr.number}`);
}
return pr ?? null;
},
async createPr({ sourceBranch, targetBranch, prTitle, prBody: rawBody, labels: labelNames, platformPrOptions, draftPR, }) {
let title = prTitle;
const base = targetBranch;
const head = sourceBranch;
const body = (0, sanitize_1.sanitize)(rawBody);
if (draftPR) {
title = utils_1.DRAFT_PREFIX + title;
}
logger_1.logger.debug(`Creating pull request: ${title} (${head} => ${base})`);
try {
const labels = Array.isArray(labelNames)
? await (0, promises_1.map)(labelNames, lookupLabelByName)
: [];
const gpr = await helper.createPR(config.repository, {
base,
head,
title,
body,
labels: labels.filter(is_1.default.number),
});
if (platformPrOptions?.usePlatformAutomerge) {
// Only Gitea v1.24.0+ and Forgejo v10.0.0+ support delete_branch_after_merge.
// This is required to not have undesired behavior when renovate finds existing branches on next run.
if (semver_1.default.gte(defaults.version, defaults.isForgejo ? '10.0.0' : '1.24.0')) {
try {
await helper.mergePR(config.repository, gpr.number, {
Do: (0, utils_1.getMergeMethod)(platformPrOptions?.automergeStrategy) ??
config.mergeMethod,
merge_when_checks_succeed: true,
delete_branch_after_merge: true,
});
logger_1.logger.debug({ prNumber: gpr.number }, 'Gitea-native automerge: success');
}
catch (err) {
logger_1.logger.warn({ err, prNumber: gpr.number }, 'Gitea-native automerge: fail');
}
}
else {
logger_1.logger.debug({ prNumber: gpr.number }, `Gitea-native automerge: not supported on this version of ${defaults.isForgejo ? 'Forgejo' : 'Gitea'}. Use ${defaults.isForgejo ? '10.0.0' : '1.24.0'} or newer.`);
}
}
const pr = (0, utils_1.toRenovatePR)(gpr, botUserName);
if (!pr) {
throw new Error('Can not parse newly created Pull Request');
}
await pr_cache_1.GiteaPrCache.setPr(gitea_helper_1.giteaHttp, config.repository, config.ignorePrAuthor, botUserName, pr);
return pr;
}
catch (err) {
// When the user manually deletes a branch from Renovate, the PR remains but is no longer linked to any branch. In
// the most recent versions of Gitea, the PR gets automatically closed when that happens, but older versions do
// not handle this properly and keep the PR open. As pushing a branch with the same name resurrects the PR, this
// would cause a HTTP 409 conflict error, which we hereby gracefully handle.
if (err.statusCode === 409) {
logger_1.logger.warn({ prTitle: title, sourceBranch }, 'Attempting to gracefully recover from 409 Conflict response in createPr()');
// Refresh cached PR list and search for pull request with matching information
pr_cache_1.GiteaPrCache.forceSync();
const pr = await platform.findPr({
branchName: sourceBranch,
state: 'open',
});
// If a valid PR was found, return and gracefully recover from the error. Otherwise, abort and throw error.
if (pr?.bodyStruct) {
if (pr.title !== title || pr.bodyStruct.hash !== (0, pr_body_1.hashBody)(body)) {
logger_1.logger.debug(`Recovered from 409 Conflict, but PR for ${sourceBranch} is outdated. Updating...`);
await platform.updatePr({
number: pr.number,
prTitle: title,
prBody: body,
});
pr.title = title;
pr.bodyStruct = (0, pr_body_1.getPrBodyStruct)(body);
}
else {
logger_1.logger.debug(`Recovered from 409 Conflict and PR for ${sourceBranch} is up-to-date`);
}
return pr;
}
}
throw err;
}
},
async updatePr({ number, prTitle, prBody: body, labels, state, targetBranch, }) {
let title = prTitle;
if ((await (0, exports.getPrList)()).find((pr) => pr.number === number)?.isDraft) {
title = utils_1.DRAFT_PREFIX + title;
}
const prUpdateParams = {
title,
...(body && { body }),
...(state && { state }),
};
if (targetBranch) {
prUpdateParams.base = targetBranch;
}
/**
* Update PR labels.
* In the Gitea API, labels are replaced on each update if the field is present.
* If the field is not present (i.e., undefined), labels aren't updated.
* However, the labels array must contain label IDs instead of names,
* so a lookup is performed to fetch the details (including the ID) of each label.
*/
if (Array.isArray(labels)) {
prUpdateParams.labels = (await (0, promises_1.map)(labels, lookupLabelByName)).filter(is_1.default.number);
if (labels.length !== prUpdateParams.labels.length) {
logger_1.logger.warn('Some labels could not be looked up. Renovate may halt label updates assuming changes by others.');
}
}
const gpr = await helper.updatePR(config.repository, number, prUpdateParams);
const pr = (0, utils_1.toRenovatePR)(gpr, botUserName);
if (pr) {
await pr_cache_1.GiteaPrCache.setPr(gitea_helper_1.giteaHttp, config.repository, config.ignorePrAuthor, botUserName, pr);
}
},
async mergePr({ id, strategy }) {
try {
await helper.mergePR(config.repository, id, {
Do: (0, utils_1.getMergeMethod)(strategy) ?? config.mergeMethod,
});
return true;
}
catch (err) {
logger_1.logger.warn({ err, id }, 'Merging of PR failed');
return false;
}
},
getIssueList() {
if (config.hasIssuesEnabled === false) {
return Promise.resolve([]);
}
config.issueList ??= helper
.searchIssues(config.repository, { state: 'all' }, { memCache: false })
.then((issues) => {
const issueList = issues.map(toRenovateIssue);
logger_1.logger.debug(`Retrieved ${issueList.length} Issues`);
return issueList;
});
return config.issueList;
},
async getIssue(number, memCache = true) {
if (config.hasIssuesEnabled === false) {
return null;
}
try {
const body = (await helper.getIssue(config.repository, number, { memCache })).body;
return {
number,
body,
};
}
catch (err) /* v8 ignore start */ {
logger_1.logger.debug({ err, number }, 'Error getting issue');
return null;
} /* v8 ignore stop */
},
async findIssue(title) {
const issueList = await platform.getIssueList();
const issue = issueList.find((i) => i.state === 'open' && i.title === title);
if (!issue) {
return null;
}
// TODO: types (#22198)
logger_1.logger.debug(`Found Issue #${issue.number}`);
// TODO #22198
return exports.getIssue(issue.number);
},
async ensureIssue({ title, reuseTitle, body: content, labels: labelNames, shouldReOpen, once, }) {
logger_1.logger.debug(`ensureIssue(${title})`);
if (config.hasIssuesEnabled === false) {
logger_1.logger.info('Cannot ensure issue because issues are disabled in this repository');
return null;
}
try {
const body = (0, utils_1.smartLinks)(content);
const issueList = await platform.getIssueList();
let issues = issueList.filter((i) => i.title === title);
if (!issues.length) {
issues = issueList.filter((i) => i.title === reuseTitle);
}
const labels = Array.isArray(labelNames)
? (await Promise.all(labelNames.map(lookupLabelByName))).filter(is_1.default.number)
: undefined;
// Update any matching issues which currently exist
if (issues.length) {
let activeIssue = issues.find((i) => i.state === 'open');
// If no active issue was found, decide if it shall be skipped, re-opened or updated without state change
if (!activeIssue) {
if (once) {
logger_1.logger.debug('Issue already closed - skipping update');
return null;
}
if (shouldReOpen) {
logger_1.logger.debug('Reopening previously closed Issue');
}
// Pick the last issue in the list as the active one
activeIssue = issues[issues.length - 1];
}
// Close any duplicate issues
for (const issue of issues) {
if (issue.state === 'open' && issue.number !== activeIssue.number) {
// TODO: types (#22198)
logger_1.logger.warn({ issueNo: issue.number }, 'Closing duplicate issue');
// TODO #22198
await helper.closeIssue(config.repository, issue.number);
}
}
// Check if issue has already correct state
if (activeIssue.title === title &&
activeIssue.body === body &&
activeIssue.state === 'open') {
logger_1.logger.debug(
// TODO: types (#22198)
`Issue #${activeIssue.number} is open and up to date - nothing to do`);
return null;
}
// Update issue body and re-open if enabled
// TODO: types (#22198)
logger_1.logger.debug(`Updating Issue #${activeIssue.number}`);
const existingIssue = await helper.updateIssue(config.repository,
// TODO #22198
activeIssue.number, {
body,
title,
state: shouldReOpen ? 'open' : activeIssue.state,
});
// Test whether the issues need to be updated
const existingLabelIds = (existingIssue.labels ?? []).map((label) => label.id);
if (labels &&
(labels.length !== existingLabelIds.length ||
labels.filter((labelId) => !existingLabelIds.includes(labelId))
.length !== 0)) {
await helper.updateIssueLabels(config.repository,
// TODO #22198
activeIssue.number, {
labels,
});
}
return 'updated';
}
// Create new issue and reset cache
const issue = await helper.createIssue(config.repository, {
body,
title,
labels,
});
logger_1.logger.debug(`Created new Issue #${issue.number}`);
config.issueList = null;
return 'created';
}
catch (err) {
logger_1.logger.warn({ err }, 'Could not ensure issue');
}
return null;
},
async ensureIssueClosing(title) {
logger_1.logger.debug(`ensureIssueClosing(${title})`);
if (config.hasIssuesEnabled === false) {
return;
}
const issueList = await platform.getIssueList();
for (const issue of issueList) {
if (issue.state === 'open' && issue.title === title) {
logger_1.logger.debug(`Closing issue...issueNo: ${issue.number}`);
// TODO #22198
await helper.closeIssue(config.repository, issue.number);
}
}
},
async deleteLabel(issue, labelName) {
logger_1.logger.debug(`Deleting label ${labelName} from Issue #${issue}`);
const label = await lookupLabelByName(labelName);
if (label) {
await helper.unassignLabel(config.repository, issue, label);
}
else {
logger_1.logger.warn({ issue, labelName }, 'Failed to lookup label for deletion');
}
},
async ensureComment({ number: issue, topic, content, }) {
try {
let body = (0, sanitize_1.sanitize)(content);
const commentList = await helper.getComments(config.repository, issue);
// Search comment by either topic or exact body
let comment = null;
if (topic) {
comment = findCommentByTopic(commentList, topic);
body = `### ${topic}\n\n${body}`;
}
else {
comment = findCommentByContent(commentList, body);
}
// Create a new comment if no match has been found, otherwise update if necessary
if (!comment) {
comment = await helper.createComment(config.repository, issue, body);
logger_1.logger.info({ repository: config.repository, issue, comment: comment.id }, 'Comment added');
}
else if (comment.body === body) {
logger_1.logger.debug(`Comment #${comment.id} is already up-to-date`);
}
else {
await helper.updateComment(config.repository, comment.id, body);
logger_1.logger.debug({ repository: config.repository, issue, comment: comment.id }, 'Comment updated');
}
return true;
}
catch (err) {
logger_1.logger.warn({ err, issue, subject: topic }, 'Error ensuring comment');
return false;
}
},
async ensureCommentRemoval(deleteConfig) {
const { number: issue } = deleteConfig;
const key = deleteConfig.type === 'by-topic'
? deleteConfig.topic
: deleteConfig.content;
logger_1.logger.debug(`Ensuring comment "${key}" in #${issue} is removed`);
const commentList = await helper.getComments(config.repository, issue);
let comment = null;
if (deleteConfig.type === 'by-topic') {
comment = findCommentByTopic(commentList, deleteConfig.topic);
}
else if (deleteConfig.type === 'by-content') {
const body = (0, sanitize_1.sanitize)(deleteConfig.content);
comment = findCommentByContent(commentList, body);
}
// Abort and do nothing if no matching comment was found
if (!comment) {
return;
}
// Try to delete comment
try {
await helper.deleteComment(config.repository, comment.id);
}
catch (err) {
logger_1.logger.warn({ err, issue, config: deleteConfig }, 'Error deleting comment');
}
},
async getBranchPr(branchName) {
logger_1.logger.debug(`getBranchPr(${branchName})`);
const pr = await platform.findPr({ branchName, state: 'open' });
return pr ? platform.getPr(pr.number) : null;
},
async addAssignees(number, assignees) {
logger_1.logger.debug(`Updating assignees '${assignees?.join(', ')}' on Issue #${number}`);
await helper.updateIssue(config.repository, number, {
assignees,
});
},
async addReviewers(number, reviewers) {
logger_1.logger.debug(`Adding reviewers '${reviewers?.join(', ')}' to #${number}`);
if (semver_1.default.lt(defaults.version, '1.14.0')) {
logger_1.logger.debug({ version: defaults.version }, 'Adding reviewer not yet supported.');
return;
}
try {
await helper.requestPrReviewers(config.repository, number, { reviewers });
}
catch (err) {
logger_1.logger.warn({ err, number, reviewers }, 'Failed to assign reviewer');
}
},
massageMarkdown(prBody) {
return (0, pr_body_2.smartTruncate)((0, utils_1.smartLinks)(prBody), maxBodyLength());
},
maxBodyLength,
};
function maxBodyLength() {
return 1000000;
}
/* eslint-disable @typescript-eslint/unbound-method */
exports.addAssignees = platform.addAssignees, exports.addReviewers = platform.addReviewers, exports.createPr = platform.createPr, exports.deleteLabel = platform.deleteLabel, exports.ensureComment = platform.ensureComment, exports.ensureCommentRemoval = platform.ensureCommentRemoval, exports.ensureIssue = platform.ensureIssue, exports.ensureIssueClosing = platform.ensureIssueClosing, exports.findIssue = platform.findIssue, exports.findPr = platform.findPr, exports.getBranchPr = platform.getBranchPr, exports.getBranchStatus = platform.getBranchStatus, exports.getBranchStatusCheck = platform.getBranchStatusCheck, exports.getIssue = platform.getIssue, exports.getRawFile = platform.getRawFile, exports.getJsonFile = platform.getJsonFile, exports.getIssueList = platform.getIssueList, exports.getPr = platform.getPr, exports.massageMarkdown = platform.massageMarkdown, exports.getPrList = platform.getPrList, exports.getRepos = platform.getRepos, exports.initPlatform = platform.initPlatform, exports.initRepo = platform.initRepo, exports.mergePr = platform.mergePr, exports.setBranchStatus = platform.setBranchStatus, exports.updatePr = platform.updatePr;
//# sourceMappingURL=index.js.map