UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

207 lines • 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.postUpgradeCommandsExecutor = postUpgradeCommandsExecutor; exports.default = executePostUpgradeCommands; const tslib_1 = require("tslib"); const crypto_1 = tslib_1.__importDefault(require("crypto")); // TODO #22198 const is_1 = tslib_1.__importDefault(require("@sindresorhus/is")); const upath_1 = tslib_1.__importDefault(require("upath")); const config_1 = require("../../../../config"); const global_1 = require("../../../../config/global"); const logger_1 = require("../../../../logger"); const array_1 = require("../../../../util/array"); const exec_1 = require("../../../../util/exec"); const fs_1 = require("../../../../util/fs"); const git_1 = require("../../../../util/git"); const minimatch_1 = require("../../../../util/minimatch"); const regex_1 = require("../../../../util/regex"); const sanitize_1 = require("../../../../util/sanitize"); const template_1 = require("../../../../util/template"); async function postUpgradeCommandsExecutor(filteredUpgradeCommands, config) { let updatedArtifacts = [...(config.updatedArtifacts ?? [])]; const artifactErrors = [...(config.artifactErrors ?? [])]; const allowedCommands = global_1.GlobalConfig.get('allowedCommands'); for (const upgrade of filteredUpgradeCommands) { (0, logger_1.addMeta)({ dep: upgrade.depName }); logger_1.logger.trace({ tasks: upgrade.postUpgradeTasks, allowedCommands, }, `Checking for post-upgrade tasks`); const commands = upgrade.postUpgradeTasks?.commands; const dataFileTemplate = upgrade.postUpgradeTasks?.dataFileTemplate; const fileFilters = upgrade.postUpgradeTasks?.fileFilters ?? ['**/*']; if (is_1.default.nonEmptyArray(commands)) { // Persist updated files in file system so any executed commands can see them const previouslyModifiedFiles = config.updatedPackageFiles.concat(updatedArtifacts); for (const file of previouslyModifiedFiles) { const canWriteFile = await (0, fs_1.localPathIsFile)(file.path); if (file.type === 'addition' && !file.isSymlink && canWriteFile) { let contents; if (typeof file.contents === 'string') { contents = Buffer.from(file.contents); } else { contents = file.contents; } // TODO #22198 await (0, fs_1.writeLocalFile)(file.path, contents); } } let dataFilePath = null; if (dataFileTemplate) { const dataFileContent = (0, sanitize_1.sanitize)((0, template_1.compile)(dataFileTemplate, (0, config_1.mergeChildConfig)(config, upgrade))); logger_1.logger.debug({ dataFileTemplate }, 'Processed post-upgrade commands data file template.'); const dataFileName = `post-upgrade-data-file-${crypto_1.default.randomBytes(8).toString('hex')}.tmp`; dataFilePath = upath_1.default.join((0, fs_1.privateCacheDir)(), dataFileName); try { await (0, fs_1.outputCacheFile)(dataFilePath, dataFileContent); logger_1.logger.debug({ dataFilePath, dataFileContent }, 'Created post-upgrade commands data file.'); } catch (error) { artifactErrors.push({ stderr: (0, sanitize_1.sanitize)(`Failed to create post-upgrade commands data file at ${dataFilePath}, reason: ${error.message}`), }); dataFilePath = null; } } for (const cmd of commands) { const compiledCmd = (0, template_1.compile)(cmd, (0, config_1.mergeChildConfig)(config, upgrade)); if (compiledCmd !== cmd) { logger_1.logger.debug({ rawCmd: cmd, compiledCmd }, 'Post-upgrade command has been compiled'); } if (allowedCommands.some((pattern) => (0, regex_1.regEx)(pattern).test(compiledCmd))) { try { logger_1.logger.trace({ cmd: compiledCmd }, 'Executing post-upgrade task'); const execOpts = { cwd: global_1.GlobalConfig.get('localDir'), }; if (dataFilePath) { execOpts.env = { RENOVATE_POST_UPGRADE_COMMAND_DATA_FILE: dataFilePath, }; } const execResult = await (0, exec_1.exec)(compiledCmd, execOpts); logger_1.logger.debug({ cmd: compiledCmd, ...execResult }, 'Executed post-upgrade task'); } catch (error) { artifactErrors.push({ lockFile: upgrade.packageFile, stderr: (0, sanitize_1.sanitize)(error.message), }); } } else { logger_1.logger.warn({ cmd: compiledCmd, allowedCommands, }, 'Post-upgrade task did not match any on allowedCommands list'); artifactErrors.push({ lockFile: upgrade.packageFile, stderr: (0, sanitize_1.sanitize)(`Post-upgrade command '${compiledCmd}' has not been added to the allowed list in allowedCommands`), }); } } const status = await (0, git_1.getRepoStatus)(); logger_1.logger.trace({ status }, 'git status after post-upgrade tasks'); logger_1.logger.debug({ addedCount: status.not_added?.length, modifiedCount: status.modified?.length, deletedCount: status.deleted?.length, renamedCount: status.renamed?.length, }, 'git status counts after post-upgrade tasks'); const addedOrModifiedFiles = [ ...(0, array_1.coerceArray)(status.not_added), ...(0, array_1.coerceArray)(status.modified), ...(0, array_1.coerceArray)(status.renamed?.map((x) => x.to)), ]; const changedFiles = [ ...addedOrModifiedFiles, ...(0, array_1.coerceArray)(status.deleted), ...(0, array_1.coerceArray)(status.renamed?.map((x) => x.from)), ]; // Check for files which were previously deleted but have been re-added without modification const previouslyDeletedFiles = updatedArtifacts.filter((ua) => ua.type === 'deletion'); for (const previouslyDeletedFile of previouslyDeletedFiles) { if (!changedFiles.includes(previouslyDeletedFile.path)) { logger_1.logger.debug({ file: previouslyDeletedFile.path }, 'Previously deleted file has been restored without modification'); updatedArtifacts = updatedArtifacts.filter((ua) => !(ua.type === 'deletion' && ua.path === previouslyDeletedFile.path)); } } logger_1.logger.trace({ addedOrModifiedFiles }, 'Added or modified files'); logger_1.logger.debug(`Checking ${addedOrModifiedFiles.length} added or modified files for post-upgrade changes`); for (const relativePath of addedOrModifiedFiles) { let fileMatched = false; for (const pattern of fileFilters) { if ((0, minimatch_1.minimatch)(pattern, { dot: true }).match(relativePath)) { fileMatched = true; logger_1.logger.debug({ file: relativePath, pattern }, 'Post-upgrade file saved'); const existingContent = await (0, fs_1.readLocalFile)(relativePath); const existingUpdatedArtifacts = updatedArtifacts.find((ua) => ua.path === relativePath); if (existingUpdatedArtifacts?.type === 'addition') { existingUpdatedArtifacts.contents = existingContent; } else { updatedArtifacts.push({ type: 'addition', path: relativePath, contents: existingContent, }); } // If the file is deleted by a previous post-update command, remove the deletion from updatedArtifacts updatedArtifacts = updatedArtifacts.filter((ua) => !(ua.type === 'deletion' && ua.path === relativePath)); } } if (!fileMatched) { logger_1.logger.debug({ file: relativePath }, 'Post-upgrade file did not match any file filters'); } } for (const relativePath of (0, array_1.coerceArray)(status.deleted)) { for (const pattern of fileFilters) { if ((0, minimatch_1.minimatch)(pattern, { dot: true }).match(relativePath)) { if (!updatedArtifacts.some((ua) => ua.path === relativePath && ua.type === 'deletion')) { logger_1.logger.debug({ file: relativePath, pattern }, 'Post-upgrade file removed'); updatedArtifacts.push({ type: 'deletion', path: relativePath, }); } // If the file is created or modified by a previous post-update command, remove the modification from updatedArtifacts updatedArtifacts = updatedArtifacts.filter((ua) => !(ua.type === 'addition' && ua.path === relativePath)); } } } } } return { updatedArtifacts, artifactErrors }; } async function executePostUpgradeCommands(config) { const hasChangedFiles = (is_1.default.array(config.updatedPackageFiles) && config.updatedPackageFiles.length > 0) || (is_1.default.array(config.updatedArtifacts) && config.updatedArtifacts.length > 0); if (!hasChangedFiles) { /* Only run post-upgrade tasks if there are changes to package files... */ logger_1.logger.debug('No changes to package files, skipping post-upgrade tasks'); return null; } const branchUpgradeCommands = [ { manager: config.manager, depName: config.upgrades.map(({ depName }) => depName).join(' '), branchName: config.branchName, postUpgradeTasks: config.postUpgradeTasks.executionMode === 'branch' ? config.postUpgradeTasks : undefined, fileFilters: config.fileFilters, }, ]; const updateUpgradeCommands = config.upgrades.filter(({ postUpgradeTasks }) => !postUpgradeTasks?.executionMode || postUpgradeTasks.executionMode === 'update'); const { updatedArtifacts, artifactErrors } = await postUpgradeCommandsExecutor(updateUpgradeCommands, config); return postUpgradeCommandsExecutor(branchUpgradeCommands, { ...config, updatedArtifacts, artifactErrors, }); } //# sourceMappingURL=execute-post-upgrade-commands.js.map