"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GerritScm = exports.configureScm = void 0;
const tslib_1 = require("tslib");
const crypto_1 = require("crypto");
const logger_1 = require("../../../logger");
const git = tslib_1.__importStar(require("../../../util/git"));
const hash_1 = require("../../../util/hash");
const default_scm_1 = require("../default-scm");
const client_1 = require("./client");
let repository;
let username;
function configureScm(repo, login) {
    repository = repo;
    username = login;
}
exports.configureScm = configureScm;
class GerritScm extends default_scm_1.DefaultGitScm {
    async branchExists(branchName) {
        const searchConfig = { state: 'open', branchName };
        const change = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        if (change) {
            return true;
        }
        return git.branchExists(branchName);
    }
    async getBranchCommit(branchName) {
        const searchConfig = { state: 'open', branchName };
        const change = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        if (change) {
            return change.current_revision;
        }
        return git.getBranchCommit(branchName);
    }
    async isBranchBehindBase(branchName, baseBranch) {
        const searchConfig = {
            state: 'open',
            branchName,
            targetBranch: baseBranch,
        };
        const change = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        if (change) {
            const currentGerritPatchset = change.revisions[change.current_revision];
            return currentGerritPatchset.actions?.['rebase'].enabled === true;
        }
        return true;
    }
    async isBranchConflicted(baseBranch, branch) {
        const searchConfig = {
            state: 'open',
            branchName: branch,
            targetBranch: baseBranch,
        };
        const change = (await client_1.client.findChanges(repository, searchConfig)).pop();
        if (change) {
            const mergeInfo = await client_1.client.getMergeableInfo(change);
            return !mergeInfo.mergeable;
        }
        else {
            logger_1.logger.warn(`There is no open change with branch=${branch} and baseBranch=${baseBranch}`);
            return true;
        }
    }
    async isBranchModified(branchName) {
        const searchConfig = { state: 'open', branchName };
        const change = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        if (change) {
            const currentGerritPatchset = change.revisions[change.current_revision];
            return currentGerritPatchset.uploader.username !== username;
        }
        return false;
    }
    async commitAndPush(commit) {
        logger_1.logger.debug(`commitAndPush(${commit.branchName})`);
        const searchConfig = {
            state: 'open',
            branchName: commit.branchName,
            targetBranch: commit.baseBranch,
        };
        const existingChange = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        let hasChanges = true;
        const origMsg = typeof commit.message === 'string' ? [commit.message] : commit.message;
        commit.message = [
            ...origMsg,
            `Renovate-Branch: ${commit.branchName}\nChange-Id: ${existingChange?.change_id ?? generateChangeId()}`,
        ];
        const commitResult = await git.prepareCommit({ ...commit, force: true });
        if (commitResult) {
            const { commitSha } = commitResult;
            if (existingChange?.revisions && existingChange.current_revision) {
                const fetchRefSpec = existingChange.revisions[existingChange.current_revision].ref;
                await git.fetchRevSpec(fetchRefSpec); //fetch current ChangeSet for git diff
                hasChanges = await git.hasDiff('HEAD', 'FETCH_HEAD'); //avoid empty patchsets
            }
            if (hasChanges || commit.force) {
                const pushResult = await git.pushCommit({
                    sourceRef: commit.branchName,
                    targetRef: `refs/for/${commit.baseBranch}`,
                    files: commit.files,
                });
                if (pushResult) {
                    //existingChange was the old change before commit/push. we need to approve again, if it was previously approved from renovate
                    if (existingChange &&
                        client_1.client.wasApprovedBy(existingChange, username)) {
                        await client_1.client.approveChange(existingChange._number);
                    }
                    return commitSha;
                }
            }
        }
        return null; //empty commit, no changes in this Gerrit-Change
    }
    deleteBranch(branchName) {
        return Promise.resolve();
    }
    async mergeToLocal(branchName) {
        const searchConfig = { state: 'open', branchName };
        const change = await client_1.client
            .findChanges(repository, searchConfig, true)
            .then((res) => res.pop());
        if (change) {
            return super.mergeToLocal(change.revisions[change.current_revision].ref);
        }
        return super.mergeToLocal(branchName);
    }
}
exports.GerritScm = GerritScm;
/**
 * This function should generate a Gerrit Change-ID analogous to the commit hook. We avoid the commit hook cause of security concerns.
 * random=$( (whoami ; hostname ; date; cat $1 ; echo $RANDOM) | git hash-object --stdin) prefixed with an 'I'.
 * TODO: Gerrit don't accept longer Change-IDs (sha256), but what happens with this https://git-scm.com/docs/hash-function-transition/ ?
 */
function generateChangeId() {
    return 'I' + (0, hash_1.hash)((0, crypto_1.randomUUID)(), 'sha1');
}
//# sourceMappingURL=scm.js.map