"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateArtifacts = updateArtifacts;
const tslib_1 = require("tslib");
const shlex_1 = require("shlex");
const upath_1 = tslib_1.__importDefault(require("upath"));
const global_1 = require("../../../config/global");
const logger_1 = require("../../../logger");
const exec_1 = require("../../../util/exec");
const fs_1 = require("../../../util/fs");
const git_1 = require("../../../util/git");
const utils_1 = require("./utils");
const DEFAULT_COMMAND_OPTIONS = ['--skip-answered', '--defaults'];
function buildCommand(config, packageFileName, newVersion) {
    const command = ['copier', 'update', ...DEFAULT_COMMAND_OPTIONS];
    if (global_1.GlobalConfig.get('allowScripts') && !config.ignoreScripts) {
        command.push('--trust');
    }
    command.push('--answers-file', (0, shlex_1.quote)(upath_1.default.basename(packageFileName)), '--vcs-ref', (0, shlex_1.quote)(newVersion));
    return command.join(' ');
}
function artifactError(packageFileName, message) {
    return [
        {
            artifactError: {
                lockFile: packageFileName,
                stderr: message,
            },
        },
    ];
}
async function updateArtifacts({ packageFileName, updatedDeps, config, }) {
    if (!updatedDeps || updatedDeps.length !== 1) {
        // Each answers file (~ packageFileName) has exactly one dependency to update.
        return artifactError(packageFileName, `Unexpected number of dependencies: ${updatedDeps.length} (should be 1)`);
    }
    const newVersion = updatedDeps[0]?.newVersion ?? updatedDeps[0]?.newValue;
    if (!newVersion) {
        return artifactError(packageFileName, 'Missing copier template version to update to');
    }
    const command = buildCommand(config, packageFileName, newVersion);
    const execOptions = {
        cwdFile: packageFileName,
        docker: {},
        userConfiguredEnv: config.env,
        toolConstraints: [
            {
                toolName: 'python',
                constraint: (0, utils_1.getPythonVersionConstraint)(config),
            },
            {
                toolName: 'copier',
                constraint: (0, utils_1.getCopierVersionConstraint)(config),
            },
        ],
    };
    try {
        await (0, exec_1.exec)(command, execOptions);
    }
    catch (err) {
        logger_1.logger.debug({ err }, `Failed to update copier template: ${err.message}`);
        return artifactError(packageFileName, err.message);
    }
    const status = await (0, git_1.getRepoStatus)();
    // If the answers file didn't change, Copier did not update anything.
    if (!status.modified.includes(packageFileName)) {
        return null;
    }
    if (status.conflicted.length > 0) {
        // Sometimes, Copier erroneously reports conflicts.
        const msg = `Updating the Copier template yielded ${status.conflicted.length} merge conflicts. ` +
            'Please check the proposed changes carefully! Conflicting files:\n  * ' +
            status.conflicted.join('\n  * ');
        logger_1.logger.debug({ packageFileName, depName: updatedDeps[0]?.depName }, msg);
    }
    const res = [];
    for (const f of [
        ...status.modified,
        ...status.not_added,
        ...status.conflicted,
    ]) {
        const fileRes = {
            file: {
                type: 'addition',
                path: f,
                contents: await (0, fs_1.readLocalFile)(f),
            },
        };
        if (status.conflicted.includes(f)) {
            // Make the reviewer aware of the conflicts.
            // This will be posted in a comment.
            fileRes.notice = {
                file: f,
                message: 'This file had merge conflicts. Please check the proposed changes carefully!',
            };
        }
        res.push(fileRes);
    }
    for (const f of status.deleted) {
        res.push({
            file: {
                type: 'deletion',
                path: f,
            },
        });
    }
    // `git status` might detect a rename, which is then not contained
    // in not_added/deleted. Ensure we respect renames as well if they happen.
    for (const f of status.renamed) {
        res.push({
            file: {
                type: 'deletion',
                path: f.from,
            },
        });
        res.push({
            file: {
                type: 'addition',
                path: f.to,
                contents: await (0, fs_1.readLocalFile)(f.to),
            },
        });
    }
    return res;
}
//# sourceMappingURL=artifacts.js.map