feat(nuget): add version scheme (#4749)

This commit is contained in:
Mark Raymond 2019-11-01 19:10:33 +00:00 committed by Rhys Arkins
parent bc763ad617
commit 5d01acc514
6 changed files with 194 additions and 0 deletions

View file

@ -551,6 +551,7 @@ const options: RenovateOptions[] = [
'maven', 'maven',
'node', 'node',
'npm', 'npm',
'nuget',
'pep440', 'pep440',
'poetry', 'poetry',
'regex', 'regex',

View file

@ -0,0 +1,59 @@
import * as generic from '../loose/generic';
import { VersioningApi } from '../common';
const pattern = /^(\d+(?:\.\d+)*)(-[^+]+)?(\+.*)?$/;
function parse(version: string) {
const matches = pattern.exec(version);
if (!matches) {
return null;
}
const [, prefix, prereleasesuffix] = matches;
const release = prefix.split('.').map(Number);
return { release, suffix: prereleasesuffix || '' };
}
function compare(version1: string, vervion2: string) {
const parsed1 = parse(version1);
const parsed2 = parse(vervion2);
// istanbul ignore if
if (!(parsed1 && parsed2)) {
return 1;
}
const length = Math.max(parsed1.release.length, parsed2.release.length);
for (let i = 0; i < length; i += 1) {
// 2.1 and 2.1.0 are equivalent
const part1 = parsed1.release[i] || 0;
const part2 = parsed2.release[i] || 0;
if (part1 !== part2) {
return part1 - part2;
}
}
// numeric version equals
const suffixComparison = parsed1.suffix.localeCompare(parsed2.suffix);
if (suffixComparison !== 0) {
// Empty suffix should compare greater than non-empty suffix
if (parsed1.suffix === '') {
return 1;
}
if (parsed2.suffix === '') {
return -1;
}
}
return suffixComparison;
}
function isStable(version: string) {
const parsed = parse(version);
return parsed && parsed.suffix === '';
}
export const api: VersioningApi = {
...generic.create({
parse,
compare,
}),
isStable,
};
export default api;

View file

@ -0,0 +1,24 @@
# NuGet versioning
## Documentation and URLs
https://docs.microsoft.com/en-us/nuget/concepts/package-versioning
The intention of this version scheme is to match as closely as possible the version comparison that NuGet itself uses.
## What type of versioning is used?
NuGet supports SemVer 2.0.0, but permits versions with differing numbers of version parts.
## Are ranges supported? How?
Ranges are not yet supported by this version scheme, but they are defined in NuGet and could be supported in the future.
## Range Strategy support
Not yet implemented.
## Implementation plan/status
- [x] Best effort parsing and sorting
- [ ] Range support

View file

@ -312,6 +312,7 @@
"maven", "maven",
"node", "node",
"npm", "npm",
"nuget",
"pep440", "pep440",
"poetry", "poetry",
"regex", "regex",

View file

@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`nuget. isStable 1.0.0+c30d7625 1`] = `true`;
exports[`nuget. isStable 1.2019.3.22 1`] = `true`;
exports[`nuget. isStable 2.0.2-pre20191018090318 1`] = `false`;
exports[`nuget. isStable 2.3.4-beta+1990ef74 1`] = `false`;
exports[`nuget. isStable 3.0.0-beta 1`] = `false`;
exports[`nuget. isStable 9.0.3 1`] = `true`;
exports[`nuget. isVersion and isValid 1.0.0+c30d7625 1`] = `"1.0.0+c30d7625"`;
exports[`nuget. isVersion and isValid 1.0.0+c30d7625 2`] = `"1.0.0+c30d7625"`;
exports[`nuget. isVersion and isValid 1.2019.3.22 1`] = `"1.2019.3.22"`;
exports[`nuget. isVersion and isValid 1.2019.3.22 2`] = `"1.2019.3.22"`;
exports[`nuget. isVersion and isValid 2.0.2-pre20191018090318 1`] = `"2.0.2-pre20191018090318"`;
exports[`nuget. isVersion and isValid 2.0.2-pre20191018090318 2`] = `"2.0.2-pre20191018090318"`;
exports[`nuget. isVersion and isValid 2.3.4-beta+1990ef74 1`] = `"2.3.4-beta+1990ef74"`;
exports[`nuget. isVersion and isValid 2.3.4-beta+1990ef74 2`] = `"2.3.4-beta+1990ef74"`;
exports[`nuget. isVersion and isValid 3.0.0.beta 1`] = `null`;
exports[`nuget. isVersion and isValid 3.0.0.beta 2`] = `null`;
exports[`nuget. isVersion and isValid 3.0.0-beta 1`] = `"3.0.0-beta"`;
exports[`nuget. isVersion and isValid 3.0.0-beta 2`] = `"3.0.0-beta"`;
exports[`nuget. isVersion and isValid 5.1.2-+ 1`] = `null`;
exports[`nuget. isVersion and isValid 5.1.2-+ 2`] = `null`;
exports[`nuget. isVersion and isValid 9.0.3 1`] = `"9.0.3"`;
exports[`nuget. isVersion and isValid 9.0.3 2`] = `"9.0.3"`;
exports[`nuget. isVersion and isValid 17.04 1`] = `"17.04"`;
exports[`nuget. isVersion and isValid 17.04 2`] = `"17.04"`;

View file

@ -0,0 +1,60 @@
import nuget from '../../lib/versioning/nuget';
describe('nuget.', () => {
describe('isVersion and isValid', () => {
[
'9.0.3',
'1.2019.3.22',
'3.0.0-beta',
'2.0.2-pre20191018090318',
'1.0.0+c30d7625',
'2.3.4-beta+1990ef74',
'17.04',
'3.0.0.beta',
'5.1.2-+',
].forEach(version => {
it(version, () => {
expect(nuget.isVersion(version)).toMatchSnapshot();
expect(nuget.isValid(version)).toMatchSnapshot();
});
});
});
describe('isStable', () => {
[
'9.0.3',
'1.2019.3.22',
'3.0.0-beta',
'2.0.2-pre20191018090318',
'1.0.0+c30d7625',
'2.3.4-beta+1990ef74',
].forEach(version => {
it(version, () => {
expect(nuget.isStable(version)).toMatchSnapshot();
});
});
});
describe('isEqual', () => {
it('should ignore leading zeros', () => {
expect(nuget.equals('17.4', '17.04')).toBe(true);
});
it('should treat missing trailing version parts as zero', () => {
expect(nuget.equals('1.4', '1.4.0')).toBe(true);
expect(nuget.equals('1.0.110', '1.0.110.0')).toBe(true);
});
it('should ignore hash suffixes', () => {
expect(nuget.equals('1.0.0', '1.0.0+c30d7625')).toBe(true);
});
});
describe('isGreaterThan', () => {
it('should compare using release number then suffix', () => {
expect(nuget.isGreaterThan('2.4.2', '2.4.1')).toBe(true);
expect(nuget.isGreaterThan('2.4-beta', '2.4-alpha')).toBe(true);
expect(nuget.isGreaterThan('1.9', '2')).toBe(false);
expect(nuget.isGreaterThan('1.9', '1.9.1')).toBe(false);
});
it('should prioritize non-prerelease over prerelease', () => {
expect(nuget.isGreaterThan('2.4.0', '2.4.0-beta')).toBe(true);
expect(nuget.isGreaterThan('2.4.0-alpha', '2.4.0')).toBe(false);
});
});
});