renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
160 lines • 7.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.client = void 0;
const error_messages_1 = require("../../../constants/error-messages");
const logger_1 = require("../../../logger");
const memory_http_cache_provider_1 = require("../../../util/http/cache/memory-http-cache-provider");
const gerrit_1 = require("../../../util/http/gerrit");
const regex_1 = require("../../../util/regex");
const utils_1 = require("./utils");
const QUOTES_REGEX = (0, regex_1.regEx)('"', 'g');
class GerritClient {
requestDetails = [
'SUBMITTABLE', //include the submittable field in ChangeInfo, which can be used to tell if the change is reviewed and ready for submit.
'CHECK', // include potential consistency problems with the change (not related to labels)
'MESSAGES',
'DETAILED_ACCOUNTS',
'LABELS',
'CURRENT_ACTIONS', //to check if current_revision can be "rebased"
'CURRENT_REVISION', //get RevisionInfo::ref to fetch
'CURRENT_COMMIT', // to get the commit message
];
gerritHttp = new gerrit_1.GerritHttp();
async getRepos() {
const res = await this.gerritHttp.getJsonUnchecked('a/projects/?type=CODE&state=ACTIVE', {});
return Object.keys(res.body);
}
async getProjectInfo(repository) {
const projectInfo = await this.gerritHttp.getJsonUnchecked(`a/projects/${encodeURIComponent(repository)}`);
if (projectInfo.body.state !== 'ACTIVE') {
throw new Error(error_messages_1.REPOSITORY_ARCHIVED);
}
return projectInfo.body;
}
async getBranchInfo(repository) {
const branchInfo = await this.gerritHttp.getJsonUnchecked(`a/projects/${encodeURIComponent(repository)}/branches/HEAD`);
return branchInfo.body;
}
async findChanges(repository, findPRConfig, refreshCache) {
const opts = {};
/* v8 ignore start: temporary code */
// TODO: should refresh the cache rather than just ignore it
if (refreshCache) {
opts.memCache = false;
}
else {
opts.cacheProvider = memory_http_cache_provider_1.memCacheProvider;
}
/* v8 ignore stop */
const filters = GerritClient.buildSearchFilters(repository, findPRConfig);
const changes = await this.gerritHttp.getJsonUnchecked(`a/changes/?q=` +
filters.join('+') +
this.requestDetails.map((det) => `&o=${det}`).join(''), opts);
logger_1.logger.trace(`findChanges(${filters.join(', ')}) => ${changes.body.length}`);
return changes.body;
}
async getChange(changeNumber) {
const changes = await this.gerritHttp.getJsonUnchecked(`a/changes/${changeNumber}?` +
this.requestDetails.map((det) => `o=${det}`).join('&'));
return changes.body;
}
async getMergeableInfo(change) {
const mergeable = await this.gerritHttp.getJsonUnchecked(`a/changes/${change._number}/revisions/current/mergeable`);
return mergeable.body;
}
async abandonChange(changeNumber) {
await this.gerritHttp.postJson(`a/changes/${changeNumber}/abandon`);
}
async submitChange(changeNumber) {
const change = await this.gerritHttp.postJson(`a/changes/${changeNumber}/submit`);
return change.body;
}
async getMessages(changeNumber) {
const messages = await this.gerritHttp.getJsonUnchecked(`a/changes/${changeNumber}/messages`, { memCache: false });
return messages.body;
}
async addMessage(changeNumber, fullMessage, tag) {
const message = this.normalizeMessage(fullMessage);
await this.gerritHttp.postJson(`a/changes/${changeNumber}/revisions/current/review`, { body: { message, tag, notify: 'NONE' } });
}
async checkForExistingMessage(changeNumber, newMessage, msgType) {
const messages = await this.getMessages(changeNumber);
return messages.some((existingMsg) => (msgType === undefined || msgType === existingMsg.tag) &&
existingMsg.message.includes(newMessage));
}
async addMessageIfNotAlreadyExists(changeNumber, message, tag) {
const newMsg = this.normalizeMessage(message);
if (!(await this.checkForExistingMessage(changeNumber, newMsg, tag))) {
await this.addMessage(changeNumber, newMsg, tag);
}
}
async setLabel(changeNumber, label, value) {
await this.gerritHttp.postJson(`a/changes/${changeNumber}/revisions/current/review`, { body: { labels: { [label]: value }, notify: 'NONE' } });
}
async addReviewers(changeNumber, reviewers) {
await this.gerritHttp.postJson(`a/changes/${changeNumber}/revisions/current/review`, {
body: {
reviewers: reviewers.map((r) => ({ reviewer: r })),
notify: 'OWNER_REVIEWERS', // Avoids notifying cc's
},
});
}
async addAssignee(changeNumber, assignee) {
await this.gerritHttp.putJson(
// TODO: refactor this as this API removed in Gerrit 3.8
`a/changes/${changeNumber}/assignee`, {
body: { assignee },
});
}
async getFile(repo, branch, fileName) {
const base64Content = await this.gerritHttp.getText(`a/projects/${encodeURIComponent(repo)}/branches/${encodeURIComponent(branch)}/files/${encodeURIComponent(fileName)}/content`);
return Buffer.from(base64Content.body, 'base64').toString();
}
async approveChange(changeId) {
const isApproved = await this.checkIfApproved(changeId);
if (!isApproved) {
await this.setLabel(changeId, 'Code-Review', +2);
}
}
async checkIfApproved(changeId) {
const change = await exports.client.getChange(changeId);
const reviewLabels = change?.labels?.['Code-Review'];
return reviewLabels === undefined || reviewLabels.approved !== undefined;
}
wasApprovedBy(change, username) {
return (change.labels?.['Code-Review'].approved &&
change.labels['Code-Review'].approved.username === username);
}
normalizeMessage(message) {
//the last \n was removed from gerrit after the comment was added...
return message.substring(0, 0x4000).trim();
}
static buildSearchFilters(repository, searchConfig) {
const filterState = (0, utils_1.mapPrStateToGerritFilter)(searchConfig.state);
const filters = ['owner:self', 'project:' + repository, filterState];
if (searchConfig.branchName) {
filters.push(...[
'(',
`footer:Renovate-Branch=${searchConfig.branchName}`,
// for backwards compatibility
'OR',
`hashtag:sourceBranch-${searchConfig.branchName}`,
')',
]);
}
if (searchConfig.targetBranch) {
filters.push(`branch:${searchConfig.targetBranch}`);
}
if (searchConfig.label) {
filters.push(`label:Code-Review=${searchConfig.label}`);
}
if (searchConfig.prTitle) {
// escaping support in Gerrit is not great, so we need to remove quotes
// special characters are ignored anyway in the search so it does not create any issues
filters.push(`message:${encodeURIComponent('"' + searchConfig.prTitle.replace(QUOTES_REGEX, '') + '"')}`);
}
return filters;
}
}
exports.client = new GerritClient();
//# sourceMappingURL=client.js.map