diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f12088901..d26264db1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,6 +2,7 @@ name: "Code scanning - action" on: push: + pull_request: schedule: - cron: '25 3 * * 5' diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index 4041440d4..547d03419 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] + os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] pypy: - 'pypy-2.7' - 'pypy-3.6' @@ -28,7 +28,7 @@ jobs: - 'pypy-3.7-v7.3.2' - 'pypy-3.6-v7.3.x' - 'pypy-3.7-v7.x' - - 'pypy-3.6-v7.3.3rc1' + - 'pypy-2.7-v7.3.4rc1' - 'pypy-3.7-nightly' steps: diff --git a/README.md b/README.md index d1fb79e97..461ee2ea6 100644 --- a/README.md +++ b/README.md @@ -61,12 +61,12 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [2.7, 3.6, 3.7, 3.8, pypy-2.7, pypy-3.6] + python-version: ['2.7', '3.6', '3.7', '3.8', 'pypy-2.7', 'pypy-3.6'] exclude: - os: macos-latest - python-version: 3.8 + python-version: '3.8' - os: windows-latest - python-version: 3.6 + python-version: '3.6' steps: - uses: actions/checkout@v2 - name: Set up Python @@ -85,7 +85,7 @@ jobs: strategy: matrix: # in this example, there is a newer version already installed, 3.7.7, so the older version will be downloaded - python-version: [3.5, 3.6, 3.7.4, 3.8] + python-version: ['3.5', '3.6', '3.7.4', '3.8'] steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -114,7 +114,7 @@ steps: - run: python my_script.py ``` -Download and set up PyPy: +Download and set up PyPy: ```yaml jobs: @@ -123,9 +123,9 @@ jobs: strategy: matrix: python-version: - - pypy-3.6 # the latest available version of PyPy that supports Python 3.6 - - pypy-3.7 # the latest available version of PyPy that supports Python 3.7 - - pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 + - 'pypy-3.6' # the latest available version of PyPy that supports Python 3.6 + - 'pypy-3.7' # the latest available version of PyPy that supports Python 3.7 + - 'pypy-3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -151,11 +151,11 @@ Check out our detailed guide on using [Python with GitHub Actions](https://help. - Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)). - All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file. - If there is a specific version of Python that is not available, you can open an issue here - + # Available versions of PyPy - + `setup-python` is able to configure PyPy from two sources: - + - Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners - For detailed information regarding the available versions of PyPy that are installed see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software). - For the latest PyPy release, all versions of Python are cached. @@ -190,9 +190,9 @@ You should specify only a major and minor version if you are okay with the most - There will be a single patch version already installed on each runner for every minor version of Python that is supported. - The patch version that will be preinstalled, will generally be the latest and every time there is a new patch released, the older version that is preinstalled will be replaced. - Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used. - + # Specifying a PyPy version -The version of PyPy should be specified in the format `pypy-[-v]`. +The version of PyPy should be specified in the format `pypy-[-v]`. The `` parameter is optional and can be skipped. The latest version will be used in this case. ``` diff --git a/__tests__/data/pypy.json b/__tests__/data/pypy.json index 95e06bbb1..c8889a3b5 100644 --- a/__tests__/data/pypy.json +++ b/__tests__/data/pypy.json @@ -89,6 +89,45 @@ } ] }, + { + "pypy_version": "7.3.4rc1", + "python_version": "2.7.18", + "stable": false, + "latest_pypy": false, + "date": "2021-03-19", + "files": [ + { + "filename": "pypy2.7-v7.3.4rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.4rc1-win64.zip", + "arch": "x64", + "platform": "win64", + "download_url": "https://test.downloads.python.org/pypy/pypy2.7-v7.3.4rc1-win64.zip" + } + ] + }, { "pypy_version": "7.3.3rc2", "python_version": "3.7.7", diff --git a/dist/index.js b/dist/index.js index f0939428b..16cab2276 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1108,10 +1108,6 @@ function findPyPyVersion(versionSpec, architecture) { let resolvedPythonVersion = ''; let installDir; const pypyVersionSpec = parsePyPyVersion(versionSpec); - // PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64. - if (utils_1.IS_WINDOWS && architecture === 'x64') { - architecture = 'x86'; - } ({ installDir, resolvedPythonVersion, resolvedPyPyVersion } = findPyPyToolCache(pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture)); if (!installDir) { ({ @@ -1133,7 +1129,9 @@ exports.findPyPyVersion = findPyPyVersion; function findPyPyToolCache(pythonVersion, pypyVersion, architecture) { let resolvedPyPyVersion = ''; let resolvedPythonVersion = ''; - let installDir = tc.find('PyPy', pythonVersion, architecture); + let installDir = utils_1.IS_WINDOWS + ? findPyPyInstallDirForWindows(pythonVersion) + : tc.find('PyPy', pythonVersion, architecture); if (installDir) { // 'tc.find' finds tool based on Python version but we also need to check // whether PyPy version satisfies requested version. @@ -1177,6 +1175,12 @@ function parsePyPyVersion(versionSpec) { }; } exports.parsePyPyVersion = parsePyPyVersion; +function findPyPyInstallDirForWindows(pythonVersion) { + let installDir = ''; + utils_1.WINDOWS_ARCHS.forEach(architecture => (installDir = installDir || tc.find('PyPy', pythonVersion, architecture))); + return installDir; +} +exports.findPyPyInstallDirForWindows = findPyPyInstallDirForWindows; /***/ }), @@ -2327,6 +2331,8 @@ const path = __importStar(__webpack_require__(622)); const semver = __importStar(__webpack_require__(876)); exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_LINUX = process.platform === 'linux'; +exports.WINDOWS_ARCHS = ['x86', 'x64']; +exports.WINDOWS_PLATFORMS = ['win32', 'win64']; const PYPY_VERSION_FILE = 'PYPY_VERSION'; /** create Symlinks for downloaded PyPy * It should be executed only for downloaded versions in runtime, because @@ -2893,7 +2899,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) { const isPyPyVersionSatisfied = isPyPyNightly || semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); const isArchPresent = item.files && - item.files.some(file => file.arch === architecture && file.platform === process.platform); + (utils_1.IS_WINDOWS + ? isArchPresentForWindows(item) + : isArchPresentForMacOrLinux(item, architecture, process.platform)); return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent; }); if (filterReleases.length === 0) { @@ -2904,7 +2912,9 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) { semver.compare(semver.coerce(current.python_version), semver.coerce(previous.python_version))); }); const foundRelease = sortedReleases[0]; - const foundAsset = foundRelease.files.find(item => item.arch === architecture && item.platform === process.platform); + const foundAsset = utils_1.IS_WINDOWS + ? findAssetForWindows(foundRelease) + : findAssetForMacOrLinux(foundRelease, architecture, process.platform); return { foundAsset, resolvedPythonVersion: foundRelease.python_version, @@ -2926,6 +2936,24 @@ function pypyVersionToSemantic(versionSpec) { return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); } exports.pypyVersionToSemantic = pypyVersionToSemantic; +function isArchPresentForWindows(item) { + return item.files.some((file) => utils_1.WINDOWS_ARCHS.includes(file.arch) && + utils_1.WINDOWS_PLATFORMS.includes(file.platform)); +} +exports.isArchPresentForWindows = isArchPresentForWindows; +function isArchPresentForMacOrLinux(item, architecture, platform) { + return item.files.some((file) => file.arch === architecture && file.platform === platform); +} +exports.isArchPresentForMacOrLinux = isArchPresentForMacOrLinux; +function findAssetForWindows(releases) { + return releases.files.find((item) => utils_1.WINDOWS_ARCHS.includes(item.arch) && + utils_1.WINDOWS_PLATFORMS.includes(item.platform)); +} +exports.findAssetForWindows = findAssetForWindows; +function findAssetForMacOrLinux(releases, architecture, platform) { + return releases.files.find((item) => item.arch === architecture && item.platform === platform); +} +exports.findAssetForMacOrLinux = findAssetForMacOrLinux; /***/ }), diff --git a/src/find-pypy.ts b/src/find-pypy.ts index 700ce9ee5..eb8dfac65 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import * as pypyInstall from './install-pypy'; import { IS_WINDOWS, + WINDOWS_ARCHS, validateVersion, getPyPyVersionFromPath, readExactPyPyVersionFile, @@ -27,11 +28,6 @@ export async function findPyPyVersion( const pypyVersionSpec = parsePyPyVersion(versionSpec); - // PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64. - if (IS_WINDOWS && architecture === 'x64') { - architecture = 'x86'; - } - ({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache( pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, @@ -67,7 +63,9 @@ export function findPyPyToolCache( ) { let resolvedPyPyVersion = ''; let resolvedPythonVersion = ''; - let installDir: string | null = tc.find('PyPy', pythonVersion, architecture); + let installDir: string | null = IS_WINDOWS + ? findPyPyInstallDirForWindows(pythonVersion) + : tc.find('PyPy', pythonVersion, architecture); if (installDir) { // 'tc.find' finds tool based on Python version but we also need to check @@ -129,3 +127,14 @@ export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec { pythonVersion: pythonVersion }; } + +export function findPyPyInstallDirForWindows(pythonVersion: string): string { + let installDir = ''; + + WINDOWS_ARCHS.forEach( + architecture => + (installDir = installDir || tc.find('PyPy', pythonVersion, architecture)) + ); + + return installDir; +} diff --git a/src/install-pypy.ts b/src/install-pypy.ts index 99d603000..402525ab3 100644 --- a/src/install-pypy.ts +++ b/src/install-pypy.ts @@ -8,6 +8,8 @@ import fs from 'fs'; import { IS_WINDOWS, + WINDOWS_ARCHS, + WINDOWS_PLATFORMS, IPyPyManifestRelease, createSymlinkInFolder, isNightlyKeyword, @@ -143,9 +145,9 @@ export function findRelease( semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); const isArchPresent = item.files && - item.files.some( - file => file.arch === architecture && file.platform === process.platform - ); + (IS_WINDOWS + ? isArchPresentForWindows(item) + : isArchPresentForMacOrLinux(item, architecture, process.platform)); return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent; }); @@ -167,9 +169,9 @@ export function findRelease( }); const foundRelease = sortedReleases[0]; - const foundAsset = foundRelease.files.find( - item => item.arch === architecture && item.platform === process.platform - ); + const foundAsset = IS_WINDOWS + ? findAssetForWindows(foundRelease) + : findAssetForMacOrLinux(foundRelease, architecture, process.platform); return { foundAsset, @@ -191,3 +193,39 @@ export function pypyVersionToSemantic(versionSpec: string) { const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); } + +export function isArchPresentForWindows(item: any) { + return item.files.some( + (file: any) => + WINDOWS_ARCHS.includes(file.arch) && + WINDOWS_PLATFORMS.includes(file.platform) + ); +} + +export function isArchPresentForMacOrLinux( + item: any, + architecture: string, + platform: string +) { + return item.files.some( + (file: any) => file.arch === architecture && file.platform === platform + ); +} + +export function findAssetForWindows(releases: any) { + return releases.files.find( + (item: any) => + WINDOWS_ARCHS.includes(item.arch) && + WINDOWS_PLATFORMS.includes(item.platform) + ); +} + +export function findAssetForMacOrLinux( + releases: any, + architecture: string, + platform: string +) { + return releases.files.find( + (item: any) => item.arch === architecture && item.platform === platform + ); +} diff --git a/src/utils.ts b/src/utils.ts index e96d5b230..c15fe3d05 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,6 +4,8 @@ import * as semver from 'semver'; export const IS_WINDOWS = process.platform === 'win32'; export const IS_LINUX = process.platform === 'linux'; +export const WINDOWS_ARCHS = ['x86', 'x64']; +export const WINDOWS_PLATFORMS = ['win32', 'win64']; const PYPY_VERSION_FILE = 'PYPY_VERSION'; export interface IPyPyManifestAsset {