From fa589f774a5ec5cb5590d357a35e3a07e454df06 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Sun, 4 Dec 2022 22:51:04 +0100 Subject: [PATCH 1/5] add support to install multiple python versions --- .github/workflows/test-pypy.yml | 43 +++++++++++++++++++ .github/workflows/test-python.yml | 26 +++++++++++- dist/setup/index.js | 43 +++++++++++-------- src/setup-python.ts | 68 +++++++++++++++++-------------- 4 files changed, 131 insertions(+), 49 deletions(-) diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index de9ba6b79..7cd1bc5ec 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -123,4 +123,47 @@ jobs: EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe ${EXECUTABLE} --version + shell: bash + + setup-pypy-multiple-versions: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + steps: + - uses: actions/checkout@v3 + - name: Setup PyPy and check latest + uses: ./ + with: + python-version: | + pypy-3.7-v7.3.x + pypy3.9-nightly + pypy3.8 + check-latest: true + - name: PyPy and Python version + run: python --version + + - name: Run simple code + run: python -c 'import math; print(math.factorial(5))' + + - name: Assert PyPy is running + run: | + import platform + assert platform.python_implementation().lower() == "pypy" + shell: python + + - name: Assert expected binaries (or symlinks) are present + run: | + EXECUTABLE="pypy-3.7-v7.3.x" + EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name + EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe + ${EXECUTABLE} --version + shell: bash + - name: Assert expected binaries (or symlinks) are present + run: | + EXECUTABLE='pypy3.8' + EXECUTABLE=${EXECUTABLE/pypy-/pypy} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name + EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe + ${EXECUTABLE} --version shell: bash \ No newline at end of file diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 921449fb1..c1800c2ba 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -190,8 +190,30 @@ jobs: - name: Validate version run: | $pythonVersion = (python --version) - if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){ - Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}" + if ("$pythonVersion" -NotMatch "${{ matrix.python-version }}"){ + Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python-version }}" + exit 1 + } + $pythonVersion + shell: pwsh + setup-python-multiple-versions: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + steps: + - uses: actions/checkout@v3 + - name: Setup Python and check latest + uses: ./ + with: + python-version: ${{ matrix.python-version }} + check-latest: true + - name: Validate version + run: | + $pythonVersion = (python --version) + if ("$pythonVersion" -NotMatch "${{ matrix.python-version }}"){ + Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python-version }}" exit 1 } $pythonVersion diff --git a/dist/setup/index.js b/dist/setup/index.js index d92820713..619656fcb 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -66797,12 +66797,12 @@ function cacheDependencies(cache, pythonVersion) { }); } function resolveVersionInput() { - let version = core.getInput('python-version'); + let version = core.getMultilineInput('python-version'); let versionFile = core.getInput('python-version-file'); - if (version && versionFile) { + if (version.length && versionFile) { core.warning('Both python-version and python-version-file inputs are specified, only python-version will be used.'); } - if (version) { + if (version.length) { return version; } if (versionFile) { @@ -66834,21 +66834,30 @@ function run() { } core.debug(`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`); try { - const version = resolveVersionInput(); + let versions; + const resolvedVersionInput = resolveVersionInput(); const checkLatest = core.getBooleanInput('check-latest'); - if (version) { - let pythonVersion; - const arch = core.getInput('architecture') || os.arch(); - const updateEnvironment = core.getBooleanInput('update-environment'); - if (isPyPyVersion(version)) { - const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest); - pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; - core.info(`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`); - } - else { - const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment, checkLatest); - pythonVersion = installed.version; - core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); + if (Array.isArray(resolvedVersionInput)) { + versions = resolvedVersionInput; + } + else { + versions = [resolvedVersionInput]; + } + if (versions.length) { + let pythonVersion = ''; + for (const version of versions) { + const arch = core.getInput('architecture') || os.arch(); + const updateEnvironment = core.getBooleanInput('update-environment'); + if (isPyPyVersion(version)) { + const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest); + pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; + core.info(`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`); + } + else { + const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment, checkLatest); + pythonVersion = installed.version; + core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); + } } const cache = core.getInput('cache'); if (cache && utils_1.isCacheFeatureAvailable()) { diff --git a/src/setup-python.ts b/src/setup-python.ts index d6e6bdaf0..0f3af6dec 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -22,17 +22,17 @@ async function cacheDependencies(cache: string, pythonVersion: string) { await cacheDistributor.restoreCache(); } -function resolveVersionInput(): string { - let version = core.getInput('python-version'); +function resolveVersionInput(): string | string[] { + let version: string | string[] = core.getMultilineInput('python-version'); let versionFile = core.getInput('python-version-file'); - if (version && versionFile) { + if (version.length && versionFile) { core.warning( 'Both python-version and python-version-file inputs are specified, only python-version will be used.' ); } - if (version) { + if (version.length) { return version; } @@ -75,35 +75,43 @@ async function run() { `Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}` ); try { - const version = resolveVersionInput(); + let versions: string[]; + const resolvedVersionInput = resolveVersionInput(); const checkLatest = core.getBooleanInput('check-latest'); - if (version) { - let pythonVersion: string; - const arch: string = core.getInput('architecture') || os.arch(); - const updateEnvironment = core.getBooleanInput('update-environment'); - if (isPyPyVersion(version)) { - const installed = await finderPyPy.findPyPyVersion( - version, - arch, - updateEnvironment, - checkLatest - ); - pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; - core.info( - `Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` - ); - } else { - const installed = await finder.useCpythonVersion( - version, - arch, - updateEnvironment, - checkLatest - ); - pythonVersion = installed.version; - core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); - } + if (Array.isArray(resolvedVersionInput)) { + versions = resolvedVersionInput as string[]; + } else { + versions = [resolvedVersionInput as string]; + } + if (versions.length) { + let pythonVersion = ''; + for (const version of versions) { + const arch: string = core.getInput('architecture') || os.arch(); + const updateEnvironment = core.getBooleanInput('update-environment'); + if (isPyPyVersion(version)) { + const installed = await finderPyPy.findPyPyVersion( + version, + arch, + updateEnvironment, + checkLatest + ); + pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; + core.info( + `Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` + ); + } else { + const installed = await finder.useCpythonVersion( + version, + arch, + updateEnvironment, + checkLatest + ); + pythonVersion = installed.version; + core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); + } + } const cache = core.getInput('cache'); if (cache && isCacheFeatureAvailable()) { await cacheDependencies(cache, pythonVersion); From 0130854fbce1e6e72eb4288a218c75f33c3401c3 Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Thu, 15 Dec 2022 14:34:43 +0100 Subject: [PATCH 2/5] fixing comments --- .github/workflows/test-python.yml | 13 ++++--- dist/setup/index.js | 31 +++++++---------- docs/advanced-usage.md | 57 +++++++++++++++++++++++++++++++ src/setup-python.ts | 33 +++++++----------- 4 files changed, 91 insertions(+), 43 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index c1800c2ba..7419ba067 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -196,7 +196,8 @@ jobs: } $pythonVersion shell: pwsh - setup-python-multiple-versions: + + setup-python-multiple-python-versions: runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -207,13 +208,17 @@ jobs: - name: Setup Python and check latest uses: ./ with: - python-version: ${{ matrix.python-version }} + python-version: | + 3.7 + 3.8 + 3.9 + 3.10 check-latest: true - name: Validate version run: | $pythonVersion = (python --version) - if ("$pythonVersion" -NotMatch "${{ matrix.python-version }}"){ - Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python-version }}" + if ("$pythonVersion" -NotMatch "3.10"){ + Write-Host "The current version is $pythonVersion; expected version is 3.10" exit 1 } $pythonVersion diff --git a/dist/setup/index.js b/dist/setup/index.js index 128dbac02..75b57a005 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -66867,31 +66867,31 @@ function cacheDependencies(cache, pythonVersion) { }); } function resolveVersionInput() { - let version = core.getMultilineInput('python-version'); + let versions = core.getMultilineInput('python-version'); let versionFile = core.getInput('python-version-file'); - if (version.length && versionFile) { + if (versions.length && versionFile) { core.warning('Both python-version and python-version-file inputs are specified, only python-version will be used.'); } - if (version.length) { - return version; + if (versions.length) { + return versions; } if (versionFile) { if (!fs_1.default.existsSync(versionFile)) { throw new Error(`The specified python version file at: ${versionFile} doesn't exist.`); } - version = fs_1.default.readFileSync(versionFile, 'utf8'); + const version = fs_1.default.readFileSync(versionFile, 'utf8'); core.info(`Resolved ${versionFile} as ${version}`); - return version; + return [version]; } utils_1.logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file."); versionFile = '.python-version'; if (fs_1.default.existsSync(versionFile)) { - version = fs_1.default.readFileSync(versionFile, 'utf8'); + const version = fs_1.default.readFileSync(versionFile, 'utf8'); core.info(`Resolved ${versionFile} as ${version}`); - return version; + return [version]; } utils_1.logWarning(`${versionFile} doesn't exist.`); - return version; + return versions; } function run() { var _a; @@ -66904,20 +66904,13 @@ function run() { } core.debug(`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`); try { - let versions; - const resolvedVersionInput = resolveVersionInput(); + const versions = resolveVersionInput(); const checkLatest = core.getBooleanInput('check-latest'); - if (Array.isArray(resolvedVersionInput)) { - versions = resolvedVersionInput; - } - else { - versions = [resolvedVersionInput]; - } if (versions.length) { let pythonVersion = ''; + const arch = core.getInput('architecture') || os.arch(); + const updateEnvironment = core.getBooleanInput('update-environment'); for (const version of versions) { - const arch = core.getInput('architecture') || os.arch(); - const updateEnvironment = core.getBooleanInput('update-environment'); if (isPyPyVersion(version)) { const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest); pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 643e73dd6..fa022d930 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -2,6 +2,7 @@ - [Using the python-version input](advanced-usage.md#using-the-python-version-input) - [Specifying a Python version](advanced-usage.md#specifying-a-python-version) - [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version) + - [Specifying multiple Python and PyPy versions](advanced-usage.md#specifying-multiple-python/pypy-version) - [Matrix Testing](advanced-usage.md#matrix-testing) - [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input) - [Check latest version](advanced-usage.md#check-latest-version) @@ -132,6 +133,62 @@ jobs: ``` More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section. +### Specifying multiple Python/PyPy version +The python-version input can get multiple python/pypy versions. The last specified version will be used as a default one. + +Download and set up multiple Python versions: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: | + 3.8 + 3.9 + 3.10 + - run: python my_script.py +``` + +Download and set up multiple PyPy versions: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: | + pypy-3.7-v7.3.x + pypy3.9-nightly + pypy3.8 + - run: python my_script.py +``` + +Download and set up multiple Python/PyPy versions: + +```yaml +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: | + 3.8 + 3.9 + pypy3.9-nightly + pypy3.8 + 3.10 + - run: python my_script.py +``` + ### Matrix Testing Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy: diff --git a/src/setup-python.ts b/src/setup-python.ts index 0f3af6dec..e9b22d0b8 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -22,18 +22,18 @@ async function cacheDependencies(cache: string, pythonVersion: string) { await cacheDistributor.restoreCache(); } -function resolveVersionInput(): string | string[] { - let version: string | string[] = core.getMultilineInput('python-version'); +function resolveVersionInput() { + let versions = core.getMultilineInput('python-version'); let versionFile = core.getInput('python-version-file'); - if (version.length && versionFile) { + if (versions.length && versionFile) { core.warning( 'Both python-version and python-version-file inputs are specified, only python-version will be used.' ); } - if (version.length) { - return version; + if (versions.length) { + return versions; } if (versionFile) { @@ -42,9 +42,9 @@ function resolveVersionInput(): string | string[] { `The specified python version file at: ${versionFile} doesn't exist.` ); } - version = fs.readFileSync(versionFile, 'utf8'); + const version = fs.readFileSync(versionFile, 'utf8'); core.info(`Resolved ${versionFile} as ${version}`); - return version; + return [version]; } logWarning( @@ -52,14 +52,14 @@ function resolveVersionInput(): string | string[] { ); versionFile = '.python-version'; if (fs.existsSync(versionFile)) { - version = fs.readFileSync(versionFile, 'utf8'); + const version = fs.readFileSync(versionFile, 'utf8'); core.info(`Resolved ${versionFile} as ${version}`); - return version; + return [version]; } logWarning(`${versionFile} doesn't exist.`); - return version; + return versions; } async function run() { @@ -75,21 +75,14 @@ async function run() { `Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}` ); try { - let versions: string[]; - const resolvedVersionInput = resolveVersionInput(); + const versions = resolveVersionInput(); const checkLatest = core.getBooleanInput('check-latest'); - if (Array.isArray(resolvedVersionInput)) { - versions = resolvedVersionInput as string[]; - } else { - versions = [resolvedVersionInput as string]; - } - if (versions.length) { let pythonVersion = ''; + const arch: string = core.getInput('architecture') || os.arch(); + const updateEnvironment = core.getBooleanInput('update-environment'); for (const version of versions) { - const arch: string = core.getInput('architecture') || os.arch(); - const updateEnvironment = core.getBooleanInput('update-environment'); if (isPyPyVersion(version)) { const installed = await finderPyPy.findPyPyVersion( version, From 963677d9d91998b40dfe5eaecd2a1576c6b154fb Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Thu, 15 Dec 2022 15:41:33 +0100 Subject: [PATCH 3/5] change pypy3.9-nightly --- .github/workflows/test-pypy.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index 7cd1bc5ec..88dce5cea 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -73,7 +73,7 @@ jobs: fail-fast: false matrix: os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] - pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly'] + pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.8-nightly'] steps: - name: Checkout @@ -138,7 +138,6 @@ jobs: with: python-version: | pypy-3.7-v7.3.x - pypy3.9-nightly pypy3.8 check-latest: true - name: PyPy and Python version From 67bdb4f236d67e8c183952c87f55f8dc0cd0c20f Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Mon, 19 Dec 2022 18:52:46 +0100 Subject: [PATCH 4/5] add group --- dist/setup/index.js | 2 ++ src/setup-python.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dist/setup/index.js b/dist/setup/index.js index 75b57a005..4ba41efca 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -66910,6 +66910,7 @@ function run() { let pythonVersion = ''; const arch = core.getInput('architecture') || os.arch(); const updateEnvironment = core.getBooleanInput('update-environment'); + core.startGroup('Installed versions'); for (const version of versions) { if (isPyPyVersion(version)) { const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest); @@ -66922,6 +66923,7 @@ function run() { core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); } } + core.endGroup(); const cache = core.getInput('cache'); if (cache && utils_1.isCacheFeatureAvailable()) { yield cacheDependencies(cache, pythonVersion); diff --git a/src/setup-python.ts b/src/setup-python.ts index e9b22d0b8..0089b4016 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -82,6 +82,7 @@ async function run() { let pythonVersion = ''; const arch: string = core.getInput('architecture') || os.arch(); const updateEnvironment = core.getBooleanInput('update-environment'); + core.startGroup('Installed versions'); for (const version of versions) { if (isPyPyVersion(version)) { const installed = await finderPyPy.findPyPyVersion( @@ -105,6 +106,7 @@ async function run() { core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); } } + core.endGroup(); const cache = core.getInput('cache'); if (cache && isCacheFeatureAvailable()) { await cacheDependencies(cache, pythonVersion); From 54d59a14e22d94311430900fd13a7458e6cf616e Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Thu, 22 Dec 2022 12:52:00 +0100 Subject: [PATCH 5/5] revert to pypy3.9-nightly --- .github/workflows/test-pypy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-pypy.yml b/.github/workflows/test-pypy.yml index a7117fd14..5340c12f3 100644 --- a/.github/workflows/test-pypy.yml +++ b/.github/workflows/test-pypy.yml @@ -74,7 +74,7 @@ jobs: fail-fast: false matrix: os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] - pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.8-nightly'] + pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly'] steps: - name: Checkout