From 8156cbeb2aec96679fea058d3daebfed9ecf3229 Mon Sep 17 00:00:00 2001 From: mayeut Date: Sat, 4 Jun 2022 17:06:17 +0200 Subject: [PATCH] feature: fallback to pre-release when no stable version is found This allows to specify version like `3.11` or `pypy3.10` in workflows before those versions are released. This lessen the burden for users of `setup-python` by not having to modify their workflow twice: once when a pre-release is available (e.g. `3.11-dev`) and once when the first stable release is published (e.g. `3.11`) --- __tests__/data/pypy.json | 86 ++++++++++++++++++++- __tests__/data/versions-manifest.json | 43 ++++++++--- __tests__/find-pypy.test.ts | 15 ++++ __tests__/finder.test.ts | 67 +++++++++++++++- __tests__/install-pypy.test.ts | 107 ++++++++++++++++++++++++-- dist/setup/index.js | 25 ++++-- src/find-pypy.ts | 3 +- src/find-python.ts | 7 +- src/install-pypy.ts | 33 +++++++- 9 files changed, 354 insertions(+), 32 deletions(-) diff --git a/__tests__/data/pypy.json b/__tests__/data/pypy.json index c8889a3b5..66d153e07 100644 --- a/__tests__/data/pypy.json +++ b/__tests__/data/pypy.json @@ -1,4 +1,88 @@ [ + { + "pypy_version": "7.3.8rc2", + "python_version": "3.8.12", + "stable": false, + "latest_pypy": false, + "date": "2022-02-11", + "files": [ + { + "filename": "pypy3.8-v7.3.8rc2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux32.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.8rc2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux64.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.8rc2-darwin64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-darwin64.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.8rc2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-s390x.tar.bz2" + }, + { + "filename": "pypy3.8-v7.3.8rc2-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win64.zip" + } + ] + }, + { + "pypy_version": "7.4.0rc1", + "python_version": "3.6.12", + "stable": false, + "latest_pypy": false, + "date": "2021-11-11", + "files": [ + { + "filename": "pypy3.6-v7.4.0rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.4.0rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux32.tar.bz2" + }, + { + "filename": "pypy3.6-v7.4.0rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.4.0rc1-darwin64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-darwin64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.4.0rc1-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-win32.zip" + }, + { + "filename": "pypy3.6-v7.4.0rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-s390x.tar.bz2" + } + ] + }, { "pypy_version": "7.3.3", "python_version": "3.6.12", @@ -530,4 +614,4 @@ } ] } -] \ No newline at end of file +] diff --git a/__tests__/data/versions-manifest.json b/__tests__/data/versions-manifest.json index 2d23f98e3..083160f50 100644 --- a/__tests__/data/versions-manifest.json +++ b/__tests__/data/versions-manifest.json @@ -1,4 +1,29 @@ [ + { + "version": "1.2.4-beta.2", + "stable": false, + "release_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5", + "files": [ + { + "filename": "sometool-1.2.4-linux-x64.tar.gz", + "arch": "x64", + "platform": "linux", + "download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-linux-x64.tar.gz" + }, + { + "filename": "sometool-1.2.4-darwin-x64.tar.gz", + "arch": "x64", + "platform": "darwin", + "download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-darwin-x64.tar.gz" + }, + { + "filename": "sometool-1.2.4-win32-x64.tar.gz", + "arch": "x64", + "platform": "win32", + "download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-win32-x64.tar.gz" + } + ] + }, { "version": "1.2.3", "stable": true, @@ -25,28 +50,28 @@ ] }, { - "version": "1.2.3-beta.2", + "version": "1.1.0-beta.2", "stable": false, - "release_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5", + "release_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5", "files": [ { - "filename": "sometool-1.2.3-linux-x64.tar.gz", + "filename": "sometool-1.1.0-linux-x64.tar.gz", "arch": "x64", "platform": "linux", - "download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5/sometool-1.2.3-linux-x64.tar.gz" + "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-linux-x64.tar.gz" }, { - "filename": "sometool-1.2.3-darwin-x64.tar.gz", + "filename": "sometool-1.1.0-darwin-x64.tar.gz", "arch": "x64", "platform": "darwin", - "download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-darwin-x64.tar.gz" + "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-darwin-x64.tar.gz" }, { - "filename": "sometool-1.2.3-win32-x64.tar.gz", + "filename": "sometool-1.1.0-win32-x64.tar.gz", "arch": "x64", "platform": "win32", - "download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-win32-x64.tar.gz" + "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-win32-x64.tar.gz" } ] } -] \ No newline at end of file +] diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts index 660f23d30..1975e75cb 100644 --- a/__tests__/find-pypy.test.ts +++ b/__tests__/find-pypy.test.ts @@ -401,4 +401,19 @@ describe('findPyPyVersion', () => { 'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest' ); }); + + it('found and install successfully, pre-release fallback', async () => { + spyCacheDir = jest.spyOn(tc, 'cacheDir'); + spyCacheDir.mockImplementation(() => + path.join(toolDir, 'PyPy', '3.8.12', architecture) + ); + spyChmodSync = jest.spyOn(fs, 'chmodSync'); + spyChmodSync.mockImplementation(() => undefined); + await expect( + finder.findPyPyVersion('pypy3.8', architecture, false, false) + ).resolves.toEqual({ + resolvedPythonVersion: '3.8.12', + resolvedPyPyVersion: '7.3.8rc2' + }); + }); }); diff --git a/__tests__/finder.test.ts b/__tests__/finder.test.ts index d2fe775b9..b56c9619e 100644 --- a/__tests__/finder.test.ts +++ b/__tests__/finder.test.ts @@ -95,7 +95,12 @@ describe('Finder tests', () => { fs.writeFileSync(`${pythonDir}.complete`, 'hello'); }); // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists) - await finder.useCpythonVersion('1.2.3', 'x64', true, false); + await expect( + finder.useCpythonVersion('1.2.3', 'x64', true, false) + ).resolves.toEqual({ + impl: 'CPython', + version: '1.2.3' + }); expect(spyCoreAddPath).toHaveBeenCalled(); expect(spyCoreExportVariable).toHaveBeenCalledWith( 'pythonLocation', @@ -122,14 +127,19 @@ describe('Finder tests', () => { const pythonDir: string = path.join( toolDir, 'Python', - '1.2.3-beta.2', + '1.2.4-beta.2', 'x64' ); await io.mkdirP(pythonDir); fs.writeFileSync(`${pythonDir}.complete`, 'hello'); }); // This will throw if it doesn't find it in the manifest (because no such version exists) - await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, false); + await expect( + finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, false) + ).resolves.toEqual({ + impl: 'CPython', + version: '1.2.4-beta.2' + }); }); it('Check-latest true, finds the latest version in the manifest', async () => { @@ -187,7 +197,7 @@ describe('Finder tests', () => { ); expect(installSpy).toHaveBeenCalled(); expect(addPathSpy).toHaveBeenCalledWith(expPath); - await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, true); + await finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, true); expect(spyCoreAddPath).toHaveBeenCalled(); expect(spyCoreExportVariable).toHaveBeenCalledWith( 'pythonLocation', @@ -199,6 +209,55 @@ describe('Finder tests', () => { ); }); + it('Finds stable Python version if it is not installed, but exists in the manifest, skipping newer pre-release', async () => { + const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo'); + findSpy.mockImplementation(() => manifestData); + + const installSpy: jest.SpyInstance = jest.spyOn( + installer, + 'installCpythonFromRelease' + ); + installSpy.mockImplementation(async () => { + const pythonDir: string = path.join(toolDir, 'Python', '1.2.3', 'x64'); + await io.mkdirP(pythonDir); + fs.writeFileSync(`${pythonDir}.complete`, 'hello'); + }); + // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists) + await expect( + finder.useCpythonVersion('1.2', 'x64', false, false) + ).resolves.toEqual({ + impl: 'CPython', + version: '1.2.3' + }); + }); + + it('Finds Python version if it is not installed, but exists in the manifest, pre-release fallback', async () => { + const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo'); + findSpy.mockImplementation(() => manifestData); + + const installSpy: jest.SpyInstance = jest.spyOn( + installer, + 'installCpythonFromRelease' + ); + installSpy.mockImplementation(async () => { + const pythonDir: string = path.join( + toolDir, + 'Python', + '1.1.0-beta.2', + 'x64' + ); + await io.mkdirP(pythonDir); + fs.writeFileSync(`${pythonDir}.complete`, 'hello'); + }); + // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists) + await expect( + finder.useCpythonVersion('1.1', 'x64', false, false) + ).resolves.toEqual({ + impl: 'CPython', + version: '1.1.0-beta.2' + }); + }); + it('Errors if Python is not installed', async () => { // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists) let thrown = false; diff --git a/__tests__/install-pypy.test.ts b/__tests__/install-pypy.test.ts index ae7fb4a66..43d27bf78 100644 --- a/__tests__/install-pypy.test.ts +++ b/__tests__/install-pypy.test.ts @@ -51,6 +51,12 @@ describe('findRelease', () => { platform: process.platform, download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}` }; + const filesRC1: IPyPyManifestAsset = { + filename: `pypy3.6-v7.4.0rc1-${extensionName}`, + arch: architecture, + platform: process.platform, + download_url: `https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-${extensionName}` + }; let getBooleanInputSpy: jest.SpyInstance; let warningSpy: jest.SpyInstance; @@ -72,7 +78,13 @@ describe('findRelease', () => { const pythonVersion = '3.6'; const pypyVersion = '7.3.7'; expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual(null); }); @@ -80,7 +92,13 @@ describe('findRelease', () => { const pythonVersion = '3.6'; const pypyVersion = '7.3.3'; expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual({ foundAsset: files, resolvedPythonVersion: '3.6.12', @@ -92,7 +110,13 @@ describe('findRelease', () => { const pythonVersion = '3.6'; const pypyVersion = '7.x'; expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual({ foundAsset: files, resolvedPythonVersion: '3.6.12', @@ -104,7 +128,13 @@ describe('findRelease', () => { const pythonVersion = '3.7'; const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2'); expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual({ foundAsset: { filename: `test${extension}`, @@ -121,7 +151,13 @@ describe('findRelease', () => { const pythonVersion = '3.6'; const pypyVersion = 'x'; expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual({ foundAsset: files, resolvedPythonVersion: '3.6.12', @@ -129,12 +165,45 @@ describe('findRelease', () => { }); }); + it('Python version and PyPy version matches semver (pre-release)', () => { + const pythonVersion = '3.6'; + const pypyVersion = '7.4.x'; + expect( + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) + ).toBeNull(); + expect( + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + true + ) + ).toEqual({ + foundAsset: filesRC1, + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.4.0rc1' + }); + }); + it('Nightly release is found', () => { const pythonVersion = '3.6'; const pypyVersion = 'nightly'; const filename = IS_WINDOWS ? 'filename.zip' : 'filename.tar.bz2'; expect( - installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + installer.findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + false + ) ).toEqual({ foundAsset: { filename: filename, @@ -244,7 +313,7 @@ describe('installPyPy', () => { spyChmodSync.mockImplementation(() => undefined); await expect( - installer.installPyPy('7.3.x', '3.6.12', architecture, undefined) + installer.installPyPy('7.x', '3.6.12', architecture, undefined) ).resolves.toEqual({ installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture), resolvedPythonVersion: '3.6.12', @@ -257,4 +326,28 @@ describe('installPyPy', () => { expect(spyCacheDir).toHaveBeenCalled(); expect(spyExec).toHaveBeenCalled(); }); + + it('found and install PyPy, pre-release fallback', async () => { + spyCacheDir = jest.spyOn(tc, 'cacheDir'); + spyCacheDir.mockImplementation(() => + path.join(toolDir, 'PyPy', '3.6.12', architecture) + ); + + spyChmodSync = jest.spyOn(fs, 'chmodSync'); + spyChmodSync.mockImplementation(() => undefined); + + await expect( + installer.installPyPy('7.4.x', '3.6.12', architecture, undefined) + ).resolves.toEqual({ + installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture), + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.4.0rc1' + }); + + expect(spyHttpClient).toHaveBeenCalled(); + expect(spyDownloadTool).toHaveBeenCalled(); + expect(spyExistsSync).toHaveBeenCalled(); + expect(spyCacheDir).toHaveBeenCalled(); + expect(spyExec).toHaveBeenCalled(); + }); }); diff --git a/dist/setup/index.js b/dist/setup/index.js index 0ae650d04..5cb3cd6f1 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -64695,7 +64695,7 @@ function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLate if (checkLatest) { releases = yield pypyInstall.getAvailablePyPyVersions(); if (releases && releases.length > 0) { - const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture); + const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture, false); if (releaseData) { core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`); pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion; @@ -64955,10 +64955,15 @@ function versionFromPath(installDir) { * Python's prelease versions look like `3.7.0b2`. * This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`. * If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent. + * + * For easier use of the action, we also map 'x.y' to allow pre-release before 'x.y.0' release */ function pythonVersionToSemantic(versionSpec) { const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g; - return versionSpec.replace(prereleaseVersion, '$1-$2'); + const majorMinor = /^(\d+)\.(\d+)$/; + return versionSpec + .replace(prereleaseVersion, '$1-$2') + .replace(majorMinor, '~$1.$2.0-0'); } exports.pythonVersionToSemantic = pythonVersionToSemantic; @@ -65003,6 +65008,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = exports.getAvailablePyPyVersions = exports.installPyPy = void 0; +const os = __importStar(__nccwpck_require__(2037)); const path = __importStar(__nccwpck_require__(1017)); const core = __importStar(__nccwpck_require__(2186)); const tc = __importStar(__nccwpck_require__(7784)); @@ -65018,7 +65024,15 @@ function installPyPy(pypyVersion, pythonVersion, architecture, releases) { if (!releases || releases.length === 0) { throw new Error('No release was found in PyPy version.json'); } - const releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture); + let releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture, false); + if (!releaseData || !releaseData.foundAsset) { + // check for pre-release + core.info([ + `Stable PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`, + `Trying pre-release versions` + ].join(os.EOL)); + releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture, true); + } if (!releaseData || !releaseData.foundAsset) { throw new Error(`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`); } @@ -65083,12 +65097,13 @@ function installPip(pythonLocation) { yield exec.exec(`${pythonLocation}/python -m pip install --ignore-installed pip`); }); } -function findRelease(releases, pythonVersion, pypyVersion, architecture) { +function findRelease(releases, pythonVersion, pypyVersion, architecture, includePrerelease) { + const options = { includePrerelease: includePrerelease }; const filterReleases = releases.filter(item => { const isPythonVersionSatisfied = semver.satisfies(semver.coerce(item.python_version), pythonVersion); const isPyPyNightly = utils_1.isNightlyKeyword(pypyVersion) && utils_1.isNightlyKeyword(item.pypy_version); const isPyPyVersionSatisfied = isPyPyNightly || - semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); + semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion, options); const isArchPresent = item.files && (utils_1.IS_WINDOWS ? isArchPresentForWindows(item) diff --git a/src/find-pypy.ts b/src/find-pypy.ts index 20b9821e1..657299282 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -39,7 +39,8 @@ export async function findPyPyVersion( releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, - architecture + architecture, + false ); if (releaseData) { diff --git a/src/find-python.ts b/src/find-python.ts index 4e54a94b6..432dc77f3 100644 --- a/src/find-python.ts +++ b/src/find-python.ts @@ -173,8 +173,13 @@ interface InstalledVersion { * Python's prelease versions look like `3.7.0b2`. * This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`. * If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent. + * + * For easier use of the action, we also map 'x.y' to allow pre-release before 'x.y.0' release */ export function pythonVersionToSemantic(versionSpec: string) { const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g; - return versionSpec.replace(prereleaseVersion, '$1-$2'); + const majorMinor = /^(\d+)\.(\d+)$/; + return versionSpec + .replace(prereleaseVersion, '$1-$2') + .replace(majorMinor, '~$1.$2.0-0'); } diff --git a/src/install-pypy.ts b/src/install-pypy.ts index 4c49e1150..3256f1235 100644 --- a/src/install-pypy.ts +++ b/src/install-pypy.ts @@ -1,3 +1,4 @@ +import * as os from 'os'; import * as path from 'path'; import * as core from '@actions/core'; import * as tc from '@actions/tool-cache'; @@ -30,13 +31,31 @@ export async function installPyPy( throw new Error('No release was found in PyPy version.json'); } - const releaseData = findRelease( + let releaseData = findRelease( releases, pythonVersion, pypyVersion, - architecture + architecture, + false ); + if (!releaseData || !releaseData.foundAsset) { + // check for pre-release + core.info( + [ + `Stable PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`, + `Trying pre-release versions` + ].join(os.EOL) + ); + releaseData = findRelease( + releases, + pythonVersion, + pypyVersion, + architecture, + true + ); + } + if (!releaseData || !releaseData.foundAsset) { throw new Error( `PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found` @@ -142,8 +161,10 @@ export function findRelease( releases: IPyPyManifestRelease[], pythonVersion: string, pypyVersion: string, - architecture: string + architecture: string, + includePrerelease: boolean ) { + const options = {includePrerelease: includePrerelease}; const filterReleases = releases.filter(item => { const isPythonVersionSatisfied = semver.satisfies( semver.coerce(item.python_version)!, @@ -153,7 +174,11 @@ export function findRelease( isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version); const isPyPyVersionSatisfied = isPyPyNightly || - semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); + semver.satisfies( + pypyVersionToSemantic(item.pypy_version), + pypyVersion, + options + ); const isArchPresent = item.files && (IS_WINDOWS