Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install multiple python versions #567

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 43 additions & 1 deletion .github/workflows/test-pypy.yml
Expand Up @@ -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
Expand Down Expand Up @@ -123,4 +123,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 @@ -190,8 +190,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