"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUpdatedPackageFiles = void 0;
const tslib_1 = require("tslib");
/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const error_messages_1 = require("../../../../constants/error-messages");
const logger_1 = require("../../../../logger");
const manager_1 = require("../../../../modules/manager");
const git_1 = require("../../../../util/git");
const string_1 = require("../../../../util/string");
const auto_replace_1 = require("./auto-replace");
async function getFileContent(updatedFileContents, filePath, config) {
    let fileContent = updatedFileContents[filePath];
    if (!fileContent) {
        fileContent = await (0, git_1.getFile)(filePath, config.reuseExistingBranch ? config.branchName : config.baseBranch);
    }
    return fileContent;
}
async function getUpdatedPackageFiles(config) {
    logger_1.logger.trace({ config });
    const reuseExistingBranch = config.reuseExistingBranch;
    logger_1.logger.debug(`manager.getUpdatedPackageFiles() reuseExistingBranch=${reuseExistingBranch}`);
    let updatedFileContents = {};
    const nonUpdatedFileContents = {};
    const packageFileManagers = {};
    const packageFileUpdatedDeps = {};
    const lockFileMaintenanceFiles = [];
    let firstUpdate = true;
    for (const upgrade of config.upgrades) {
        const manager = upgrade.manager;
        const packageFile = upgrade.packageFile;
        const depName = upgrade.depName;
        // TODO: fix types, can be undefined (#22198)
        const newVersion = upgrade.newVersion;
        const currentVersion = upgrade.currentVersion;
        const updateLockedDependency = (0, manager_1.get)(manager, 'updateLockedDependency');
        packageFileManagers[packageFile] = manager;
        packageFileUpdatedDeps[packageFile] =
            packageFileUpdatedDeps[packageFile] || [];
        packageFileUpdatedDeps[packageFile].push({ ...upgrade });
        const packageFileContent = await getFileContent(updatedFileContents, packageFile, config);
        let lockFileContent = null;
        const lockFile = upgrade.lockFile ?? upgrade.lockFiles?.[0] ?? '';
        if (lockFile) {
            lockFileContent = await getFileContent(updatedFileContents, lockFile, config);
        }
        // istanbul ignore if
        if (reuseExistingBranch &&
            (!packageFileContent || (lockFile && !lockFileContent))) {
            logger_1.logger.debug({ packageFile, depName }, 'Rebasing branch after file not found');
            return getUpdatedPackageFiles({
                ...config,
                reuseExistingBranch: false,
            });
        }
        if (upgrade.updateType === 'lockFileMaintenance') {
            lockFileMaintenanceFiles.push(packageFile);
        }
        else if (upgrade.isRemediation) {
            const { status, files } = await updateLockedDependency({
                ...upgrade,
                depName,
                newVersion,
                currentVersion,
                packageFile,
                packageFileContent: packageFileContent,
                lockFile,
                lockFileContent: lockFileContent,
                allowParentUpdates: true,
                allowHigherOrRemoved: true,
            });
            if (reuseExistingBranch && status !== 'already-updated') {
                logger_1.logger.debug({ lockFile, depName, status }, 'Need to retry branch as it is not already up-to-date');
                return getUpdatedPackageFiles({
                    ...config,
                    reuseExistingBranch: false,
                });
            }
            if (files) {
                updatedFileContents = { ...updatedFileContents, ...files };
                Object.keys(files).forEach((file) => delete nonUpdatedFileContents[file]);
            }
            if (status === 'update-failed' || status === 'unsupported') {
                upgrade.remediationNotPossible = true;
            }
        }
        else if (upgrade.isLockfileUpdate) {
            if (updateLockedDependency) {
                const { status, files } = await updateLockedDependency({
                    ...upgrade,
                    depName,
                    newVersion,
                    currentVersion,
                    packageFile,
                    packageFileContent: packageFileContent,
                    lockFile,
                    lockFileContent: lockFileContent,
                    allowParentUpdates: false,
                });
                if (status === 'unsupported') {
                    // incompatible lock file
                    if (!updatedFileContents[packageFile]) {
                        nonUpdatedFileContents[packageFile] = packageFileContent;
                    }
                }
                else if (status === 'already-updated') {
                    logger_1.logger.debug(`Upgrade of ${depName} to ${newVersion} is already done in existing branch`);
                }
                else {
                    // something changed
                    if (reuseExistingBranch) {
                        logger_1.logger.debug({ lockFile, depName, status }, 'Need to retry branch as upgrade requirements are not mets');
                        return getUpdatedPackageFiles({
                            ...config,
                            reuseExistingBranch: false,
                        });
                    }
                    if (files) {
                        updatedFileContents = { ...updatedFileContents, ...files };
                        Object.keys(files).forEach((file) => delete nonUpdatedFileContents[file]);
                    }
                }
            }
            else {
                logger_1.logger.debug({ manager }, 'isLockFileUpdate without updateLockedDependency');
                if (!updatedFileContents[packageFile]) {
                    nonUpdatedFileContents[packageFile] = packageFileContent;
                }
            }
        }
        else {
            const bumpPackageVersion = (0, manager_1.get)(manager, 'bumpPackageVersion');
            const updateDependency = (0, manager_1.get)(manager, 'updateDependency');
            if (!updateDependency) {
                let res = await (0, auto_replace_1.doAutoReplace)(upgrade, packageFileContent, reuseExistingBranch, firstUpdate);
                firstUpdate = false;
                if (res) {
                    if (bumpPackageVersion &&
                        upgrade.bumpVersion &&
                        upgrade.packageFileVersion) {
                        const { bumpedContent } = await bumpPackageVersion(res, upgrade.packageFileVersion, upgrade.bumpVersion, packageFile);
                        res = bumpedContent;
                    }
                    if (res === packageFileContent) {
                        logger_1.logger.debug({ packageFile, depName }, 'No content changed');
                    }
                    else {
                        logger_1.logger.debug({ packageFile, depName }, 'Contents updated');
                        updatedFileContents[packageFile] = res;
                        delete nonUpdatedFileContents[packageFile];
                    }
                    continue;
                }
                else if (reuseExistingBranch) {
                    return getUpdatedPackageFiles({
                        ...config,
                        reuseExistingBranch: false,
                    });
                }
                logger_1.logger.error({ packageFile, depName }, 'Could not autoReplace');
                throw new Error(error_messages_1.WORKER_FILE_UPDATE_FAILED);
            }
            let newContent = await updateDependency({
                fileContent: packageFileContent,
                upgrade,
            });
            if (newContent &&
                bumpPackageVersion &&
                upgrade.bumpVersion &&
                upgrade.packageFileVersion) {
                const { bumpedContent } = await bumpPackageVersion(newContent, upgrade.packageFileVersion, upgrade.bumpVersion, packageFile);
                newContent = bumpedContent;
            }
            if (!newContent) {
                if (reuseExistingBranch) {
                    logger_1.logger.debug({ packageFile, depName }, 'Rebasing branch after error updating content');
                    return getUpdatedPackageFiles({
                        ...config,
                        reuseExistingBranch: false,
                    });
                }
                logger_1.logger.debug({ existingContent: packageFileContent, config: upgrade }, 'Error updating file');
                throw new Error(error_messages_1.WORKER_FILE_UPDATE_FAILED);
            }
            if (newContent !== packageFileContent) {
                if (reuseExistingBranch) {
                    // This ensure it's always 1 commit from the bot
                    logger_1.logger.debug({ packageFile, depName }, 'Need to update package file so will rebase first');
                    return getUpdatedPackageFiles({
                        ...config,
                        reuseExistingBranch: false,
                    });
                }
                logger_1.logger.debug(`Updating ${depName} in ${(0, string_1.coerceString)(packageFile, lockFile)}`);
                updatedFileContents[packageFile] = newContent;
                delete nonUpdatedFileContents[packageFile];
            }
            if (newContent === packageFileContent) {
                if (upgrade.manager === 'git-submodules') {
                    updatedFileContents[packageFile] = newContent;
                    delete nonUpdatedFileContents[packageFile];
                }
            }
        }
    }
    const updatedPackageFiles = Object.keys(updatedFileContents).map((name) => ({
        type: 'addition',
        path: name,
        contents: updatedFileContents[name],
    }));
    const updatedArtifacts = [];
    const artifactErrors = [];
    for (const packageFile of updatedPackageFiles) {
        const manager = packageFileManagers[packageFile.path];
        const updatedDeps = packageFileUpdatedDeps[packageFile.path];
        const updateArtifacts = (0, manager_1.get)(manager, 'updateArtifacts');
        if (updateArtifacts) {
            const results = await updateArtifacts({
                packageFileName: packageFile.path,
                updatedDeps,
                // TODO #22198
                newPackageFileContent: packageFile.contents.toString(),
                config,
            });
            if (is_1.default.nonEmptyArray(results)) {
                for (const res of results) {
                    const { file, artifactError } = res;
                    if (file) {
                        updatedArtifacts.push(file);
                    }
                    else if (artifactError) {
                        artifactErrors.push(artifactError);
                    }
                }
            }
        }
    }
    const nonUpdatedPackageFiles = Object.keys(nonUpdatedFileContents).map((name) => ({
        type: 'addition',
        path: name,
        contents: nonUpdatedFileContents[name],
    }));
    for (const packageFile of nonUpdatedPackageFiles) {
        const manager = packageFileManagers[packageFile.path];
        const updatedDeps = packageFileUpdatedDeps[packageFile.path];
        const updateArtifacts = (0, manager_1.get)(manager, 'updateArtifacts');
        if (updateArtifacts) {
            const results = await updateArtifacts({
                packageFileName: packageFile.path,
                updatedDeps,
                // TODO #22198
                newPackageFileContent: packageFile.contents.toString(),
                config,
            });
            if (is_1.default.nonEmptyArray(results)) {
                updatedPackageFiles.push(packageFile);
                for (const res of results) {
                    const { file, artifactError } = res;
                    // istanbul ignore else
                    if (file) {
                        updatedArtifacts.push(file);
                    }
                    else if (artifactError) {
                        artifactErrors.push(artifactError);
                    }
                }
            }
        }
    }
    if (!reuseExistingBranch) {
        // Only perform lock file maintenance if it's a fresh commit
        for (const packageFile of lockFileMaintenanceFiles) {
            const manager = packageFileManagers[packageFile];
            const updateArtifacts = (0, manager_1.get)(manager, 'updateArtifacts');
            if (updateArtifacts) {
                const packageFileContents = updatedFileContents[packageFile] ||
                    (await (0, git_1.getFile)(packageFile, config.baseBranch));
                const results = await updateArtifacts({
                    packageFileName: packageFile,
                    updatedDeps: [],
                    newPackageFileContent: packageFileContents,
                    config,
                });
                if (is_1.default.nonEmptyArray(results)) {
                    for (const res of results) {
                        const { file, artifactError } = res;
                        if (file) {
                            updatedArtifacts.push(file);
                        }
                        else if (artifactError) {
                            artifactErrors.push(artifactError);
                        }
                    }
                }
            }
        }
    }
    return {
        reuseExistingBranch, // Need to overwrite original config
        updatedPackageFiles,
        updatedArtifacts,
        artifactErrors,
    };
}
exports.getUpdatedPackageFiles = getUpdatedPackageFiles;
//# sourceMappingURL=get-updated.js.map