Skip to content

Commit

Permalink
Install multiple python versions (#567)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry-shibanov committed Dec 22, 2022
1 parent c3e0339 commit 5ccb29d
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 57 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/test-pypy.yml
Expand Up @@ -124,4 +124,46 @@ 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.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
31 changes: 29 additions & 2 deletions .github/workflows/test-python.yml
Expand Up @@ -191,8 +191,35 @@ 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-python-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: |
3.7
3.8
3.9
3.10
check-latest: true
- name: Validate version
run: |
$pythonVersion = (python --version)
if ("$pythonVersion" -NotMatch "3.10"){
Write-Host "The current version is $pythonVersion; expected version is 3.10"
exit 1
}
$pythonVersion
Expand Down
46 changes: 25 additions & 21 deletions dist/setup/index.js
Expand Up @@ -66867,31 +66867,31 @@ function cacheDependencies(cache, pythonVersion) {
});
}
function resolveVersionInput() {
let version = core.getInput('python-version');
let versions = core.getMultilineInput('python-version');
let versionFile = core.getInput('python-version-file');
if (version && 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) {
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;
Expand All @@ -66904,22 +66904,26 @@ function run() {
}
core.debug(`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`);
try {
const version = resolveVersionInput();
const versions = resolveVersionInput();
const checkLatest = core.getBooleanInput('check-latest');
if (version) {
let pythonVersion;
if (versions.length) {
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})`);
core.startGroup('Installed versions');
for (const version of versions) {
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})`);
}
}
core.endGroup();
const cache = core.getInput('cache');
if (cache && utils_1.isCacheFeatureAvailable()) {
yield cacheDependencies(cache, pythonVersion);
Expand Down
57 changes: 57 additions & 0 deletions docs/advanced-usage.md
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
71 changes: 37 additions & 34 deletions src/setup-python.ts
Expand Up @@ -22,18 +22,18 @@ async function cacheDependencies(cache: string, pythonVersion: string) {
await cacheDistributor.restoreCache();
}

function resolveVersionInput(): string {
let version = core.getInput('python-version');
function resolveVersionInput() {
let versions = core.getMultilineInput('python-version');
let versionFile = core.getInput('python-version-file');

if (version && 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) {
return version;
if (versions.length) {
return versions;
}

if (versionFile) {
Expand All @@ -42,24 +42,24 @@ function resolveVersionInput(): 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(
"Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file."
);
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() {
Expand All @@ -75,35 +75,38 @@ async function run() {
`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`
);
try {
const version = resolveVersionInput();
const versions = resolveVersionInput();
const checkLatest = core.getBooleanInput('check-latest');

if (version) {
let pythonVersion: string;
if (versions.length) {
let pythonVersion = '';
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})`);
core.startGroup('Installed versions');
for (const version of versions) {
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})`);
}
}

core.endGroup();
const cache = core.getInput('cache');
if (cache && isCacheFeatureAvailable()) {
await cacheDependencies(cache, pythonVersion);
Expand Down

0 comments on commit 5ccb29d

Please sign in to comment.