renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
209 lines • 8.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.bumpVersions = bumpVersions;
const semver_1 = require("semver");
const logger_1 = require("../../../../logger");
const scm_1 = require("../../../../modules/platform/scm");
const array_1 = require("../../../../util/array");
const fs_1 = require("../../../../util/fs");
const regex_1 = require("../../../../util/regex");
const string_match_1 = require("../../../../util/string-match");
const template_1 = require("../../../../util/template");
const file_match_1 = require("../../extract/file-match");
async function bumpVersions(config) {
const bumpVersions = config.bumpVersions;
if (!bumpVersions?.length) {
return;
}
// skip if no packageFiles or artifacts have been updated
if (!config.updatedPackageFiles?.length && !config.updatedArtifacts?.length) {
return;
}
const allFiles = await scm_1.scm.getFileList();
const fileList = (0, file_match_1.getFilteredFileList)(config, allFiles);
const packageFileChanges = fileChangeListToMap(config.updatedPackageFiles);
const artifactFileChanges = fileChangeListToMap(config.updatedArtifacts);
for (const bumpVersionConfig of bumpVersions) {
await bumpVersion(bumpVersionConfig, config, fileList, packageFileChanges, artifactFileChanges);
}
// update the config with the new files
config.updatedPackageFiles = Object.values(packageFileChanges).flat();
config.updatedArtifacts = Object.values(artifactFileChanges).flat();
}
async function bumpVersion(config, branchConfig, fileList, packageFiles, artifactFiles) {
const rawBumpType = config.bumpType ?? 'patch';
// all log messages should be prefixed with this string to facilitate easier logLevelRemapping
const bumpVersionsDescr = config.name
? `bumpVersions(${config.name})`
: 'bumpVersions';
const files = [];
try {
files.push(...getMatchedFiles(bumpVersionsDescr, config.filePatterns, branchConfig, fileList));
}
catch (e) {
addArtifactError(branchConfig, `Failed to calculate matched files for bumpVersions: ${e.message}`);
return;
}
if (!files.length) {
logger_1.logger.debug(`${bumpVersionsDescr}: filePatterns did not match any files`);
return;
}
logger_1.logger.trace({ files }, `${bumpVersionsDescr}: Found ${files.length} files to bump versions`);
// keeping this only for logging purposes
const matchStrings = [];
// prepare the matchStrings
const matchStringsRegexes = [];
for (const matchString of config.matchStrings) {
try {
const templated = (0, template_1.compile)(matchString, branchConfig);
matchStrings.push(templated);
matchStringsRegexes.push((0, regex_1.regEx)(templated));
}
catch (e) {
addArtifactError(branchConfig, `Failed to compile matchString for ${bumpVersionsDescr}: ${e.message}`, matchString);
}
}
logger_1.logger.trace({ matchStrings }, `${bumpVersionsDescr}: Compiled matchStrings`);
for (const filePath of files) {
let fileBumped = false;
const fileContents = await getFileContent(bumpVersionsDescr, filePath, packageFiles, artifactFiles);
if (!fileContents) {
continue;
}
for (const matchStringRegex of matchStringsRegexes) {
// extracting the version from the file
const regexResult = matchStringRegex.exec(fileContents);
if (!regexResult) {
continue;
}
const version = regexResult.groups?.version;
if (!version) {
logger_1.logger.debug({ file: filePath }, `${bumpVersionsDescr}: No version found`);
continue;
}
// getting new version
let newVersion = null;
try {
const bumpType = (0, template_1.compile)(rawBumpType, branchConfig);
newVersion = (0, semver_1.inc)(version, bumpType);
}
catch (e) {
addArtifactError(branchConfig, `Failed to calculate new version for ${bumpVersionsDescr}: ${e.message}`, filePath);
}
if (!newVersion) {
logger_1.logger.debug({ file: filePath }, `${bumpVersionsDescr}: Could not bump version`);
continue;
}
// replace the content of the `version` group with newVersion
const newFileContents = fileContents
.toString()
.replace(matchStringRegex, (match, ...groups) => {
const { version } = groups.pop();
return match.replace(version, newVersion);
});
// update the file. Add it to the buckets if exists or create a new artifact update
if (packageFiles[filePath]) {
packageFiles[filePath].push({
type: 'addition',
path: filePath,
contents: newFileContents,
});
}
else {
artifactFiles[filePath] ??= [];
artifactFiles[filePath].push({
type: 'addition',
path: filePath,
contents: newFileContents,
});
}
fileBumped = true;
}
if (!fileBumped) {
logger_1.logger.debug({ file: filePath }, `${bumpVersionsDescr}: No match found for bumping version`);
}
}
}
/**
* Get files that match ANY of the fileMatches pattern. fileMatches are compiled with the branchConfig.
* @param bumpVersionsDescr log description for the bump version config
* @param filePatternTemplates list of regex patterns
* @param branchConfig compile metadata
* @param fileList list of files to match against
*/
function getMatchedFiles(bumpVersionsDescr, filePatternTemplates, branchConfig, fileList) {
// prepare file regex
const filePatterns = [];
for (const filePatternTemplateElement of filePatternTemplates) {
const filePattern = (0, template_1.compile)(filePatternTemplateElement, branchConfig);
filePatterns.push(filePattern);
}
logger_1.logger.trace({ filePatterns }, `${bumpVersionsDescr}: Compiled filePatterns`);
// get files that match the fileMatch
const files = [];
for (const file of fileList) {
if ((0, string_match_1.matchRegexOrGlobList)(file, filePatterns)) {
files.push(file);
}
}
return files;
}
function fileChangeListToMap(list) {
const record = {};
for (const fileChange of (0, array_1.coerceArray)(list)) {
record[fileChange.path] ??= [];
record[fileChange.path].push(fileChange);
}
return record;
}
function addArtifactError(branchConfig, message, fileName) {
branchConfig.artifactErrors ??= [];
branchConfig.artifactErrors.push({
stderr: message,
fileName,
});
}
async function getFileContent(bumpVersionsDescr, filePath, packageFiles, artifactFiles) {
const packageFileChanges = parseFileChanges(filePath, packageFiles);
const artifactFileChanges = parseFileChanges(filePath, artifactFiles);
// skip if the file is deleted as it virtually doesn't exist
if (packageFileChanges.state === 'deleted' ||
artifactFileChanges.state === 'deleted') {
return null;
}
if (packageFileChanges.state === 'modified') {
const lastChange = packageFileChanges.content;
if (lastChange) {
return lastChange;
}
}
if (artifactFileChanges.state === 'modified') {
const lastChange = artifactFileChanges.content;
if (lastChange) {
return lastChange;
}
}
try {
return await (0, fs_1.readLocalFile)(filePath, 'utf8');
}
catch (e) {
logger_1.logger.warn({ file: filePath }, `${bumpVersionsDescr}: Could not read file: ${e.message}`);
return null;
}
}
function parseFileChanges(filePath, changeRecord) {
const changes = (0, array_1.coerceArray)(changeRecord[filePath]);
// skip if we can fetch from record
if (!changes.length) {
return { state: 'unmodified' };
}
const lastChange = changes[changes.length - 1];
if (lastChange.type === 'deletion') {
return { state: 'deleted' };
}
return {
state: 'modified',
content: lastChange.contents?.toString() ?? null,
};
}
//# sourceMappingURL=bump-versions.js.map