From e6c917a949516d04d01bbd9eea3dd92dbcc87e43 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Wed, 16 Dec 2020 15:46:38 +0300 Subject: [PATCH] Add pypy unit tests to cover code * add tests * Update test-pypy.yml * Update test-python.yml * Update test-python.yml * Update README.md * fixing tests * change order Co-authored-by: Maxim Lobanov --- .github/workflows/test-pypy.yml | 4 +- .github/workflows/test-python.yml | 4 +- README.md | 24 +- __tests__/data/pypy.json | 494 ++++++++++++++++++++++++++++++ __tests__/find-pypy.test.ts | 248 +++++++++++++++ __tests__/install-pypy.test.ts | 230 ++++++++++++++ dist/index.js | 69 +++-- src/find-pypy.ts | 9 +- src/install-pypy.ts | 36 +-- src/utils.ts | 29 +- 10 files changed, 1063 insertions(+), 84 deletions(-) create mode 100644 __tests__/data/pypy.json create mode 100644 __tests__/find-pypy.test.ts create mode 100644 __tests__/install-pypy.test.ts diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index 4f5d31db..4041440d 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -9,7 +9,7 @@ on: paths-ignore: - '**.md' schedule: - - cron: 0 0 * * * + - cron: 30 3 * * * jobs: setup-pypy: @@ -44,4 +44,4 @@ jobs: run: python --version - name: Run simple code - run: python -c 'import math; print(math.factorial(5))' \ No newline at end of file + run: python -c 'import math; print(math.factorial(5))' diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 2026d7c9..3a85ee22 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -9,7 +9,7 @@ on: paths-ignore: - '**.md' schedule: - - cron: 0 0 * * * + - cron: 30 3 * * * jobs: default-version: @@ -91,7 +91,7 @@ jobs: - name: Run simple code run: python -c 'import math; print(math.factorial(5))' - setup-pypy-legacy-way: + setup-pypy-legacy: name: Setup PyPy ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: diff --git a/README.md b/README.md index d169b086..d1fb79e9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This action sets up a Python environment for use in actions by: - Allows for pinning to a specific patch version of Python without the worry of it ever being removed or changed. - Automatic setup and download of Python packages if using a self-hosted runner. - Support for pre-release versions of Python. -- Support for installation any version of PyPy on-flight +- Support for installing any version of PyPy on-flight # Usage @@ -123,8 +123,8 @@ jobs: strategy: matrix: python-version: - - pypy-3.6 # the latest available version of PyPy - - pypy-3.7 # the latest available version of PyPy + - 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 @@ -133,7 +133,7 @@ jobs: python-version: ${{ matrix.python-version }} - run: python my_script.py ``` -More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in [Available versions of PyPy](#available-versions-of-pypy) section. +More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#available-versions-of-pypy) section. # Getting started with Python + Actions @@ -158,11 +158,11 @@ Check out our detailed guide on using [Python with GitHub Actions](https://help. - 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 version of Python are cached. - - Cache is updated with 1-2 weeks delay. if you specify PyPy as `pypy-3.6`, the version from cache will be used although a new version is available. If you need to start using the recently released version right after release, you should specify exact PyPy version `pypy-3.6-v7.3.3`. + - For the latest PyPy release, all versions of Python are cached. + - Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy-3.6`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy-3.6-v7.3.3`. -- Downloadable PyPy versions from [official PyPy site](https://downloads.python.org/pypy/). - - All available versions are listed in the [versions.json](https://downloads.python.org/pypy/versions.json) file. +- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/). + - All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file. - PyPy < 7.3.3 are not available to install on-flight. - If some versions are not available, you can open an issue in https://foss.heptapod.net/pypy/pypy/ @@ -193,12 +193,12 @@ You should specify only a major and minor version if you are okay with the most # Specifying a PyPy version The version of PyPy should be specified in the format `pypy-[-v]`. -Parameter `` is optional and can be skipped. The latest version will be used in this case. +The `` parameter is optional and can be skipped. The latest version will be used in this case. ``` -pypy-3.6 # the latest available version of PyPy -pypy-3.7 # the latest available version of PyPy -pypy-2.7 # the latest available version of PyPy +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-2.7 # the latest available version of PyPy that supports Python 2.7 pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy diff --git a/__tests__/data/pypy.json b/__tests__/data/pypy.json new file mode 100644 index 00000000..95e06bbb --- /dev/null +++ b/__tests__/data/pypy.json @@ -0,0 +1,494 @@ +[ + { + "pypy_version": "7.3.3", + "python_version": "3.6.12", + "stable": true, + "latest_pypy": true, + "date": "2020-11-21", + "files": [ + { + "filename": "pypy3.6-v7.3.3-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-aarch64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-linux32.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-linux64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-darwin64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-darwin64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-win32.zip" + }, + { + "filename": "pypy3.6-v7.3.3-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.3rc1", + "python_version": "3.6.12", + "stable": false, + "latest_pypy": false, + "date": "2020-11-11", + "files": [ + { + "filename": "pypy3.6-v7.3.3rc1-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-aarch64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-linux32rc1.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-linux32.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3rc1-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-linux64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3rc1-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-osx64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.3-win32rc1.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-win32.zip" + }, + { + "filename": "pypy3.6-v7.3.3rc1-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.3rc1-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.3rc2", + "python_version": "3.7.7", + "stable": false, + "latest_pypy": false, + "date": "2020-11-11", + "files": [ + { + "filename": "test.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "test.tar.bz2" + }, + { + "filename": "test.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "test.tar.bz2" + }, + { + "filename": "test.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "test.tar.bz2" + }, + { + "filename": "test.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "test.tar.bz2" + }, + { + "filename": "test.zip", + "arch": "x86", + "platform": "win32", + "download_url": "test.zip" + }, + { + "filename": "test.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "test.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.3", + "python_version": "3.7.9", + "stable": true, + "latest_pypy": true, + "date": "2020-11-21", + "files": [ + { + "filename": "pypy3.7-v7.3.3-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.3-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.3-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.3-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.3-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-win32.zip" + }, + { + "filename": "pypy3.7-v7.3.3-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.3-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.3", + "python_version": "2.7.18", + "stable": true, + "latest_pypy": true, + "date": "2020-11-21", + "files": [ + { + "filename": "pypy2.7-v7.3.3-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.3-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.3-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.3-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.3-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-win32.zip" + }, + { + "filename": "pypy2.7-v7.3.3-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.3-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.2", + "python_version": "3.6.9", + "stable": true, + "latest_pypy": true, + "date": "2020-09-25", + "files": [ + { + "filename": "pypy3.6-v7.3.2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-aarch64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-linux32.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-linux64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-osx64.tar.bz2" + }, + { + "filename": "pypy3.6-v7.3.2-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-win32.zip" + }, + { + "filename": "pypy3.6-v7.3.2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.6-v7.3.2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.2", + "python_version": "3.7.9", + "stable": true, + "latest_pypy": false, + "date": "2020-09-25", + "files": [ + { + "filename": "pypy3.7-v7.3.2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-aarch64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-linux32.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-linux64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-osx64.tar.bz2" + }, + { + "filename": "pypy3.7-v7.3.2-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-win32.zip" + }, + { + "filename": "pypy3.7-v7.3.2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy3.7-v7.3.2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "7.3.2", + "python_version": "2.7.13", + "stable": true, + "latest_pypy": true, + "date": "2020-09-25", + "files": [ + { + "filename": "pypy2.7-v7.3.2-aarch64.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-aarch64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.2-linux32.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-linux32.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.2-linux64.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-linux64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.2-osx64.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-osx64.tar.bz2" + }, + { + "filename": "pypy2.7-v7.3.2-win32.zip", + "arch": "x86", + "platform": "win32", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-win32.zip" + }, + { + "filename": "pypy2.7-v7.3.2-s390x.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "https://test.download.python.org/pypy/pypy2.7-v7.3.2-s390x.tar.bz2" + } + ] + }, + { + "pypy_version": "nightly", + "python_version": "2.7", + "stable": false, + "latest_pypy": false, + "files": [ + { + "filename": "filename.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.zip", + "arch": "x86", + "platform": "win32", + "download_url": "http://nightlyBuilds.org/filename.zip" + }, + { + "filename": "filename.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + } + ] + }, + { + "pypy_version": "nightly", + "python_version": "3.7", + "stable": false, + "latest_pypy": false, + "files": [ + { + "filename": "filename.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.zip", + "arch": "x86", + "platform": "win32", + "download_url": "http://nightlyBuilds.org/filename.zip" + }, + { + "filename": "filename.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + } + ] + }, + { + "pypy_version": "nightly", + "python_version": "3.6", + "stable": false, + "latest_pypy": false, + "files": [ + { + "filename": "filename.tar.bz2", + "arch": "aarch64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "i686", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.tar.bz2", + "arch": "x64", + "platform": "darwin", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + }, + { + "filename": "filename.zip", + "arch": "x86", + "platform": "win32", + "download_url": "http://nightlyBuilds.org/filename.zip" + }, + { + "filename": "filename.tar.bz2", + "arch": "s390x", + "platform": "linux", + "download_url": "http://nightlyBuilds.org/filename.tar.bz2" + } + ] + } +] \ No newline at end of file diff --git a/__tests__/find-pypy.test.ts b/__tests__/find-pypy.test.ts new file mode 100644 index 00000000..b9c6599f --- /dev/null +++ b/__tests__/find-pypy.test.ts @@ -0,0 +1,248 @@ +import fs from 'fs'; + +import * as utils from '../src/utils'; +import {HttpClient} from '@actions/http-client'; +import * as ifm from '@actions/http-client/interfaces'; +import * as tc from '@actions/tool-cache'; +import * as exec from '@actions/exec'; + +import * as path from 'path'; +import * as semver from 'semver'; + +import * as finder from '../src/find-pypy'; +import { + IPyPyManifestRelease, + IS_WINDOWS, + validateVersion, + getPyPyVersionFromPath +} from '../src/utils'; + +const manifestData = require('./data/pypy.json'); + +let architecture: string; + +if (IS_WINDOWS) { + architecture = 'x86'; +} else { + architecture = 'x64'; +} + +const toolDir = path.join(__dirname, 'runner', 'tools'); +const tempDir = path.join(__dirname, 'runner', 'temp'); + +describe('parsePyPyVersion', () => { + it.each([ + ['pypy-3.6-v7.3.3', {pythonVersion: '3.6', pypyVersion: 'v7.3.3'}], + ['pypy-3.6-v7.3.x', {pythonVersion: '3.6', pypyVersion: 'v7.3.x'}], + ['pypy-3.6-v7.x', {pythonVersion: '3.6', pypyVersion: 'v7.x'}], + ['pypy-3.6', {pythonVersion: '3.6', pypyVersion: 'x'}], + ['pypy-3.6-nightly', {pythonVersion: '3.6', pypyVersion: 'nightly'}], + ['pypy-3.6-v7.3.3rc1', {pythonVersion: '3.6', pypyVersion: 'v7.3.3-rc.1'}] + ])('%s -> %s', (input, expected) => { + expect(finder.parsePyPyVersion(input)).toEqual(expected); + }); + + it('throw on invalid input', () => { + expect(() => finder.parsePyPyVersion('pypy-')).toThrowError( + "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-'. See README for examples and documentation." + ); + }); +}); + +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( + '3.6.5' + ); + }); +}); + +describe('findPyPyToolCache', () => { + const actualPythonVersion = '3.6.17'; + const actualPyPyVersion = '7.5.4'; + const pypyPath = path.join('PyPy', actualPythonVersion, architecture); + let tcFind: jest.SpyInstance; + let spyReadExactPyPyVersion: jest.SpyInstance; + + beforeEach(() => { + tcFind = jest.spyOn(tc, 'find'); + tcFind.mockImplementation((toolname: string, pythonVersion: string) => { + const semverVersion = new semver.Range(pythonVersion); + return semver.satisfies(actualPythonVersion, semverVersion) + ? pypyPath + : ''; + }); + + spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile'); + spyReadExactPyPyVersion.mockImplementation(() => actualPyPyVersion); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it('PyPy exists on the path and versions are satisfied', () => { + expect(finder.findPyPyToolCache('3.6.17', 'v7.5.4', architecture)).toEqual({ + installDir: pypyPath, + resolvedPythonVersion: actualPythonVersion, + resolvedPyPyVersion: actualPyPyVersion + }); + }); + + it('PyPy exists on the path and versions are satisfied with semver', () => { + expect(finder.findPyPyToolCache('3.6', 'v7.5.x', architecture)).toEqual({ + installDir: pypyPath, + resolvedPythonVersion: actualPythonVersion, + resolvedPyPyVersion: actualPyPyVersion + }); + }); + + it("PyPy exists on the path, but Python version doesn't match", () => { + expect(finder.findPyPyToolCache('3.7', 'v7.5.4', architecture)).toEqual({ + installDir: '', + resolvedPythonVersion: '', + resolvedPyPyVersion: '' + }); + }); + + it("PyPy exists on the path, but PyPy version doesn't match", () => { + expect(finder.findPyPyToolCache('3.6', 'v7.5.1', architecture)).toEqual({ + installDir: null, + resolvedPythonVersion: '', + resolvedPyPyVersion: '' + }); + }); +}); + +describe('findPyPyVersion', () => { + let tcFind: jest.SpyInstance; + let spyExtractZip: jest.SpyInstance; + let spyExtractTar: jest.SpyInstance; + let spyHttpClient: jest.SpyInstance; + let spyExistsSync: jest.SpyInstance; + let spyExec: jest.SpyInstance; + let spySymlinkSync: jest.SpyInstance; + let spyDownloadTool: jest.SpyInstance; + let spyReadExactPyPyVersion: jest.SpyInstance; + let spyFsReadDir: jest.SpyInstance; + let spyWriteExactPyPyVersionFile: jest.SpyInstance; + let spyCacheDir: jest.SpyInstance; + let spyChmodSync: jest.SpyInstance; + + beforeEach(() => { + tcFind = jest.spyOn(tc, 'find'); + tcFind.mockImplementation((tool: string, version: string) => { + const semverRange = new semver.Range(version); + let pypyPath = ''; + if (semver.satisfies('3.6.12', semverRange)) { + pypyPath = path.join(toolDir, 'PyPy', '3.6.12', architecture); + } + return pypyPath; + }); + + spyWriteExactPyPyVersionFile = jest.spyOn( + utils, + 'writeExactPyPyVersionFile' + ); + spyWriteExactPyPyVersionFile.mockImplementation(() => null); + + spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile'); + spyReadExactPyPyVersion.mockImplementation(() => '7.3.3'); + + spyDownloadTool = jest.spyOn(tc, 'downloadTool'); + spyDownloadTool.mockImplementation(() => path.join(tempDir, 'PyPy')); + + spyExtractZip = jest.spyOn(tc, 'extractZip'); + spyExtractZip.mockImplementation(() => tempDir); + + spyExtractTar = jest.spyOn(tc, 'extractTar'); + spyExtractTar.mockImplementation(() => tempDir); + + spyFsReadDir = jest.spyOn(fs, 'readdirSync'); + spyFsReadDir.mockImplementation((directory: string) => ['PyPyTest']); + + spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); + spyHttpClient.mockImplementation( + async (): Promise> => { + const result = JSON.stringify(manifestData); + return { + statusCode: 200, + headers: {}, + result: JSON.parse(result) as IPyPyManifestRelease[] + }; + } + ); + + spyExec = jest.spyOn(exec, 'exec'); + spyExec.mockImplementation(() => undefined); + + spySymlinkSync = jest.spyOn(fs, 'symlinkSync'); + spySymlinkSync.mockImplementation(() => undefined); + + spyExistsSync = jest.spyOn(fs, 'existsSync'); + spyExistsSync.mockReturnValue(true); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it('found PyPy in toolcache', async () => { + await expect( + finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture) + ).resolves.toEqual({ + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.3.3' + }); + }); + + it('throw on invalid input format', 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(() => + path.join(toolDir, 'PyPy', '3.7.7', architecture) + ); + spyChmodSync = jest.spyOn(fs, 'chmodSync'); + spyChmodSync.mockImplementation(() => undefined); + await expect( + finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture) + ).resolves.toEqual({ + resolvedPythonVersion: '3.7.9', + resolvedPyPyVersion: '7.3.3' + }); + }); + + it('throw if release is not found', async () => { + await expect( + finder.findPyPyVersion('pypy3.7-v7.3.x', architecture) + ).rejects.toThrowError( + "Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-'. See README for examples and documentation." + ); + }); +}); diff --git a/__tests__/install-pypy.test.ts b/__tests__/install-pypy.test.ts new file mode 100644 index 00000000..cffc90e8 --- /dev/null +++ b/__tests__/install-pypy.test.ts @@ -0,0 +1,230 @@ +import fs from 'fs'; + +import {HttpClient} from '@actions/http-client'; +import * as ifm from '@actions/http-client/interfaces'; +import * as tc from '@actions/tool-cache'; +import * as exec from '@actions/exec'; +import * as path from 'path'; + +import * as installer from '../src/install-pypy'; +import { + IPyPyManifestRelease, + IPyPyManifestAsset, + IS_WINDOWS +} from '../src/utils'; + +const manifestData = require('./data/pypy.json'); + +let architecture: string; +if (IS_WINDOWS) { + architecture = 'x86'; +} else { + architecture = 'x64'; +} + +const toolDir = path.join(__dirname, 'runner', 'tools'); +const tempDir = path.join(__dirname, 'runner', 'temp'); + +describe('pypyVersionToSemantic', () => { + it.each([ + ['7.3.3rc1', '7.3.3-rc.1'], + ['7.3.3', '7.3.3'], + ['7.3.x', '7.3.x'], + ['7.x', '7.x'], + ['nightly', 'nightly'] + ])('%s -> %s', (input, expected) => { + expect(installer.pypyVersionToSemantic(input)).toEqual(expected); + }); +}); + +describe('findRelease', () => { + const result = JSON.stringify(manifestData); + const releases = JSON.parse(result) as IPyPyManifestRelease[]; + const extension = IS_WINDOWS ? '.zip' : '.tar.bz2'; + const extensionName = IS_WINDOWS + ? `${process.platform}${extension}` + : `${process.platform}64${extension}`; + const files: IPyPyManifestAsset = { + filename: `pypy3.6-v7.3.3-${extensionName}`, + arch: architecture, + platform: process.platform, + download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}` + }; + + it("Python version is found, but PyPy version doesn't match", () => { + const pythonVersion = '3.6'; + const pypyVersion = '7.3.7'; + expect( + installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + ).toEqual(null); + }); + + it('Python version is found and PyPy version matches', () => { + const pythonVersion = '3.6'; + const pypyVersion = '7.3.3'; + expect( + installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + ).toEqual({ + foundAsset: files, + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: pypyVersion + }); + }); + + it('Python version is found in toolcache and PyPy version matches semver', () => { + const pythonVersion = '3.6'; + const pypyVersion = '7.x'; + expect( + installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + ).toEqual({ + foundAsset: files, + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.3.3' + }); + }); + + it('Python and preview version of PyPy are found', () => { + const pythonVersion = '3.7'; + const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2'); + expect( + installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + ).toEqual({ + foundAsset: { + filename: `test${extension}`, + arch: architecture, + platform: process.platform, + download_url: `test${extension}` + }, + resolvedPythonVersion: '3.7.7', + resolvedPyPyVersion: '7.3.3rc2' + }); + }); + + it('Python version with latest PyPy is found', () => { + const pythonVersion = '3.6'; + const pypyVersion = 'x'; + expect( + installer.findRelease(releases, pythonVersion, pypyVersion, architecture) + ).toEqual({ + foundAsset: files, + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.3.3' + }); + }); + + 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) + ).toEqual({ + foundAsset: { + filename: filename, + arch: architecture, + platform: process.platform, + download_url: `http://nightlyBuilds.org/${filename}` + }, + resolvedPythonVersion: '3.6', + resolvedPyPyVersion: pypyVersion + }); + }); +}); + +describe('installPyPy', () => { + let tcFind: jest.SpyInstance; + let spyExtractZip: jest.SpyInstance; + let spyExtractTar: jest.SpyInstance; + let spyFsReadDir: jest.SpyInstance; + let spyFsWriteFile: jest.SpyInstance; + let spyHttpClient: jest.SpyInstance; + let spyExistsSync: jest.SpyInstance; + let spyExec: jest.SpyInstance; + let spySymlinkSync: jest.SpyInstance; + let spyDownloadTool: jest.SpyInstance; + let spyCacheDir: jest.SpyInstance; + let spyChmodSync: jest.SpyInstance; + + beforeEach(() => { + tcFind = jest.spyOn(tc, 'find'); + tcFind.mockImplementation(() => path.join('PyPy', '3.6.12', architecture)); + + spyDownloadTool = jest.spyOn(tc, 'downloadTool'); + spyDownloadTool.mockImplementation(() => path.join(tempDir, 'PyPy')); + + spyExtractZip = jest.spyOn(tc, 'extractZip'); + spyExtractZip.mockImplementation(() => tempDir); + + spyExtractTar = jest.spyOn(tc, 'extractTar'); + spyExtractTar.mockImplementation(() => tempDir); + + spyFsReadDir = jest.spyOn(fs, 'readdirSync'); + spyFsReadDir.mockImplementation(() => ['PyPyTest']); + + spyFsWriteFile = jest.spyOn(fs, 'writeFileSync'); + spyFsWriteFile.mockImplementation(() => undefined); + + spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); + spyHttpClient.mockImplementation( + async (): Promise> => { + const result = JSON.stringify(manifestData); + return { + statusCode: 200, + headers: {}, + result: JSON.parse(result) as IPyPyManifestRelease[] + }; + } + ); + + spyExec = jest.spyOn(exec, 'exec'); + spyExec.mockImplementation(() => undefined); + + spySymlinkSync = jest.spyOn(fs, 'symlinkSync'); + spySymlinkSync.mockImplementation(() => undefined); + + spyExistsSync = jest.spyOn(fs, 'existsSync'); + spyExistsSync.mockImplementation(() => false); + }); + + afterEach(() => { + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it('throw if release is not found', async () => { + await expect( + installer.installPyPy('7.3.3', '3.6.17', architecture) + ).rejects.toThrowError( + `PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found` + ); + + expect(spyHttpClient).toHaveBeenCalled(); + expect(spyDownloadTool).not.toHaveBeenCalled(); + expect(spyExec).not.toHaveBeenCalled(); + }); + + it('found and install PyPy', 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.3.x', '3.6.12', architecture) + ).resolves.toEqual({ + installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture), + resolvedPythonVersion: '3.6.12', + resolvedPyPyVersion: '7.3.3' + }); + + expect(spyHttpClient).toHaveBeenCalled(); + expect(spyDownloadTool).toHaveBeenCalled(); + expect(spyExistsSync).toHaveBeenCalled(); + expect(spyCacheDir).toHaveBeenCalled(); + expect(spyExec).toHaveBeenCalled(); + }); +}); diff --git a/dist/index.js b/dist/index.js index 5fb5226b..4992e541 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1138,7 +1138,7 @@ function findPyPyToolCache(pythonVersion, pypyVersion, architecture) { // 'tc.find' finds tool based on Python version but we also need to check // whether PyPy version satisfies requested version. resolvedPythonVersion = utils_1.getPyPyVersionFromPath(installDir); - resolvedPyPyVersion = pypyInstall.readExactPyPyVersion(installDir); + resolvedPyPyVersion = utils_1.readExactPyPyVersionFile(installDir); const isPyPyVersionSatisfies = semver.satisfies(resolvedPyPyVersion, pypyVersion); if (!isPyPyVersionSatisfies) { installDir = null; @@ -2308,6 +2308,9 @@ exports.debug = debug; // for test "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; @@ -2316,11 +2319,12 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __importStar(__webpack_require__(747)); +const fs_1 = __importDefault(__webpack_require__(747)); const path = __importStar(__webpack_require__(622)); const semver = __importStar(__webpack_require__(876)); exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_LINUX = process.platform === 'linux'; +const PYPY_VERSION_FILE = 'PYPY_VERSION'; /** create Symlinks for downloaded PyPy * It should be executed only for downloaded versions in runtime, because * toolcache versions have this setup. @@ -2328,12 +2332,12 @@ exports.IS_LINUX = process.platform === 'linux'; function createSymlinkInFolder(folderPath, sourceName, targetName, setExecutable = false) { const sourcePath = path.join(folderPath, sourceName); const targetPath = path.join(folderPath, targetName); - if (fs.existsSync(targetPath)) { + if (fs_1.default.existsSync(targetPath)) { return; } - fs.symlinkSync(sourcePath, targetPath); + fs_1.default.symlinkSync(sourcePath, targetPath); if (!exports.IS_WINDOWS && setExecutable) { - fs.chmodSync(targetPath, '755'); + fs_1.default.chmodSync(targetPath, '755'); } } exports.createSymlinkInFolder = createSymlinkInFolder; @@ -2349,6 +2353,28 @@ function getPyPyVersionFromPath(installDir) { return path.basename(path.dirname(installDir)); } exports.getPyPyVersionFromPath = getPyPyVersionFromPath; +/** + * In tool-cache, we put PyPy to '/PyPy//x64' + * There is no easy way to determine what PyPy version is located in specific folder + * 'pypy --version' is not reliable enough since it is not set properly for preview versions + * "7.3.3rc1" is marked as '7.3.3' in 'pypy --version' + * so we put PYPY_VERSION file to PyPy directory when install it to VM and read it when we need to know version + * PYPY_VERSION contains exact version from 'versions.json' + */ +function readExactPyPyVersionFile(installDir) { + let pypyVersion = ''; + let fileVersion = path.join(installDir, PYPY_VERSION_FILE); + if (fs_1.default.existsSync(fileVersion)) { + pypyVersion = fs_1.default.readFileSync(fileVersion).toString(); + } + return pypyVersion; +} +exports.readExactPyPyVersionFile = readExactPyPyVersionFile; +function writeExactPyPyVersionFile(installDir, resolvedPyPyVersion) { + const pypyFilePath = path.join(installDir, PYPY_VERSION_FILE); + fs_1.default.writeFileSync(pypyFilePath, resolvedPyPyVersion); +} +exports.writeExactPyPyVersionFile = writeExactPyPyVersionFile; /***/ }), @@ -2767,6 +2793,9 @@ var __importStar = (this && this.__importStar) || function (mod) { result["default"] = mod; return result; }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); const path = __importStar(__webpack_require__(622)); const core = __importStar(__webpack_require__(470)); @@ -2774,9 +2803,8 @@ const tc = __importStar(__webpack_require__(533)); const semver = __importStar(__webpack_require__(876)); const httpm = __importStar(__webpack_require__(539)); const exec = __importStar(__webpack_require__(986)); -const fs = __importStar(__webpack_require__(747)); +const fs_1 = __importDefault(__webpack_require__(747)); const utils_1 = __webpack_require__(163); -const PYPY_VERSION_FILE = 'PYPY_VERSION'; function installPyPy(pypyVersion, pythonVersion, architecture) { return __awaiter(this, void 0, void 0, function* () { let downloadDir; @@ -2801,13 +2829,13 @@ function installPyPy(pypyVersion, pythonVersion, architecture) { } // root folder in archive can have unpredictable name so just take the first folder // downloadDir is unique folder under TEMP and can't contain any other folders - const archiveName = fs.readdirSync(downloadDir)[0]; + const archiveName = fs_1.default.readdirSync(downloadDir)[0]; const toolDir = path.join(downloadDir, archiveName); let installDir = toolDir; if (!utils_1.isNightlyKeyword(resolvedPyPyVersion)) { installDir = yield tc.cacheDir(toolDir, 'PyPy', resolvedPythonVersion, architecture); } - writeExactPyPyVersionFile(installDir, resolvedPyPyVersion); + utils_1.writeExactPyPyVersionFile(installDir, resolvedPyPyVersion); const binaryPath = getPyPyBinaryPath(installDir); yield createPyPySymlink(binaryPath, resolvedPythonVersion); yield installPip(binaryPath); @@ -2871,29 +2899,6 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) { }; } exports.findRelease = findRelease; -// helper functions -/** - * In tool-cache, we put PyPy to '/PyPy//x64' - * There is no easy way to determine what PyPy version is located in specific folder - * 'pypy --version' is not reliable enough since it is not set properly for preview versions - * "7.3.3rc1" is marked as '7.3.3' in 'pypy --version' - * so we put PYPY_VERSION file to PyPy directory when install it to VM and read it when we need to know version - * PYPY_VERSION contains exact version from 'versions.json' - */ -function readExactPyPyVersion(installDir) { - let pypyVersion = ''; - let fileVersion = path.join(installDir, PYPY_VERSION_FILE); - if (fs.existsSync(fileVersion)) { - pypyVersion = fs.readFileSync(fileVersion).toString(); - core.debug(`Version from ${PYPY_VERSION_FILE} file is ${pypyVersion}`); - } - return pypyVersion; -} -exports.readExactPyPyVersion = readExactPyPyVersion; -function writeExactPyPyVersionFile(installDir, resolvedPyPyVersion) { - const pypyFilePath = path.join(installDir, PYPY_VERSION_FILE); - fs.writeFileSync(pypyFilePath, resolvedPyPyVersion); -} /** Get PyPy binary location from the tool of installation directory * - On Linux and macOS, the Python interpreter is in 'bin'. * - On Windows, it is in the installation root. diff --git a/src/find-pypy.ts b/src/find-pypy.ts index 1fc44398..b45f48f8 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -1,6 +1,11 @@ import * as path from 'path'; import * as pypyInstall from './install-pypy'; -import {IS_WINDOWS, validateVersion, getPyPyVersionFromPath} from './utils'; +import { + IS_WINDOWS, + validateVersion, + getPyPyVersionFromPath, + readExactPyPyVersionFile +} from './utils'; import * as semver from 'semver'; import * as core from '@actions/core'; @@ -67,7 +72,7 @@ export function findPyPyToolCache( // 'tc.find' finds tool based on Python version but we also need to check // whether PyPy version satisfies requested version. resolvedPythonVersion = getPyPyVersionFromPath(installDir); - resolvedPyPyVersion = pypyInstall.readExactPyPyVersion(installDir); + resolvedPyPyVersion = readExactPyPyVersionFile(installDir); const isPyPyVersionSatisfies = semver.satisfies( resolvedPyPyVersion, diff --git a/src/install-pypy.ts b/src/install-pypy.ts index cf006e0d..99d60300 100644 --- a/src/install-pypy.ts +++ b/src/install-pypy.ts @@ -4,17 +4,16 @@ import * as tc from '@actions/tool-cache'; import * as semver from 'semver'; import * as httpm from '@actions/http-client'; import * as exec from '@actions/exec'; -import * as fs from 'fs'; +import fs from 'fs'; import { IS_WINDOWS, IPyPyManifestRelease, createSymlinkInFolder, - isNightlyKeyword + isNightlyKeyword, + writeExactPyPyVersionFile } from './utils'; -const PYPY_VERSION_FILE = 'PYPY_VERSION'; - export async function installPyPy( pypyVersion: string, pythonVersion: string, @@ -179,35 +178,6 @@ export function findRelease( }; } -// helper functions - -/** - * In tool-cache, we put PyPy to '/PyPy//x64' - * There is no easy way to determine what PyPy version is located in specific folder - * 'pypy --version' is not reliable enough since it is not set properly for preview versions - * "7.3.3rc1" is marked as '7.3.3' in 'pypy --version' - * so we put PYPY_VERSION file to PyPy directory when install it to VM and read it when we need to know version - * PYPY_VERSION contains exact version from 'versions.json' - */ -export function readExactPyPyVersion(installDir: string) { - let pypyVersion = ''; - let fileVersion = path.join(installDir, PYPY_VERSION_FILE); - if (fs.existsSync(fileVersion)) { - pypyVersion = fs.readFileSync(fileVersion).toString(); - core.debug(`Version from ${PYPY_VERSION_FILE} file is ${pypyVersion}`); - } - - return pypyVersion; -} - -function writeExactPyPyVersionFile( - installDir: string, - resolvedPyPyVersion: string -) { - const pypyFilePath = path.join(installDir, PYPY_VERSION_FILE); - fs.writeFileSync(pypyFilePath, resolvedPyPyVersion); -} - /** Get PyPy binary location from the tool of installation directory * - On Linux and macOS, the Python interpreter is in 'bin'. * - On Windows, it is in the installation root. diff --git a/src/utils.ts b/src/utils.ts index 52143b34..845fe097 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,9 +1,10 @@ -import * as fs from 'fs'; +import fs from 'fs'; import * as path from 'path'; import * as semver from 'semver'; export const IS_WINDOWS = process.platform === 'win32'; export const IS_LINUX = process.platform === 'linux'; +const PYPY_VERSION_FILE = 'PYPY_VERSION'; export interface IPyPyManifestAsset { filename: string; @@ -53,3 +54,29 @@ export function isNightlyKeyword(pypyVersion: string) { export function getPyPyVersionFromPath(installDir: string) { return path.basename(path.dirname(installDir)); } + +/** + * In tool-cache, we put PyPy to '/PyPy//x64' + * There is no easy way to determine what PyPy version is located in specific folder + * 'pypy --version' is not reliable enough since it is not set properly for preview versions + * "7.3.3rc1" is marked as '7.3.3' in 'pypy --version' + * so we put PYPY_VERSION file to PyPy directory when install it to VM and read it when we need to know version + * PYPY_VERSION contains exact version from 'versions.json' + */ +export function readExactPyPyVersionFile(installDir: string) { + let pypyVersion = ''; + let fileVersion = path.join(installDir, PYPY_VERSION_FILE); + if (fs.existsSync(fileVersion)) { + pypyVersion = fs.readFileSync(fileVersion).toString(); + } + + return pypyVersion; +} + +export function writeExactPyPyVersionFile( + installDir: string, + resolvedPyPyVersion: string +) { + const pypyFilePath = path.join(installDir, PYPY_VERSION_FILE); + fs.writeFileSync(pypyFilePath, resolvedPyPyVersion); +}