Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add rez versioning #10930

Merged
merged 36 commits into from Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
cd6bb19
Add rez versioning with tests and docs
skral Jul 22, 2021
6b0dd16
Update note to mention we don't support pipes yet
skral Jul 22, 2021
3936123
Merge branch 'main' into feat/add-rez-versioning
viceice Jul 23, 2021
4729622
Improve clarity around rez based on semver
skral Jul 28, 2021
d0e01e1
Improve clarity around dot ranges
skral Jul 28, 2021
8d4b3a4
Improve clarity around exact versions
skral Jul 28, 2021
d3de6bb
Improve clarity around not supporting pipes yet
skral Jul 28, 2021
14b5473
Follow style guide and add spaces before it
skral Jul 28, 2021
9101eb7
Fix lint by running prettier
skral Jul 28, 2021
ca94324
Fix coverage
skral Jul 28, 2021
770dfa4
Fix import position to amtch style guide
skral Jul 29, 2021
25393cd
Merge branch 'main' into feat/add-rez-versioning
viceice Jul 29, 2021
c855885
Merge branch 'main' into feat/add-rez-versioning
viceice Jul 29, 2021
f7de465
Use proper casing
skral Jul 29, 2021
3f8935e
Add more clarity about pipes in rez
skral Jul 29, 2021
0078dff
Use backticks to keep with style
skral Jul 29, 2021
90d48e8
Merge branch 'main' into feat/add-rez-versioning
skral Sep 9, 2021
aba2544
Fix style
skral Sep 9, 2021
6ad7867
Merge branch 'main' into feat/add-rez-versioning
rarkins Sep 9, 2021
4ed36c3
Fix test name for linter
skral Sep 12, 2021
e6b4395
Revert hiding rez from versioning api
skral Sep 12, 2021
9d40035
Merge branch 'main' into feat/add-rez-versioning
skral Sep 12, 2021
a577f6b
Refactor to even out module size
skral Sep 13, 2021
143c558
Refactor tests to latest style
skral Sep 13, 2021
c07977f
Fix style
skral Sep 13, 2021
ef824c9
Merge branch 'main' into feat/add-rez-versioning
skral Sep 13, 2021
5e7a4ae
Fix security concerns
skral Sep 13, 2021
630afd9
Merge branch 'main' into feat/add-rez-versioning
skral Sep 13, 2021
82f713f
Merge branch 'main' into feat/add-rez-versioning
skral Sep 13, 2021
1917f2f
Fix style
skral Sep 13, 2021
839c72a
Merge branch 'feat/add-rez-versioning' of github.com:skral/renovate i…
skral Sep 13, 2021
3284ad3
Merge branch 'main' into feat/add-rez-versioning
skral Sep 13, 2021
02b0e10
Merge branch 'main' into feat/add-rez-versioning
skral Sep 15, 2021
8f2c765
Merge branch 'main' into feat/add-rez-versioning
rarkins Sep 15, 2021
f58a54c
Merge branch 'main' into feat/add-rez-versioning
rarkins Sep 17, 2021
4a513f2
Merge branch 'main' into feat/add-rez-versioning
viceice Sep 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/versioning/api.ts
Expand Up @@ -14,6 +14,7 @@ import * as nuget from './nuget';
import * as pep440 from './pep440';
import * as poetry from './poetry';
import * as regex from './regex';
import * as rez from './rez';
import * as ruby from './ruby';
import * as semver from './semver';
import * as swift from './swift';
Expand All @@ -39,6 +40,7 @@ api.set('nuget', nuget.api);
api.set('pep440', pep440.api);
api.set('poetry', poetry.api);
api.set('regex', regex.api);
api.set('rez', rez.api);
api.set('ruby', ruby.api);
api.set('semver', semver.api);
api.set('swift', swift.api);
Expand Down
2 changes: 0 additions & 2 deletions lib/versioning/index.spec.ts
Expand Up @@ -33,8 +33,6 @@ describe('versioning/index', () => {
const vers = allVersioning.getVersionings();

const loadedVers = loadModules(__dirname);
// TODO: revert rez in #10930
delete loadedVers.rez;
expect(Array.from(vers.keys())).toEqual(Object.keys(loadedVers));

for (const name of vers.keys()) {
Expand Down
442 changes: 442 additions & 0 deletions lib/versioning/rez/index.spec.ts

Large diffs are not rendered by default.

277 changes: 218 additions & 59 deletions lib/versioning/rez/index.ts
@@ -1,59 +1,218 @@
// istanbul ignore file: requires (#10930)

// original rez regex written in python (#11634)
// version_range_regex = (
// # Match a version number (e.g. 1.0.0)
// r" ^(?P<version>{version_group})$"
// "|"
// # Or match an exact version number (e.g. ==1.0.0)
// " ^(?P<exact_version>"
// " ==" # Required == operator
// " (?P<exact_version_group>{version_group})?"
// " )$"
// "|"
// # Or match an inclusive bound (e.g. 1.0.0..2.0.0)
// " ^(?P<inclusive_bound>"
// " (?P<inclusive_lower_version>{version_group})?"
// " \.\." # Required .. operator
// " (?P<inclusive_upper_version>{version_group})?"
// " )$"
// "|"
// # Or match a lower bound (e.g. 1.0.0+)
// " ^(?P<lower_bound>"
// " (?P<lower_bound_prefix>>|>=)?" # Bound is exclusive?
// " (?P<lower_version>{version_group})?"
// " (?(lower_bound_prefix)|\+)" # + only if bound is not exclusive
// " )$"
// "|"
// # Or match an upper bound (e.g. <=1.0.0)
// " ^(?P<upper_bound>"
// " (?P<upper_bound_prefix><(?={version_group})|<=)?" # Bound is exclusive?
// " (?P<upper_version>{version_group})?"
// " )$"
// "|"
// # Or match a range in ascending order (e.g. 1.0.0+<2.0.0)
// " ^(?P<range_asc>"
// " (?P<range_lower_asc>"
// " (?P<range_lower_asc_prefix>>|>=)?" # Lower bound is exclusive?
// " (?P<range_lower_asc_version>{version_group})?"
// " (?(range_lower_asc_prefix)|\+)?" # + only if lower bound is not exclusive
// " )(?P<range_upper_asc>"
// " (?(range_lower_asc_version),?|)" # , only if lower bound is found
// " (?P<range_upper_asc_prefix><(?={version_group})|<=)" # <= only if followed by a version group
// " (?P<range_upper_asc_version>{version_group})?"
// " )"
// " )$"
// "|"
// # Or match a range in descending order (e.g. <=2.0.0,1.0.0+)
// " ^(?P<range_desc>"
// " (?P<range_upper_desc>"
// " (?P<range_upper_desc_prefix><|<=)?" # Upper bound is exclusive?
// " (?P<range_upper_desc_version>{version_group})?"
// " (?(range_upper_desc_prefix)|\+)?" # + only if upper bound is not exclusive
// " )(?P<range_lower_desc>"
// " (?(range_upper_desc_version),|)" # Comma is not optional because we don't want to recognize something like "<4>3"
// " (?P<range_lower_desc_prefix><(?={version_group})|>=?)" # >= or > only if followed by a version group
// " (?P<range_lower_desc_version>{version_group})?"
// " )"
// " )$"
// ).format(version_group=version_group)
import { api as npm } from '../npm';
import { api as pep440 } from '../pep440';
import type { NewValueConfig, VersioningApi } from '../types';
import {
ascendingRange,
descendingRange,
exactVersion,
inclusiveBound,
lowerBound,
upperBound,
versionGroup,
} from './pattern';
import {
npm2rezplus,
padZeroes,
pep4402rezInclusiveBound,
rez2npm,
rez2pep440,
} from './transform';

export const id = 'rez';
export const displayName = 'rez';
export const urls = ['https://github.com/nerdvegas/rez'];
export const supportsRanges = true;
export const supportedRangeStrategies = ['bump', 'extend', 'pin', 'replace'];

function equals(a: string, b: string): boolean {
try {
return npm.equals(padZeroes(a), padZeroes(b));
} catch (err) /* istanbul ignore next */ {
return pep440.equals(a, b);
}
}

function getMajor(version: string): number {
try {
return npm.getMajor(padZeroes(version));
} catch (err) /* istanbul ignore next */ {
return pep440.getMajor(version);
}
}

function getMinor(version: string): number {
try {
return npm.getMinor(padZeroes(version));
} catch (err) /* istanbul ignore next */ {
return pep440.getMinor(version);
}
}

function getPatch(version: string): number {
try {
return npm.getPatch(padZeroes(version));
} catch (err) /* istanbul ignore next */ {
return pep440.getPatch(version);
}
}

function isGreaterThan(a: string, b: string): boolean {
try {
return npm.isGreaterThan(padZeroes(a), padZeroes(b));
} catch (err) /* istanbul ignore next */ {
return pep440.isGreaterThan(a, b);
}
}

function isLessThanRange(version: string, range: string): boolean {
return (
npm.isVersion(padZeroes(version)) &&
npm.isLessThanRange(padZeroes(version), rez2npm(range))
);
}

export function isValid(input: string): string | boolean {
return npm.isValid(rez2npm(input));
}

function isStable(version: string): boolean {
return npm.isStable(padZeroes(version));
}

function isVersion(input: string): string | boolean {
return npm.isVersion(padZeroes(rez2npm(input)));
}

function matches(version: string, range: string): boolean {
return (
npm.isVersion(padZeroes(version)) &&
npm.matches(padZeroes(version), rez2npm(range))
);
}

function getSatisfyingVersion(versions: string[], range: string): string {
return npm.getSatisfyingVersion(versions, rez2npm(range));
}

function minSatisfyingVersion(versions: string[], range: string): string {
return npm.minSatisfyingVersion(versions, rez2npm(range));
}

function isSingleVersion(constraint: string): string | boolean {
return (
(constraint.trim().startsWith('==') &&
isVersion(constraint.trim().substring(2).trim())) ||
isVersion(constraint.trim())
);
}

function sortVersions(a: string, b: string): number {
return npm.sortVersions(padZeroes(a), padZeroes(b));
}

function getNewValue({
currentValue,
rangeStrategy,
currentVersion,
newVersion,
}: NewValueConfig): string {
const pep440Value = pep440.getNewValue({
currentValue: rez2pep440(currentValue),
rangeStrategy,
currentVersion,
newVersion,
});
if (exactVersion.test(currentValue)) {
return pep440Value;
}
if (inclusiveBound.test(currentValue)) {
return pep4402rezInclusiveBound(pep440Value);
}
if (lowerBound.test(currentValue)) {
if (currentValue.includes('+')) {
return npm2rezplus(pep440Value);
}
return pep440Value;
}
if (upperBound.test(currentValue)) {
return pep440Value;
}
if (ascendingRange.test(currentValue)) {
// Replace version numbers but keep rez format, otherwise we just end up trying
// to convert every single case separately.
const match = ascendingRange.exec(currentValue);
const lowerBoundAscCurrent = match.groups.range_lower_asc;
const upperBoundAscCurrent = match.groups.range_upper_asc;
const lowerAscVersionCurrent = match.groups.range_lower_asc_version;
const upperAscVersionCurrent = match.groups.range_upper_asc_version;
const [lowerBoundAscPep440, upperBoundAscPep440] = pep440Value.split(', ');
const lowerAscVersionNew = new RegExp(versionGroup).exec(
lowerBoundAscPep440
)[0];
const upperAscVersionNew = new RegExp(versionGroup).exec(
upperBoundAscPep440
)[0];
const lowerBoundAscNew = lowerBoundAscCurrent.replace(
lowerAscVersionCurrent,
lowerAscVersionNew
);
const upperBoundAscNew = upperBoundAscCurrent.replace(
upperAscVersionCurrent,
upperAscVersionNew
);
const separator = currentValue.includes(',') ? ',' : '';

return lowerBoundAscNew + separator + upperBoundAscNew;
}
if (descendingRange.test(currentValue)) {
// Replace version numbers but keep rez format, otherwise we just end up trying
// to convert every single case separately.
const match = descendingRange.exec(currentValue);
const upperBoundDescCurrent = match.groups.range_upper_desc;
const lowerBoundDescCurrent = match.groups.range_lower_desc;
const upperDescVersionCurrent = match.groups.range_upper_desc_version;
const lowerDescVersionCurrent = match.groups.range_lower_desc_version;
const [lowerBoundDescPep440, upperBoundDescPep440] =
pep440Value.split(', ');

const upperDescVersionNew = new RegExp(versionGroup).exec(
upperBoundDescPep440
)[0];
const lowerDescVersionNew = new RegExp(versionGroup).exec(
lowerBoundDescPep440
)[0];
const upperBoundDescNew = upperBoundDescCurrent.replace(
upperDescVersionCurrent,
upperDescVersionNew
);
const lowerBoundDescNew = lowerBoundDescCurrent.replace(
lowerDescVersionCurrent,
lowerDescVersionNew
);
// Descending ranges are only supported with a comma.
const separator = ',';

return upperBoundDescNew + separator + lowerBoundDescNew;
}
return null;
}

export const api: VersioningApi = {
equals,
getMajor,
getMinor,
getPatch,
getNewValue,
getSatisfyingVersion,
isCompatible: isVersion,
isGreaterThan,
isLessThanRange,
isSingleVersion,
isStable,
isValid,
isVersion,
matches,
minSatisfyingVersion,
sortVersions,
};
export default api;
89 changes: 89 additions & 0 deletions lib/versioning/rez/pattern.ts
@@ -0,0 +1,89 @@
// Regular Expressions have been copied from, some more work were necessary to make it work:
// original rez regex written in python (#11634)
// version_range_regex = (
// # Match a version number (e.g. 1.0.0)
// r" ^(?P<version>{version_group})$"
// "|"
// # Or match an exact version number (e.g. ==1.0.0)
// " ^(?P<exact_version>"
// " ==" # Required == operator
// " (?P<exact_version_group>{version_group})?"
// " )$"
// "|"
// # Or match an inclusive bound (e.g. 1.0.0..2.0.0)
// " ^(?P<inclusive_bound>"
// " (?P<inclusive_lower_version>{version_group})?"
// " \.\." # Required .. operator
// " (?P<inclusive_upper_version>{version_group})?"
// " )$"
// "|"
// # Or match a lower bound (e.g. 1.0.0+)
// " ^(?P<lower_bound>"
// " (?P<lower_bound_prefix>>|>=)?" # Bound is exclusive?
// " (?P<lower_version>{version_group})?"
// " (?(lower_bound_prefix)|\+)" # + only if bound is not exclusive
// " )$"
// "|"
// # Or match an upper bound (e.g. <=1.0.0)
// " ^(?P<upper_bound>"
// " (?P<upper_bound_prefix><(?={version_group})|<=)?" # Bound is exclusive?
// " (?P<upper_version>{version_group})?"
// " )$"
// "|"
// # Or match a range in ascending order (e.g. 1.0.0+<2.0.0)
// " ^(?P<range_asc>"
// " (?P<range_lower_asc>"
// " (?P<range_lower_asc_prefix>>|>=)?" # Lower bound is exclusive?
// " (?P<range_lower_asc_version>{version_group})?"
// " (?(range_lower_asc_prefix)|\+)?" # + only if lower bound is not exclusive
// " )(?P<range_upper_asc>"
// " (?(range_lower_asc_version),?|)" # , only if lower bound is found
// " (?P<range_upper_asc_prefix><(?={version_group})|<=)" # <= only if followed by a version group
// " (?P<range_upper_asc_version>{version_group})?"
// " )"
// " )$"
// "|"
// # Or match a range in descending order (e.g. <=2.0.0,1.0.0+)
// " ^(?P<range_desc>"
// " (?P<range_upper_desc>"
// " (?P<range_upper_desc_prefix><|<=)?" # Upper bound is exclusive?
// " (?P<range_upper_desc_version>{version_group})?"
// " (?(range_upper_desc_prefix)|\+)?" # + only if upper bound is not exclusive
// " )(?P<range_lower_desc>"
// " (?(range_upper_desc_version),|)" # Comma is not optional because we don't want to recognize something like "<4>3"
// " (?P<range_lower_desc_prefix><(?={version_group})|>=?)" # >= or > only if followed by a version group
// " (?P<range_lower_desc_version>{version_group})?"
// " )"
// " )$"
// ).format(version_group=version_group)
// - Replace {version_group} -> ${versionGroup}
// - Replace (?P<...>) -> (?<...>)
// - Replace ?(...) -> \k<...>
// - Replace single \ -> double \
export const versionGroup = '([0-9a-zA-Z_]+(?:[.-][0-9a-zA-Z_]+)*)';
export const matchVersion = new RegExp(
`^(?<version>${versionGroup})$`
); /* Match a version number (e.g. 1.0.0) */
export const exactVersion = new RegExp(
`^(?<exact_version>==(?<exact_version_group>${versionGroup})?)$`
); /* Match an exact version number (e.g. ==1.0.0) */
// inclusiveBound is called inclusive but behaviour in rez is this:
// package-1..3 will match versions 1.2.3, 2.3.4, but not 3.0.0 or above
export const inclusiveBound = new RegExp(
`^(?<inclusive_bound>(?<inclusive_lower_version>${versionGroup})?\\.\\.(?<inclusive_upper_version>${versionGroup})?)$`
); /* Match an inclusive bound (e.g. 1.0.0..2.0.0) */
// Add ? after |\\+) in order to match >=1.15
export const lowerBound = new RegExp(
`^(?<lower_bound>(?<lower_bound_prefix>>|>=)?(?<lower_version>${versionGroup})?(\\k<lower_bound_prefix>|\\+)?)$`
); /* Match a lower bound (e.g. 1.0.0+) */
export const upperBound = new RegExp(
`^(?<upper_bound>(?<upper_bound_prefix><(?=${versionGroup})|<=)?(?<upper_version>${versionGroup})?)$`
); /* Match an upper bound (e.g. <=1.0.0) */
// Add ,? to match >=7,<9 (otherwise it just matches >=7<9)
export const ascendingRange = new RegExp(
`^(?<range_asc>(?<range_lower_asc>(?<range_lower_asc_prefix>>|>=)?(?<range_lower_asc_version>${versionGroup})?(\\k<range_lower_asc_prefix>|\\+)?),?(?<range_upper_asc>(\\k<range_lower_asc_version>,?|)(?<range_upper_asc_prefix><(?=${versionGroup})|<=)(?<range_upper_asc_version>${versionGroup})?))$`
); /* Match a range in ascending order (e.g. 1.0.0+<2.0.0) */
// Add , to match <9,>=7 (otherwise it just matches <9>=7)
export const descendingRange = new RegExp(
`^(?<range_desc>(?<range_upper_desc>(?<range_upper_desc_prefix><|<=)?(?<range_upper_desc_version>${versionGroup})?(\\k<range_upper_desc_prefix>|\\+)?),(?<range_lower_desc>(\\k<range_upper_desc_version>,|)(?<range_lower_desc_prefix><(?=${versionGroup})|>=?)(?<range_lower_desc_version>${versionGroup})?))$`
); /* Match a range in descending order (e.g. <=2.0.0,1.0.0+) */