fix(ivy): Make the versioning implementation more precise (#8363)

This commit is contained in:
Sergei Zharinov 2021-01-21 15:35:36 +04:00 committed by GitHub
parent d0531f52fb
commit 6e84bb1780
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 37 deletions

View file

@ -21,16 +21,6 @@ export const presets: Record<string, Preset> = {
}, },
], ],
}, },
ignoreSbtLatestIntegration: {
description: 'Do not upgrade sbt latest.integration',
packageRules: [
{
managers: ['sbt'],
matchCurrentVersion: '/^latest\\.integration$/',
enabled: false,
},
],
},
ignoreSpringCloudNumeric: { ignoreSpringCloudNumeric: {
description: 'Ignore spring cloud 1.x releases', description: 'Ignore spring cloud 1.x releases',
packageRules: [ packageRules: [

View file

@ -6,7 +6,7 @@ import {
} from './parse'; } from './parse';
import ivy from '.'; import ivy from '.';
const { isVersion, matches } = ivy; const { getNewValue, isValid, isVersion, matches } = ivy;
describe('versioning/ivy/match', () => { describe('versioning/ivy/match', () => {
it('parses dynamic revisions', () => { it('parses dynamic revisions', () => {
@ -61,7 +61,32 @@ describe('versioning/ivy/match', () => {
}); });
describe('versioning/ivy/index', () => { describe('versioning/ivy/index', () => {
it('validates version string', () => { it('isValid', () => {
expect(isValid('')).toBe(false);
expect(isValid('1.0.0')).toBe(true);
expect(isValid('0')).toBe(true);
expect(isValid('0.1-2-sp')).toBe(true);
expect(isValid('1-final')).toBe(true);
expect(isValid('v1.0.0')).toBe(true);
expect(isValid('x1.0.0')).toBe(true);
expect(isValid('2.1.1.RELEASE')).toBe(true);
expect(isValid('Greenwich.SR1')).toBe(true);
expect(isValid('.1')).toBe(false);
expect(isValid('1.')).toBe(false);
expect(isValid('-1')).toBe(false);
expect(isValid('1-')).toBe(false);
expect(isValid('latest')).toBe(true);
expect(isValid('latest.release')).toBe(true);
expect(isValid('latest.milestone')).toBe(true);
expect(isValid('latest.integration')).toBe(true);
expect(isValid('1.0.+')).toBe(true);
expect(isValid('1.0+')).toBe(false);
expect(isValid(']0,1[')).toBe(true);
expect(isValid('[0,1]')).toBe(true);
expect(isValid('[0,1),(1,2]')).toBe(false);
});
it('isVersion', () => {
expect(isVersion('')).toBe(false); expect(isVersion('')).toBe(false);
expect(isVersion('1.0.0')).toBe(true); expect(isVersion('1.0.0')).toBe(true);
expect(isVersion('0')).toBe(true); expect(isVersion('0')).toBe(true);
@ -76,17 +101,17 @@ describe('versioning/ivy/index', () => {
expect(isVersion('-1')).toBe(false); expect(isVersion('-1')).toBe(false);
expect(isVersion('1-')).toBe(false); expect(isVersion('1-')).toBe(false);
expect(isVersion('latest')).toBe(true); expect(isVersion('latest')).toBe(false);
expect(isVersion('latest.release')).toBe(true); expect(isVersion('latest.release')).toBe(false);
expect(isVersion('latest.milestone')).toBe(true); expect(isVersion('latest.milestone')).toBe(false);
expect(isVersion('latest.integration')).toBe(true); expect(isVersion('latest.integration')).toBe(false);
expect(isVersion('1.0.+')).toBe(true); expect(isVersion('1.0.+')).toBe(false);
expect(isVersion('1.0+')).toBe(false); expect(isVersion('1.0+')).toBe(false);
expect(isVersion(']0,1[')).toBe(true); expect(isVersion(']0,1[')).toBe(false);
expect(isVersion('[0,1]')).toBe(true); expect(isVersion('[0,1]')).toBe(false);
expect(isVersion('[0,1),(1,2]')).toBe(false); expect(isVersion('[0,1),(1,2]')).toBe(false);
}); });
it('matches against dynamic revisions', () => { it('matches', () => {
expect(matches('', 'latest')).toBe(false); expect(matches('', 'latest')).toBe(false);
expect(matches('0', '')).toBe(false); expect(matches('0', '')).toBe(false);
expect(matches('0', 'latest')).toBe(true); expect(matches('0', 'latest')).toBe(true);
@ -126,4 +151,51 @@ describe('versioning/ivy/index', () => {
expect(matches('1', '[1,)')).toBe(true); expect(matches('1', '[1,)')).toBe(true);
expect(matches('1', '(1,)')).toBe(false); expect(matches('1', '(1,)')).toBe(false);
}); });
it('api', () => {
expect(ivy.isGreaterThan('1.1', '1')).toBe(true);
expect(ivy.getSatisfyingVersion(['0', '1', '2'], '(,2)')).toBe('1');
expect(
ivy.getNewValue({
currentValue: '1',
rangeStrategy: 'auto',
fromVersion: '1',
toVersion: '1.1',
})
).toBe('1.1');
expect(
ivy.getNewValue({
currentValue: '[1.2.3,]',
rangeStrategy: 'auto',
fromVersion: '1.2.3',
toVersion: '1.2.4',
})
).toBe('[1.2.3,]');
});
it('pin', () => {
const sample = [
['[1.2.3]', '1.2.3', '1.2.4'],
['[1.0.0,1.2.3]', '1.0.0', '1.2.4'],
['[1.0.0,1.2.23]', '1.0.0', '1.2.23'],
['(,1.0]', '0.0.1', '2.0'],
['],1.0]', '0.0.1', '2.0'],
['(,1.0)', '0.1', '2.0'],
['],1.0[', '2.0', '],2.0['],
['[1.0,1.2],[1.3,1.5)', '1.0', '1.2.4'],
['[1.0,1.2],[1.3,1.5[', '1.0', '1.2.4'],
['[1.2.3,)', '1.2.3', '1.2.4'],
['[1.2.3,[', '1.2.3', '1.2.4'],
['latest.integration', '1.0', '2.0'],
['latest', '1.0', '2.0'],
];
sample.forEach(([currentValue, fromVersion, toVersion]) => {
expect(
getNewValue({
currentValue,
rangeStrategy: 'pin',
fromVersion,
toVersion,
})
).toEqual(toVersion);
});
});
}); });

View file

@ -1,7 +1,13 @@
import { VersioningApi } from '../common'; import { NewValueConfig, VersioningApi } from '../common';
import maven from '../maven'; import maven from '../maven';
import { TYPE_QUALIFIER, isSubversion, tokenize } from '../maven/compare';
import { import {
TYPE_QUALIFIER,
autoExtendMavenRange,
isSubversion,
tokenize,
} from '../maven/compare';
import {
LATEST_REGEX,
REV_TYPE_LATEST, REV_TYPE_LATEST,
REV_TYPE_SUBREV, REV_TYPE_SUBREV,
parseDynamicRevision, parseDynamicRevision,
@ -20,27 +26,27 @@ const {
getMinor, getMinor,
getPatch, getPatch,
isGreaterThan, isGreaterThan,
isSingleVersion,
isStable, isStable,
matches: mavenMatches, matches: mavenMatches,
getSatisfyingVersion,
minSatisfyingVersion,
getNewValue,
sortVersions, sortVersions,
} = maven; } = maven;
function isVersion(str: string): string | boolean { function isValid(str: string): string | boolean {
if (!str) { if (!str) {
return false; return false;
} }
return isSingleVersion(str) || !!parseDynamicRevision(str); return maven.isVersion(str) || !!parseDynamicRevision(str);
}
function isVersion(str: string): string | boolean {
if (!str || LATEST_REGEX.test(str)) {
return false;
}
return maven.isVersion(str);
} }
function matches(a: string, b: string): boolean { function matches(a: string, b: string): boolean {
if (!a) { if (!a || !b) {
return false;
}
if (!b) {
return false; return false;
} }
const dynamicRevision = parseDynamicRevision(b); const dynamicRevision = parseDynamicRevision(b);
@ -70,6 +76,31 @@ function matches(a: string, b: string): boolean {
return mavenMatches(a, value); return mavenMatches(a, value);
} }
function getSatisfyingVersion(versions: string[], range: string): string {
return versions.reduce((result, version) => {
if (matches(version, range)) {
if (!result) {
return version;
}
if (isGreaterThan(version, result)) {
return version;
}
}
return result;
}, null);
}
function getNewValue({
currentValue,
rangeStrategy,
toVersion,
}: NewValueConfig): string | null {
if (isVersion(currentValue) || rangeStrategy === 'pin') {
return toVersion;
}
return autoExtendMavenRange(currentValue, toVersion);
}
export const api: VersioningApi = { export const api: VersioningApi = {
equals, equals,
getMajor, getMajor,
@ -77,13 +108,13 @@ export const api: VersioningApi = {
getPatch, getPatch,
isCompatible: isVersion, isCompatible: isVersion,
isGreaterThan, isGreaterThan,
isSingleVersion, isSingleVersion: isVersion,
isStable, isStable,
isValid: isVersion, isValid,
isVersion, isVersion,
matches, matches,
getSatisfyingVersion, getSatisfyingVersion,
minSatisfyingVersion, minSatisfyingVersion: getSatisfyingVersion,
getNewValue, getNewValue,
sortVersions, sortVersions,
}; };

View file

@ -10,12 +10,13 @@ export interface Revision {
value: string; value: string;
} }
function parseDynamicRevision(str: string): Revision { export const LATEST_REGEX = /^latest\.|^latest$/i;
function parseDynamicRevision(str: string): Revision | null {
if (!str) { if (!str) {
return null; return null;
} }
const LATEST_REGEX = /^latest\.|^latest$/i;
if (LATEST_REGEX.test(str)) { if (LATEST_REGEX.test(str)) {
const value = str.replace(LATEST_REGEX, '').toLowerCase() || null; const value = str.replace(LATEST_REGEX, '').toLowerCase() || null;
return { return {