mirror of
https://github.com/astral-sh/setup-uv.git
synced 2025-04-05 07:05:18 -04:00
Add support for pep440 version identifiers
This commit is contained in:
parent
2d49baf2b6
commit
a9389853bb
6 changed files with 860 additions and 6 deletions
18
.github/workflows/test.yml
vendored
18
.github/workflows/test.yml
vendored
|
@ -82,6 +82,23 @@ jobs:
|
|||
env:
|
||||
UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }}
|
||||
|
||||
test-pep440-version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install version 0.4.30
|
||||
id: setup-uv
|
||||
uses: ./
|
||||
with:
|
||||
version: ">=0.4.25,<0.5"
|
||||
- name: Correct version gets installed
|
||||
run: |
|
||||
if [ "$UV_VERSION" != "0.4.30" ]; then
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }}
|
||||
|
||||
test-pyproject-file-version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -475,6 +492,7 @@ jobs:
|
|||
- test-default-version
|
||||
- test-specific-version
|
||||
- test-semver-range
|
||||
- test-pep440-version
|
||||
- test-pyproject-file-version
|
||||
- test-malformed-pyproject-file-fallback
|
||||
- test-uv-file-version
|
||||
|
|
|
@ -66,6 +66,7 @@ For an example workflow, see
|
|||
### Install a version by supplying a semver range
|
||||
|
||||
You can specify a [semver range](https://github.com/npm/node-semver?tab=readme-ov-file#ranges)
|
||||
or [pep440 identifier](https://peps.python.org/pep-0440/#version-specifiers)
|
||||
to install the latest version that satisfies the range.
|
||||
|
||||
```yaml
|
||||
|
@ -82,6 +83,13 @@ to install the latest version that satisfies the range.
|
|||
version: "0.4.x"
|
||||
```
|
||||
|
||||
```yaml
|
||||
- name: Install a pep440-specifier-satisfying version of uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
with:
|
||||
version: ">=0.4.25,<0.5"
|
||||
```
|
||||
|
||||
### Install a required-version
|
||||
|
||||
You can specify a [required-version](https://docs.astral.sh/uv/reference/settings/#required-version)
|
||||
|
|
795
dist/setup/index.js
generated
vendored
795
dist/setup/index.js
generated
vendored
|
@ -76630,6 +76630,783 @@ class ReflectionTypeCheck {
|
|||
exports.ReflectionTypeCheck = ReflectionTypeCheck;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 63297:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
const { valid, clean, explain, parse } = __nccwpck_require__(99961);
|
||||
|
||||
const { lt, le, eq, ne, ge, gt, compare, rcompare } = __nccwpck_require__(99469);
|
||||
|
||||
const {
|
||||
filter,
|
||||
maxSatisfying,
|
||||
minSatisfying,
|
||||
RANGE_PATTERN,
|
||||
satisfies,
|
||||
validRange,
|
||||
} = __nccwpck_require__(23185);
|
||||
|
||||
const { major, minor, patch, inc } = __nccwpck_require__(6829);
|
||||
|
||||
module.exports = {
|
||||
// version
|
||||
valid,
|
||||
clean,
|
||||
explain,
|
||||
parse,
|
||||
|
||||
// operator
|
||||
lt,
|
||||
le,
|
||||
lte: le,
|
||||
eq,
|
||||
ne,
|
||||
neq: ne,
|
||||
ge,
|
||||
gte: ge,
|
||||
gt,
|
||||
compare,
|
||||
rcompare,
|
||||
|
||||
// range
|
||||
filter,
|
||||
maxSatisfying,
|
||||
minSatisfying,
|
||||
RANGE_PATTERN,
|
||||
satisfies,
|
||||
validRange,
|
||||
|
||||
// semantic
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
inc,
|
||||
};
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 99469:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
const { parse } = __nccwpck_require__(99961);
|
||||
|
||||
module.exports = {
|
||||
compare,
|
||||
rcompare,
|
||||
lt,
|
||||
le,
|
||||
eq,
|
||||
ne,
|
||||
ge,
|
||||
gt,
|
||||
'<': lt,
|
||||
'<=': le,
|
||||
'==': eq,
|
||||
'!=': ne,
|
||||
'>=': ge,
|
||||
'>': gt,
|
||||
'===': arbitrary,
|
||||
};
|
||||
|
||||
function lt(version, other) {
|
||||
return compare(version, other) < 0;
|
||||
}
|
||||
|
||||
function le(version, other) {
|
||||
return compare(version, other) <= 0;
|
||||
}
|
||||
|
||||
function eq(version, other) {
|
||||
return compare(version, other) === 0;
|
||||
}
|
||||
|
||||
function ne(version, other) {
|
||||
return compare(version, other) !== 0;
|
||||
}
|
||||
|
||||
function ge(version, other) {
|
||||
return compare(version, other) >= 0;
|
||||
}
|
||||
|
||||
function gt(version, other) {
|
||||
return compare(version, other) > 0;
|
||||
}
|
||||
|
||||
function arbitrary(version, other) {
|
||||
return version.toLowerCase() === other.toLowerCase();
|
||||
}
|
||||
|
||||
function compare(version, other) {
|
||||
const parsedVersion = parse(version);
|
||||
const parsedOther = parse(other);
|
||||
|
||||
const keyVersion = calculateKey(parsedVersion);
|
||||
const keyOther = calculateKey(parsedOther);
|
||||
|
||||
return pyCompare(keyVersion, keyOther);
|
||||
}
|
||||
|
||||
function rcompare(version, other) {
|
||||
return -compare(version, other);
|
||||
}
|
||||
|
||||
// this logic is buitin in python, but we need to port it to js
|
||||
// see https://stackoverflow.com/a/5292332/1438522
|
||||
function pyCompare(elemIn, otherIn) {
|
||||
let elem = elemIn;
|
||||
let other = otherIn;
|
||||
if (elem === other) {
|
||||
return 0;
|
||||
}
|
||||
if (Array.isArray(elem) !== Array.isArray(other)) {
|
||||
elem = Array.isArray(elem) ? elem : [elem];
|
||||
other = Array.isArray(other) ? other : [other];
|
||||
}
|
||||
if (Array.isArray(elem)) {
|
||||
const len = Math.min(elem.length, other.length);
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
const res = pyCompare(elem[i], other[i]);
|
||||
if (res !== 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return elem.length - other.length;
|
||||
}
|
||||
if (elem === -Infinity || other === Infinity) {
|
||||
return -1;
|
||||
}
|
||||
if (elem === Infinity || other === -Infinity) {
|
||||
return 1;
|
||||
}
|
||||
return elem < other ? -1 : 1;
|
||||
}
|
||||
|
||||
function calculateKey(input) {
|
||||
const { epoch } = input;
|
||||
let { release, pre, post, local, dev } = input;
|
||||
// When we compare a release version, we want to compare it with all of the
|
||||
// trailing zeros removed. So we'll use a reverse the list, drop all the now
|
||||
// leading zeros until we come to something non zero, then take the rest
|
||||
// re-reverse it back into the correct order and make it a tuple and use
|
||||
// that for our sorting key.
|
||||
release = release.concat();
|
||||
release.reverse();
|
||||
while (release.length && release[0] === 0) {
|
||||
release.shift();
|
||||
}
|
||||
release.reverse();
|
||||
|
||||
// We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
||||
// We'll do this by abusing the pre segment, but we _only_ want to do this
|
||||
// if there is !a pre or a post segment. If we have one of those then
|
||||
// the normal sorting rules will handle this case correctly.
|
||||
if (!pre && !post && dev) pre = -Infinity;
|
||||
// Versions without a pre-release (except as noted above) should sort after
|
||||
// those with one.
|
||||
else if (!pre) pre = Infinity;
|
||||
|
||||
// Versions without a post segment should sort before those with one.
|
||||
if (!post) post = -Infinity;
|
||||
|
||||
// Versions without a development segment should sort after those with one.
|
||||
if (!dev) dev = Infinity;
|
||||
|
||||
if (!local) {
|
||||
// Versions without a local segment should sort before those with one.
|
||||
local = -Infinity;
|
||||
} else {
|
||||
// Versions with a local segment need that segment parsed to implement
|
||||
// the sorting rules in PEP440.
|
||||
// - Alpha numeric segments sort before numeric segments
|
||||
// - Alpha numeric segments sort lexicographically
|
||||
// - Numeric segments sort numerically
|
||||
// - Shorter versions sort before longer versions when the prefixes
|
||||
// match exactly
|
||||
local = local.map((i) =>
|
||||
Number.isNaN(Number(i)) ? [-Infinity, i] : [Number(i), ''],
|
||||
);
|
||||
}
|
||||
|
||||
return [epoch, release, pre, post, dev, local];
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 6829:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
const { explain, parse, stringify } = __nccwpck_require__(99961);
|
||||
|
||||
// those notation are borrowed from semver
|
||||
module.exports = {
|
||||
major,
|
||||
minor,
|
||||
patch,
|
||||
inc,
|
||||
};
|
||||
|
||||
function major(input) {
|
||||
const version = explain(input);
|
||||
if (!version) {
|
||||
throw new TypeError('Invalid Version: ' + input);
|
||||
}
|
||||
return version.release[0];
|
||||
}
|
||||
|
||||
function minor(input) {
|
||||
const version = explain(input);
|
||||
if (!version) {
|
||||
throw new TypeError('Invalid Version: ' + input);
|
||||
}
|
||||
if (version.release.length < 2) {
|
||||
return 0;
|
||||
}
|
||||
return version.release[1];
|
||||
}
|
||||
|
||||
function patch(input) {
|
||||
const version = explain(input);
|
||||
if (!version) {
|
||||
throw new TypeError('Invalid Version: ' + input);
|
||||
}
|
||||
if (version.release.length < 3) {
|
||||
return 0;
|
||||
}
|
||||
return version.release[2];
|
||||
}
|
||||
|
||||
function inc(input, release, preReleaseIdentifier) {
|
||||
let identifier = preReleaseIdentifier || `a`;
|
||||
const version = parse(input);
|
||||
|
||||
if (!version) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
!['a', 'b', 'c', 'rc', 'alpha', 'beta', 'pre', 'preview'].includes(
|
||||
identifier,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (release) {
|
||||
case 'premajor':
|
||||
{
|
||||
const [majorVersion] = version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion + 1;
|
||||
}
|
||||
version.pre = [identifier, 0];
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'preminor':
|
||||
{
|
||||
const [majorVersion, minorVersion = 0] = version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion;
|
||||
version.release[1] = minorVersion + 1;
|
||||
}
|
||||
version.pre = [identifier, 0];
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'prepatch':
|
||||
{
|
||||
const [majorVersion, minorVersion = 0, patchVersion = 0] =
|
||||
version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion;
|
||||
version.release[1] = minorVersion;
|
||||
version.release[2] = patchVersion + 1;
|
||||
}
|
||||
version.pre = [identifier, 0];
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'prerelease':
|
||||
if (version.pre === null) {
|
||||
const [majorVersion, minorVersion = 0, patchVersion = 0] =
|
||||
version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion;
|
||||
version.release[1] = minorVersion;
|
||||
version.release[2] = patchVersion + 1;
|
||||
version.pre = [identifier, 0];
|
||||
} else {
|
||||
if (preReleaseIdentifier === undefined && version.pre !== null) {
|
||||
[identifier] = version.pre;
|
||||
}
|
||||
|
||||
const [letter, number] = version.pre;
|
||||
if (letter === identifier) {
|
||||
version.pre = [letter, number + 1];
|
||||
} else {
|
||||
version.pre = [identifier, 0];
|
||||
}
|
||||
}
|
||||
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'major':
|
||||
if (
|
||||
version.release.slice(1).some((value) => value !== 0) ||
|
||||
version.pre === null
|
||||
) {
|
||||
const [majorVersion] = version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion + 1;
|
||||
}
|
||||
delete version.pre;
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'minor':
|
||||
if (
|
||||
version.release.slice(2).some((value) => value !== 0) ||
|
||||
version.pre === null
|
||||
) {
|
||||
const [majorVersion, minorVersion = 0] = version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion;
|
||||
version.release[1] = minorVersion + 1;
|
||||
}
|
||||
delete version.pre;
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
case 'patch':
|
||||
if (
|
||||
version.release.slice(3).some((value) => value !== 0) ||
|
||||
version.pre === null
|
||||
) {
|
||||
const [majorVersion, minorVersion = 0, patchVersion = 0] =
|
||||
version.release;
|
||||
version.release.fill(0);
|
||||
version.release[0] = majorVersion;
|
||||
version.release[1] = minorVersion;
|
||||
version.release[2] = patchVersion + 1;
|
||||
}
|
||||
delete version.pre;
|
||||
delete version.post;
|
||||
delete version.dev;
|
||||
delete version.local;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return stringify(version);
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 23185:
|
||||
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||
|
||||
// This file is dual licensed under the terms of the Apache License, Version
|
||||
// 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
// for complete details.
|
||||
|
||||
const { VERSION_PATTERN, explain: explainVersion } = __nccwpck_require__(99961);
|
||||
|
||||
const Operator = __nccwpck_require__(99469);
|
||||
|
||||
const RANGE_PATTERN = [
|
||||
'(?<operator>(===|~=|==|!=|<=|>=|<|>))',
|
||||
'\\s*',
|
||||
'(',
|
||||
/* */ '(?<version>(?:' + VERSION_PATTERN.replace(/\?<\w+>/g, '?:') + '))',
|
||||
/* */ '(?<prefix>\\.\\*)?',
|
||||
/* */ '|',
|
||||
/* */ '(?<legacy>[^,;\\s)]+)',
|
||||
')',
|
||||
].join('');
|
||||
|
||||
module.exports = {
|
||||
RANGE_PATTERN,
|
||||
parse,
|
||||
satisfies,
|
||||
filter,
|
||||
validRange,
|
||||
maxSatisfying,
|
||||
minSatisfying,
|
||||
};
|
||||
|
||||
const isEqualityOperator = (op) => ['==', '!=', '==='].includes(op);
|
||||
|
||||
const rangeRegex = new RegExp('^' + RANGE_PATTERN + '$', 'i');
|
||||
|
||||
function parse(ranges) {
|
||||
if (!ranges.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const specifiers = ranges
|
||||
.split(',')
|
||||
.map((range) => rangeRegex.exec(range.trim()) || {})
|
||||
.map(({ groups }) => {
|
||||
if (!groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let { ...spec } = groups;
|
||||
const { operator, version, prefix, legacy } = groups;
|
||||
|
||||
if (version) {
|
||||
spec = { ...spec, ...explainVersion(version) };
|
||||
if (operator === '~=') {
|
||||
if (spec.release.length < 2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!isEqualityOperator(operator) && spec.local) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
if (!isEqualityOperator(operator) || spec.dev || spec.local) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (legacy && operator !== '===') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return spec;
|
||||
});
|
||||
|
||||
if (specifiers.filter(Boolean).length !== specifiers.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return specifiers;
|
||||
}
|
||||
|
||||
function filter(versions, specifier, options = {}) {
|
||||
const filtered = pick(versions, specifier, options);
|
||||
if (filtered.length === 0 && options.prereleases === undefined) {
|
||||
return pick(versions, specifier, { prereleases: true });
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
function maxSatisfying(versions, range, options) {
|
||||
const found = filter(versions, range, options).sort(Operator.compare);
|
||||
return found.length === 0 ? null : found[found.length - 1];
|
||||
}
|
||||
|
||||
function minSatisfying(versions, range, options) {
|
||||
const found = filter(versions, range, options).sort(Operator.compare);
|
||||
return found.length === 0 ? null : found[0];
|
||||
}
|
||||
|
||||
function pick(versions, specifier, options) {
|
||||
const parsed = parse(specifier);
|
||||
|
||||
if (!parsed) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return versions.filter((version) => {
|
||||
const explained = explainVersion(version);
|
||||
|
||||
if (!parsed.length) {
|
||||
return explained && !(explained.is_prerelease && !options.prereleases);
|
||||
}
|
||||
|
||||
return parsed.reduce((pass, spec) => {
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
return contains({ ...spec, ...options }, { version, explained });
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
function satisfies(version, specifier, options = {}) {
|
||||
const filtered = pick([version], specifier, options);
|
||||
|
||||
return filtered.length === 1;
|
||||
}
|
||||
|
||||
function arrayStartsWith(array, prefix) {
|
||||
if (prefix.length > array.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < prefix.length; i += 1) {
|
||||
if (prefix[i] !== array[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function contains(specifier, input) {
|
||||
const { explained } = input;
|
||||
let { version } = input;
|
||||
const { ...spec } = specifier;
|
||||
|
||||
if (spec.prereleases === undefined) {
|
||||
spec.prereleases = spec.is_prerelease;
|
||||
}
|
||||
|
||||
if (explained && explained.is_prerelease && !spec.prereleases) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spec.operator === '~=') {
|
||||
let compatiblePrefix = spec.release.slice(0, -1).concat('*').join('.');
|
||||
if (spec.epoch) {
|
||||
compatiblePrefix = spec.epoch + '!' + compatiblePrefix;
|
||||
}
|
||||
return satisfies(version, `>=${spec.version}, ==${compatiblePrefix}`);
|
||||
}
|
||||
|
||||
if (spec.prefix) {
|
||||
const isMatching =
|
||||
explained.epoch === spec.epoch &&
|
||||
arrayStartsWith(explained.release, spec.release);
|
||||
const isEquality = spec.operator !== '!=';
|
||||
return isEquality ? isMatching : !isMatching;
|
||||
}
|
||||
|
||||
if (explained)
|
||||
if (explained.local && spec.version) {
|
||||
version = explained.public;
|
||||
spec.version = explainVersion(spec.version).public;
|
||||
}
|
||||
|
||||
if (spec.operator === '<' || spec.operator === '>') {
|
||||
// simplified version of https://www.python.org/dev/peps/pep-0440/#exclusive-ordered-comparison
|
||||
if (Operator.eq(spec.release.join('.'), explained.release.join('.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const op = Operator[spec.operator];
|
||||
return op(version, spec.version || spec.legacy);
|
||||
}
|
||||
|
||||
function validRange(specifier) {
|
||||
return Boolean(parse(specifier));
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 99961:
|
||||
/***/ ((module) => {
|
||||
|
||||
const VERSION_PATTERN = [
|
||||
'v?',
|
||||
'(?:',
|
||||
/* */ '(?:(?<epoch>[0-9]+)!)?', // epoch
|
||||
/* */ '(?<release>[0-9]+(?:\\.[0-9]+)*)', // release segment
|
||||
/* */ '(?<pre>', // pre-release
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<pre_l>(a|b|c|rc|alpha|beta|pre|preview))',
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<pre_n>[0-9]+)?',
|
||||
/* */ ')?',
|
||||
/* */ '(?<post>', // post release
|
||||
/* */ '(?:-(?<post_n1>[0-9]+))',
|
||||
/* */ '|',
|
||||
/* */ '(?:',
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<post_l>post|rev|r)',
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<post_n2>[0-9]+)?',
|
||||
/* */ ')',
|
||||
/* */ ')?',
|
||||
/* */ '(?<dev>', // dev release
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<dev_l>dev)',
|
||||
/* */ '[-_\\.]?',
|
||||
/* */ '(?<dev_n>[0-9]+)?',
|
||||
/* */ ')?',
|
||||
')',
|
||||
'(?:\\+(?<local>[a-z0-9]+(?:[-_\\.][a-z0-9]+)*))?', // local version
|
||||
].join('');
|
||||
|
||||
module.exports = {
|
||||
VERSION_PATTERN,
|
||||
valid,
|
||||
clean,
|
||||
explain,
|
||||
parse,
|
||||
stringify,
|
||||
};
|
||||
|
||||
const validRegex = new RegExp('^' + VERSION_PATTERN + '$', 'i');
|
||||
|
||||
function valid(version) {
|
||||
return validRegex.test(version) ? version : null;
|
||||
}
|
||||
|
||||
const cleanRegex = new RegExp('^\\s*' + VERSION_PATTERN + '\\s*$', 'i');
|
||||
function clean(version) {
|
||||
return stringify(parse(version, cleanRegex));
|
||||
}
|
||||
|
||||
function parse(version, regex) {
|
||||
// Validate the version and parse it into pieces
|
||||
const { groups } = (regex || validRegex).exec(version) || {};
|
||||
if (!groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Store the parsed out pieces of the version
|
||||
const parsed = {
|
||||
epoch: Number(groups.epoch ? groups.epoch : 0),
|
||||
release: groups.release.split('.').map(Number),
|
||||
pre: normalize_letter_version(groups.pre_l, groups.pre_n),
|
||||
post: normalize_letter_version(
|
||||
groups.post_l,
|
||||
groups.post_n1 || groups.post_n2,
|
||||
),
|
||||
dev: normalize_letter_version(groups.dev_l, groups.dev_n),
|
||||
local: parse_local_version(groups.local),
|
||||
};
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function stringify(parsed) {
|
||||
if (!parsed) {
|
||||
return null;
|
||||
}
|
||||
const { epoch, release, pre, post, dev, local } = parsed;
|
||||
const parts = [];
|
||||
|
||||
// Epoch
|
||||
if (epoch !== 0) {
|
||||
parts.push(`${epoch}!`);
|
||||
}
|
||||
// Release segment
|
||||
parts.push(release.join('.'));
|
||||
|
||||
// Pre-release
|
||||
if (pre) {
|
||||
parts.push(pre.join(''));
|
||||
}
|
||||
// Post-release
|
||||
if (post) {
|
||||
parts.push('.' + post.join(''));
|
||||
}
|
||||
// Development release
|
||||
if (dev) {
|
||||
parts.push('.' + dev.join(''));
|
||||
}
|
||||
// Local version segment
|
||||
if (local) {
|
||||
parts.push(`+${local}`);
|
||||
}
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
function normalize_letter_version(letterIn, numberIn) {
|
||||
let letter = letterIn;
|
||||
let number = numberIn;
|
||||
if (letter) {
|
||||
// We consider there to be an implicit 0 in a pre-release if there is
|
||||
// not a numeral associated with it.
|
||||
if (!number) {
|
||||
number = 0;
|
||||
}
|
||||
// We normalize any letters to their lower case form
|
||||
letter = letter.toLowerCase();
|
||||
|
||||
// We consider some words to be alternate spellings of other words and
|
||||
// in those cases we want to normalize the spellings to our preferred
|
||||
// spelling.
|
||||
if (letter === 'alpha') {
|
||||
letter = 'a';
|
||||
} else if (letter === 'beta') {
|
||||
letter = 'b';
|
||||
} else if (['c', 'pre', 'preview'].includes(letter)) {
|
||||
letter = 'rc';
|
||||
} else if (['rev', 'r'].includes(letter)) {
|
||||
letter = 'post';
|
||||
}
|
||||
return [letter, Number(number)];
|
||||
}
|
||||
if (!letter && number) {
|
||||
// We assume if we are given a number, but we are not given a letter
|
||||
// then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||
letter = 'post';
|
||||
|
||||
return [letter, Number(number)];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parse_local_version(local) {
|
||||
/*
|
||||
Takes a string like abc.1.twelve and turns it into("abc", 1, "twelve").
|
||||
*/
|
||||
if (local) {
|
||||
return local
|
||||
.split(/[._-]/)
|
||||
.map((part) =>
|
||||
Number.isNaN(Number(part)) ? part.toLowerCase() : Number(part),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function explain(version) {
|
||||
const parsed = parse(version);
|
||||
if (!parsed) {
|
||||
return parsed;
|
||||
}
|
||||
const { epoch, release, pre, post, dev, local } = parsed;
|
||||
|
||||
let base_version = '';
|
||||
if (epoch !== 0) {
|
||||
base_version += epoch + '!';
|
||||
}
|
||||
base_version += release.join('.');
|
||||
|
||||
const is_prerelease = Boolean(dev || pre);
|
||||
const is_devrelease = Boolean(dev);
|
||||
const is_postrelease = Boolean(post);
|
||||
|
||||
// return
|
||||
|
||||
return {
|
||||
epoch,
|
||||
release,
|
||||
pre,
|
||||
post: post ? post[1] : post,
|
||||
dev: dev ? dev[1] : dev,
|
||||
local: local ? local.join('.') : local,
|
||||
public: stringify(parsed).split('+', 1)[0],
|
||||
base_version,
|
||||
is_prerelease,
|
||||
is_devrelease,
|
||||
is_postrelease,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 31324:
|
||||
|
@ -123171,6 +123948,7 @@ exports.resolveVersion = resolveVersion;
|
|||
const core = __importStar(__nccwpck_require__(37484));
|
||||
const tc = __importStar(__nccwpck_require__(33472));
|
||||
const path = __importStar(__nccwpck_require__(76760));
|
||||
const pep440 = __importStar(__nccwpck_require__(63297));
|
||||
const node_fs_1 = __nccwpck_require__(73024);
|
||||
const constants_1 = __nccwpck_require__(56156);
|
||||
const checksum_1 = __nccwpck_require__(95391);
|
||||
|
@ -123222,8 +124000,8 @@ async function resolveVersion(versionInput, githubToken) {
|
|||
}
|
||||
const availableVersions = await getAvailableVersions(githubToken);
|
||||
core.debug(`Available versions: ${availableVersions}`);
|
||||
const resolvedVersion = tc.evaluateVersions(availableVersions, version);
|
||||
if (resolvedVersion === "") {
|
||||
const resolvedVersion = maxSatisfying(availableVersions, version);
|
||||
if (resolvedVersion === undefined) {
|
||||
throw new Error(`No version found for ${version}`);
|
||||
}
|
||||
return resolvedVersion;
|
||||
|
@ -123281,6 +124059,19 @@ async function getLatestRelease(octokit) {
|
|||
});
|
||||
return latestRelease;
|
||||
}
|
||||
function maxSatisfying(versions, version) {
|
||||
const maxSemver = tc.evaluateVersions(versions, version);
|
||||
if (maxSemver !== "") {
|
||||
core.debug(`Found a version that satisfies the semver range: ${maxSemver}`);
|
||||
return maxSemver;
|
||||
}
|
||||
const maxPep440 = pep440.maxSatisfying(versions, version);
|
||||
if (maxPep440 !== null) {
|
||||
core.debug(`Found a version that satisfies the pep440 specifier: ${maxPep440}`);
|
||||
return maxPep440;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
|
16
package-lock.json
generated
16
package-lock.json
generated
|
@ -18,6 +18,7 @@
|
|||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.3",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.1",
|
||||
"@renovatebot/pep440": "^4.1.0",
|
||||
"smol-toml": "^1.3.1",
|
||||
"undici": "^7.5.0"
|
||||
},
|
||||
|
@ -1705,6 +1706,16 @@
|
|||
"@protobuf-ts/runtime": "^2.9.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@renovatebot/pep440": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@renovatebot/pep440/-/pep440-4.1.0.tgz",
|
||||
"integrity": "sha512-mo2RxnOSp78Njt1HmgMwjl6FapP4OyIS8HypJlymCvN7AIV2Xf5PmZfl/E3O1WWZ6IjKrfsEAaPWFMi8tnkq3g==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^20.9.0 || ^22.11.0",
|
||||
"pnpm": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
|
@ -5933,6 +5944,11 @@
|
|||
"@protobuf-ts/runtime": "^2.9.4"
|
||||
}
|
||||
},
|
||||
"@renovatebot/pep440": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@renovatebot/pep440/-/pep440-4.1.0.tgz",
|
||||
"integrity": "sha512-mo2RxnOSp78Njt1HmgMwjl6FapP4OyIS8HypJlymCvN7AIV2Xf5PmZfl/E3O1WWZ6IjKrfsEAaPWFMi8tnkq3g=="
|
||||
},
|
||||
"@sinclair/typebox": {
|
||||
"version": "0.27.8",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
|
||||
|
|
|
@ -32,8 +32,9 @@
|
|||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.3",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.1",
|
||||
"undici": "^7.5.0",
|
||||
"smol-toml": "^1.3.1"
|
||||
"@renovatebot/pep440": "^4.1.0",
|
||||
"smol-toml": "^1.3.1",
|
||||
"undici": "^7.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as core from "@actions/core";
|
||||
import * as tc from "@actions/tool-cache";
|
||||
import * as path from "node:path";
|
||||
import * as pep440 from "@renovatebot/pep440";
|
||||
import { promises as fs } from "node:fs";
|
||||
import { OWNER, REPO, TOOL_CACHE_NAME } from "../utils/constants";
|
||||
import type { Architecture, Platform } from "../utils/platforms";
|
||||
|
@ -85,8 +86,8 @@ export async function resolveVersion(
|
|||
}
|
||||
const availableVersions = await getAvailableVersions(githubToken);
|
||||
core.debug(`Available versions: ${availableVersions}`);
|
||||
const resolvedVersion = tc.evaluateVersions(availableVersions, version);
|
||||
if (resolvedVersion === "") {
|
||||
const resolvedVersion = maxSatisfying(availableVersions, version);
|
||||
if (resolvedVersion === undefined) {
|
||||
throw new Error(`No version found for ${version}`);
|
||||
}
|
||||
return resolvedVersion;
|
||||
|
@ -154,3 +155,22 @@ async function getLatestRelease(octokit: InstanceType<typeof Octokit>) {
|
|||
});
|
||||
return latestRelease;
|
||||
}
|
||||
|
||||
function maxSatisfying(
|
||||
versions: string[],
|
||||
version: string,
|
||||
): string | undefined {
|
||||
const maxSemver = tc.evaluateVersions(versions, version);
|
||||
if (maxSemver !== "") {
|
||||
core.debug(`Found a version that satisfies the semver range: ${maxSemver}`);
|
||||
return maxSemver;
|
||||
}
|
||||
const maxPep440 = pep440.maxSatisfying(versions, version);
|
||||
if (maxPep440 !== null) {
|
||||
core.debug(
|
||||
`Found a version that satisfies the pep440 specifier: ${maxPep440}`,
|
||||
);
|
||||
return maxPep440;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue