"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.client = void 0;
const error_messages_1 = require("../../../constants/error-messages");
const logger_1 = require("../../../logger");
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 problems with the change.
        '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.getJson('a/projects/?type=CODE&state=ACTIVE', {});
        return Object.keys(res.body);
    }
    async getProjectInfo(repository) {
        const projectInfo = await this.gerritHttp.getJson(`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.getJson(`a/projects/${encodeURIComponent(repository)}/branches/HEAD`);
        return branchInfo.body;
    }
    async findChanges(repository, findPRConfig, refreshCache) {
        const filters = GerritClient.buildSearchFilters(repository, findPRConfig);
        const changes = await this.gerritHttp.getJson(`a/changes/?q=` +
            filters.join('+') +
            this.requestDetails.map((det) => `&o=${det}`).join(''), { memCache: !refreshCache });
        logger_1.logger.trace(`findChanges(${filters.join(', ')}) => ${changes.body.length}`);
        return changes.body;
    }
    async getChange(changeNumber) {
        const changes = await this.gerritHttp.getJson(`a/changes/${changeNumber}?` +
            this.requestDetails.map((det) => `o=${det}`).join('&'));
        return changes.body;
    }
    async getMergeableInfo(change) {
        const mergeable = await this.gerritHttp.getJson(`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 setCommitMessage(changeNumber, message) {
        await this.gerritHttp.putJson(`a/changes/${changeNumber}/message`, {
            body: { message },
        });
    }
    async updateChangeSubject(number, currentMessage, newSubject) {
        // Replace first line of the commit message with the new subject
        const newMessage = currentMessage.replace(new RegExp(`^.*$`, 'm'), newSubject);
        await this.setCommitMessage(number, newMessage);
    }
    async getMessages(changeNumber) {
        const messages = await this.gerritHttp.getJson(`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 } });
    }
    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 } } });
    }
    async addReviewer(changeNumber, reviewer) {
        await this.gerritHttp.postJson(`a/changes/${changeNumber}/reviewers`, {
            body: { reviewer },
        });
    }
    async addAssignee(changeNumber, assignee) {
        await this.gerritHttp.putJson(`a/changes/${changeNumber}/assignee`, {
            body: { assignee },
        });
    }
    async getFile(repo, branch, fileName) {
        const base64Content = await this.gerritHttp.get(`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