Files
renovate/lib/modules/versioning/ruby/strategies/replace.ts
T
Rhys Arkins dca3418bbd refactor: lib/modules (#14488)
Moves datasource, manager, platform and versioning code from lib/ into new lib/modules/

BREAKING CHANGE: External tools must update paths to datasource, manager, platform and versioning
2022-03-04 09:04:02 +01:00

104 lines
3.1 KiB
TypeScript

import { satisfies } from '@renovatebot/ruby-semver';
import { logger } from '../../../../logger';
import bump from './bump';
function countInstancesOf(str: string, char: string): number {
return str.split(char).length - 1;
}
function isMajorRange(range: string): boolean {
const splitRange = range.split(',').map((part) => part.trim());
return (
splitRange.length === 1 &&
splitRange[0]?.startsWith('~>') &&
countInstancesOf(splitRange[0], '.') === 0
);
}
function isCommonRubyMajorRange(range: string): boolean {
const splitRange = range.split(',').map((part) => part.trim());
return (
splitRange.length === 2 &&
splitRange[0]?.startsWith('~>') &&
countInstancesOf(splitRange[0], '.') === 1 &&
splitRange[1]?.startsWith('>=')
);
}
function isCommonRubyMinorRange(range: string): boolean {
const splitRange = range.split(',').map((part) => part.trim());
return (
splitRange.length === 2 &&
splitRange[0]?.startsWith('~>') &&
countInstancesOf(splitRange[0], '.') === 2 &&
splitRange[1]?.startsWith('>=')
);
}
function reduceOnePrecision(version: string): string {
const versionParts = version.split('.');
// istanbul ignore if
if (versionParts.length === 1) {
return version;
}
versionParts.pop();
return versionParts.join('.');
}
export function matchPrecision(existing: string, next: string): string {
let res = next;
while (res.split('.').length > existing.split('.').length) {
res = reduceOnePrecision(res);
}
return res;
}
export default ({ to, range }: { range: string; to: string }): string => {
if (satisfies(to, range)) {
return range;
}
let newRange;
if (isCommonRubyMajorRange(range)) {
const firstPart = reduceOnePrecision(to);
newRange = `~> ${firstPart}, >= ${to}`;
} else if (isCommonRubyMinorRange(range)) {
const firstPart = reduceOnePrecision(to) + '.0';
newRange = `~> ${firstPart}, >= ${to}`;
} else if (isMajorRange(range)) {
const majorPart = to.split('.')[0];
newRange = '~>' + (range.includes(' ') ? ' ' : '') + majorPart;
} else {
const lastPart = range
.split(',')
.map((part) => part.trim())
.slice(-1)
.join();
const lastPartPrecision = lastPart.split('.').length;
const toPrecision = to.split('.').length;
let massagedTo: string = to;
if (!lastPart.startsWith('<') && toPrecision > lastPartPrecision) {
massagedTo = to.split('.').slice(0, lastPartPrecision).join('.');
}
const newLastPart = bump({ to: massagedTo, range: lastPart });
newRange = range.replace(lastPart, newLastPart);
const firstPart = range
.split(',')
.map((part) => part.trim())
.shift();
if (firstPart && !satisfies(to, firstPart)) {
let newFirstPart = bump({ to: massagedTo, range: firstPart });
newFirstPart = matchPrecision(firstPart, newFirstPart);
newRange = newRange.replace(firstPart, newFirstPart);
}
}
// istanbul ignore if
if (!satisfies(to, newRange)) {
logger.warn(
{ range, to, newRange },
'Ruby versioning getNewValue problem: to version is not satisfied by new range'
);
return range;
}
return newRange;
};