diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts index b9c6599f..ddf7ebcf 100644 --- a/__tests__/find-pypy.test.ts +++ b/__tests__/find-pypy.test.ts @@ -49,23 +49,6 @@ describe('parsePyPyVersion', () => { }); }); -describe('validateVersion', () => { - it.each([ - ['v7.3.3', true], - ['v7.3.x', true], - ['v7.x', true], - ['x', true], - ['v7.3.3-rc.1', true], - ['nightly', true], - ['v7.3.b', false], - ['3.6', true], - ['3.b', false], - ['3', true] - ])('%s -> %s', (input, expected) => { - expect(validateVersion(input)).toEqual(expected); - }); -}); - describe('getPyPyVersionFromPath', () => { it('/fake/toolcache/PyPy/3.6.5/x64 -> 3.6.5', () => { expect(getPyPyVersionFromPath('/fake/toolcache/PyPy/3.6.5/x64')).toEqual( @@ -223,6 +206,12 @@ describe('findPyPyVersion', () => { ).rejects.toThrow(); }); + it('throw on invalid input format pypy3.7-7.3.x', async () => { + await expect( + finder.findPyPyVersion('pypy3.7-v7.3.x', architecture) + ).rejects.toThrow(); + }); + it('found and install successfully', async () => { spyCacheDir = jest.spyOn(tc, 'cacheDir'); spyCacheDir.mockImplementation(() => @@ -240,9 +229,9 @@ describe('findPyPyVersion', () => { it('throw if release is not found', async () => { await expect( - finder.findPyPyVersion('pypy3.7-v7.3.x', architecture) + finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture) ).rejects.toThrowError( - "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-'. See README for examples and documentation." + `PyPy version 3.7 (v7.5.x) with arch ${architecture} not found` ); }); }); diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts new file mode 100644 index 00000000..9463849f --- /dev/null +++ b/__tests__/utils.test.ts @@ -0,0 +1,34 @@ +import { + validateVersion, + validatePythonVersionFormatForPyPy +} from '../src/utils'; + +describe('validatePythonVersionFormatForPyPy', () => { + it.each([ + ['3.6', true], + ['3.7', true], + ['3.6.x', false], + ['3.7.x', false], + ['3.x', false], + ['3', false] + ])('%s -> %s', (input, expected) => { + expect(validatePythonVersionFormatForPyPy(input)).toEqual(expected); + }); +}); + +describe('validateVersion', () => { + it.each([ + ['v7.3.3', true], + ['v7.3.x', true], + ['v7.x', true], + ['x', true], + ['v7.3.3-rc.1', true], + ['nightly', true], + ['v7.3.b', false], + ['3.6', true], + ['3.b', false], + ['3', true] + ])('%s -> %s', (input, expected) => { + expect(validateVersion(input)).toEqual(expected); + }); +}); diff --git a/dist/index.js b/dist/index.js index 4992e541..3fe97152 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1168,6 +1168,9 @@ function parsePyPyVersion(versionSpec) { if (!utils_1.validateVersion(pythonVersion) || !utils_1.validateVersion(pypyVersion)) { throw new Error("Invalid 'version' property for PyPy. Both Python version and PyPy versions should satisfy SemVer notation. See README for examples and documentation."); } + if (!utils_1.validatePythonVersionFormatForPyPy(pythonVersion)) { + throw new Error("Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation."); + } return { pypyVersion: pypyVersion, pythonVersion: pythonVersion @@ -2375,6 +2378,16 @@ function writeExactPyPyVersionFile(installDir, resolvedPyPyVersion) { fs_1.default.writeFileSync(pypyFilePath, resolvedPyPyVersion); } exports.writeExactPyPyVersionFile = writeExactPyPyVersionFile; +/** + * Python version should be specified explicitly like "x.y" (2.7, 3.6, 3.7) + * "3.x" or "3" are not supported + * because it could cause ambiguity when both PyPy version and Python version are not precise + */ +function validatePythonVersionFormatForPyPy(version) { + const re = /^\d+\.\d+$/; + return re.test(version); +} +exports.validatePythonVersionFormatForPyPy = validatePythonVersionFormatForPyPy; /***/ }), diff --git a/src/find-pypy.ts b/src/find-pypy.ts index b45f48f8..700ce9ee 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -4,7 +4,8 @@ import { IS_WINDOWS, validateVersion, getPyPyVersionFromPath, - readExactPyPyVersionFile + readExactPyPyVersionFile, + validatePythonVersionFormatForPyPy } from './utils'; import * as semver from 'semver'; @@ -117,6 +118,12 @@ export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec { ); } + if (!validatePythonVersionFormatForPyPy(pythonVersion)) { + throw new Error( + "Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation." + ); + } + return { pypyVersion: pypyVersion, pythonVersion: pythonVersion diff --git a/src/utils.ts b/src/utils.ts index 845fe097..e96d5b23 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -80,3 +80,13 @@ export function writeExactPyPyVersionFile( const pypyFilePath = path.join(installDir, PYPY_VERSION_FILE); fs.writeFileSync(pypyFilePath, resolvedPyPyVersion); } + +/** + * Python version should be specified explicitly like "x.y" (2.7, 3.6, 3.7) + * "3.x" or "3" are not supported + * because it could cause ambiguity when both PyPy version and Python version are not precise + */ +export function validatePythonVersionFormatForPyPy(version: string) { + const re = /^\d+\.\d+$/; + return re.test(version); +}