mirror of https://github.com/actions/setup-python
feature: fallback to pre-release when no stable version is found (#414)
This allows to specify version like `3.11` or `pypy3.10` in workflows before those versions are released. This lessen the burden for users of `setup-python` by not having to modify their workflow twice: once when a pre-release is available (e.g. `3.11-dev`) and once when the first stable release is published (e.g. `3.11`)
This commit is contained in:
parent
a6eba85bba
commit
2652534ead
|
@ -149,6 +149,35 @@ jobs:
|
||||||
- name: Run simple code
|
- name: Run simple code
|
||||||
run: python -c 'import math; print(math.factorial(5))'
|
run: python -c 'import math; print(math.factorial(5))'
|
||||||
|
|
||||||
|
setup-prerelease-version:
|
||||||
|
name: Setup 3.12 ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: setup-python 3.12
|
||||||
|
id: setup-python
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
python-version: '3.12'
|
||||||
|
allow-prereleases: true
|
||||||
|
|
||||||
|
- name: Check python-path
|
||||||
|
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Validate version
|
||||||
|
run: ${{ startsWith(steps.setup-python.outputs.python-version, '3.12.') }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run simple code
|
||||||
|
run: python -c 'import math; print(math.factorial(5))'
|
||||||
|
|
||||||
setup-versions-noenv:
|
setup-versions-noenv:
|
||||||
name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
|
name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
@ -223,4 +252,4 @@ jobs:
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
$pythonVersion
|
$pythonVersion
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
|
@ -85,6 +85,7 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
|
||||||
- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
|
- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
|
||||||
- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
|
- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
|
||||||
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
|
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
|
||||||
|
- [Allow pre-releases](docs/advanced-usage.md#allow-pre-releases)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,94 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"pypy_version": "7.3.8rc2",
|
||||||
|
"python_version": "3.8.12",
|
||||||
|
"stable": false,
|
||||||
|
"latest_pypy": false,
|
||||||
|
"date": "2022-02-11",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-linux32.tar.bz2",
|
||||||
|
"arch": "i686",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux32.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-linux64.tar.bz2",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux64.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-darwin64.tar.bz2",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "darwin",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-darwin64.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-s390x.tar.bz2",
|
||||||
|
"arch": "s390x",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-s390x.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-win64.zip",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "win64",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win64.zip"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.8-v7.3.8rc2-win32.zip",
|
||||||
|
"arch": "x86",
|
||||||
|
"platform": "win32",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win32.zip"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pypy_version": "7.4.0rc1",
|
||||||
|
"python_version": "3.6.12",
|
||||||
|
"stable": false,
|
||||||
|
"latest_pypy": false,
|
||||||
|
"date": "2021-11-11",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-aarch64.tar.bz2",
|
||||||
|
"arch": "aarch64",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-aarch64.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-linux32.tar.bz2",
|
||||||
|
"arch": "i686",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux32.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-linux64.tar.bz2",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux64.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-darwin64.tar.bz2",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "darwin",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-darwin64.tar.bz2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-win32.zip",
|
||||||
|
"arch": "x86",
|
||||||
|
"platform": "win32",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-win32.zip"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "pypy3.6-v7.4.0rc1-s390x.tar.bz2",
|
||||||
|
"arch": "s390x",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-s390x.tar.bz2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pypy_version": "7.3.3",
|
"pypy_version": "7.3.3",
|
||||||
"python_version": "3.6.12",
|
"python_version": "3.6.12",
|
||||||
|
@ -530,4 +620,4 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,4 +1,29 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "1.2.4-beta.2",
|
||||||
|
"stable": false,
|
||||||
|
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"filename": "sometool-1.2.4-linux-x64.tar.gz",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "linux",
|
||||||
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-linux-x64.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "sometool-1.2.4-darwin-x64.tar.gz",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "darwin",
|
||||||
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-darwin-x64.tar.gz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "sometool-1.2.4-win32-x64.tar.gz",
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "win32",
|
||||||
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-win32-x64.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"stable": true,
|
"stable": true,
|
||||||
|
@ -25,28 +50,28 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"version": "1.2.3-beta.2",
|
"version": "1.1.0-beta.2",
|
||||||
"stable": false,
|
"stable": false,
|
||||||
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5",
|
"release_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5",
|
||||||
"files": [
|
"files": [
|
||||||
{
|
{
|
||||||
"filename": "sometool-1.2.3-linux-x64.tar.gz",
|
"filename": "sometool-1.1.0-linux-x64.tar.gz",
|
||||||
"arch": "x64",
|
"arch": "x64",
|
||||||
"platform": "linux",
|
"platform": "linux",
|
||||||
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5/sometool-1.2.3-linux-x64.tar.gz"
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-linux-x64.tar.gz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "sometool-1.2.3-darwin-x64.tar.gz",
|
"filename": "sometool-1.1.0-darwin-x64.tar.gz",
|
||||||
"arch": "x64",
|
"arch": "x64",
|
||||||
"platform": "darwin",
|
"platform": "darwin",
|
||||||
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-darwin-x64.tar.gz"
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-darwin-x64.tar.gz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "sometool-1.2.3-win32-x64.tar.gz",
|
"filename": "sometool-1.1.0-win32-x64.tar.gz",
|
||||||
"arch": "x64",
|
"arch": "x64",
|
||||||
"platform": "win32",
|
"platform": "win32",
|
||||||
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-win32-x64.tar.gz"
|
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-win32-x64.tar.gz"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -273,7 +273,13 @@ describe('findPyPyVersion', () => {
|
||||||
|
|
||||||
it('found PyPy in toolcache', async () => {
|
it('found PyPy in toolcache', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true, false)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.6-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -291,13 +297,13 @@ describe('findPyPyVersion', () => {
|
||||||
|
|
||||||
it('throw on invalid input format', async () => {
|
it('throw on invalid input format', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false)
|
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false, false)
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throw on invalid input format pypy3.7-7.3.x', async () => {
|
it('throw on invalid input format pypy3.7-7.3.x', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false)
|
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false, false)
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -309,7 +315,13 @@ describe('findPyPyVersion', () => {
|
||||||
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
||||||
spyChmodSync.mockImplementation(() => undefined);
|
spyChmodSync.mockImplementation(() => undefined);
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true, false)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.7-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.7.9',
|
resolvedPythonVersion: '3.7.9',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -333,7 +345,13 @@ describe('findPyPyVersion', () => {
|
||||||
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
||||||
spyChmodSync.mockImplementation(() => undefined);
|
spyChmodSync.mockImplementation(() => undefined);
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, false)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.7-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.7.9',
|
resolvedPythonVersion: '3.7.9',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -344,7 +362,13 @@ describe('findPyPyVersion', () => {
|
||||||
|
|
||||||
it('throw if release is not found', async () => {
|
it('throw if release is not found', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true, false)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.7-v7.5.x',
|
||||||
|
architecture,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
).rejects.toThrowError(
|
).rejects.toThrowError(
|
||||||
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
|
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
|
||||||
);
|
);
|
||||||
|
@ -352,7 +376,13 @@ describe('findPyPyVersion', () => {
|
||||||
|
|
||||||
it('check-latest enabled version found and used from toolcache', async () => {
|
it('check-latest enabled version found and used from toolcache', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, false, true)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.6-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -371,7 +401,13 @@ describe('findPyPyVersion', () => {
|
||||||
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
||||||
spyChmodSync.mockImplementation(() => undefined);
|
spyChmodSync.mockImplementation(() => undefined);
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, true)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.7-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.7.9',
|
resolvedPythonVersion: '3.7.9',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -391,7 +427,13 @@ describe('findPyPyVersion', () => {
|
||||||
return pypyPath;
|
return pypyPath;
|
||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
finder.findPyPyVersion('pypy-3.8-v7.3.x', architecture, false, true)
|
finder.findPyPyVersion(
|
||||||
|
'pypy-3.8-v7.3.x',
|
||||||
|
architecture,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
resolvedPythonVersion: '3.8.8',
|
resolvedPythonVersion: '3.8.8',
|
||||||
resolvedPyPyVersion: '7.3.3'
|
resolvedPyPyVersion: '7.3.3'
|
||||||
|
@ -401,4 +443,22 @@ describe('findPyPyVersion', () => {
|
||||||
'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
|
'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('found and install successfully, pre-release fallback', async () => {
|
||||||
|
spyCacheDir = jest.spyOn(tc, 'cacheDir');
|
||||||
|
spyCacheDir.mockImplementation(() =>
|
||||||
|
path.join(toolDir, 'PyPy', '3.8.12', architecture)
|
||||||
|
);
|
||||||
|
spyChmodSync = jest.spyOn(fs, 'chmodSync');
|
||||||
|
spyChmodSync.mockImplementation(() => undefined);
|
||||||
|
await expect(
|
||||||
|
finder.findPyPyVersion('pypy3.8', architecture, false, false, false)
|
||||||
|
).rejects.toThrowError();
|
||||||
|
await expect(
|
||||||
|
finder.findPyPyVersion('pypy3.8', architecture, false, false, true)
|
||||||
|
).resolves.toEqual({
|
||||||
|
resolvedPythonVersion: '3.8.12',
|
||||||
|
resolvedPyPyVersion: '7.3.8rc2'
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,7 +56,7 @@ describe('Finder tests', () => {
|
||||||
await io.mkdirP(pythonDir);
|
await io.mkdirP(pythonDir);
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
await finder.useCpythonVersion('3.x', 'x64', true, false);
|
await finder.useCpythonVersion('3.x', 'x64', true, false, false);
|
||||||
expect(spyCoreAddPath).toHaveBeenCalled();
|
expect(spyCoreAddPath).toHaveBeenCalled();
|
||||||
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
||||||
'pythonLocation',
|
'pythonLocation',
|
||||||
|
@ -73,7 +73,7 @@ describe('Finder tests', () => {
|
||||||
await io.mkdirP(pythonDir);
|
await io.mkdirP(pythonDir);
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
await finder.useCpythonVersion('3.x', 'x64', false, false);
|
await finder.useCpythonVersion('3.x', 'x64', false, false, false);
|
||||||
expect(spyCoreAddPath).not.toHaveBeenCalled();
|
expect(spyCoreAddPath).not.toHaveBeenCalled();
|
||||||
expect(spyCoreExportVariable).not.toHaveBeenCalled();
|
expect(spyCoreExportVariable).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
@ -95,7 +95,12 @@ describe('Finder tests', () => {
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
});
|
});
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
await finder.useCpythonVersion('1.2.3', 'x64', true, false);
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.2.3', 'x64', true, false, false)
|
||||||
|
).resolves.toEqual({
|
||||||
|
impl: 'CPython',
|
||||||
|
version: '1.2.3'
|
||||||
|
});
|
||||||
expect(spyCoreAddPath).toHaveBeenCalled();
|
expect(spyCoreAddPath).toHaveBeenCalled();
|
||||||
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
||||||
'pythonLocation',
|
'pythonLocation',
|
||||||
|
@ -122,14 +127,19 @@ describe('Finder tests', () => {
|
||||||
const pythonDir: string = path.join(
|
const pythonDir: string = path.join(
|
||||||
toolDir,
|
toolDir,
|
||||||
'Python',
|
'Python',
|
||||||
'1.2.3-beta.2',
|
'1.2.4-beta.2',
|
||||||
'x64'
|
'x64'
|
||||||
);
|
);
|
||||||
await io.mkdirP(pythonDir);
|
await io.mkdirP(pythonDir);
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
});
|
});
|
||||||
// This will throw if it doesn't find it in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the manifest (because no such version exists)
|
||||||
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, false);
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, false, false)
|
||||||
|
).resolves.toEqual({
|
||||||
|
impl: 'CPython',
|
||||||
|
version: '1.2.4-beta.2'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Check-latest true, finds the latest version in the manifest', async () => {
|
it('Check-latest true, finds the latest version in the manifest', async () => {
|
||||||
|
@ -176,7 +186,7 @@ describe('Finder tests', () => {
|
||||||
|
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
await finder.useCpythonVersion('1.2', 'x64', true, true);
|
await finder.useCpythonVersion('1.2', 'x64', true, true, false);
|
||||||
|
|
||||||
expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
|
expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
|
||||||
expect(infoSpy).toHaveBeenCalledWith(
|
expect(infoSpy).toHaveBeenCalledWith(
|
||||||
|
@ -187,7 +197,7 @@ describe('Finder tests', () => {
|
||||||
);
|
);
|
||||||
expect(installSpy).toHaveBeenCalled();
|
expect(installSpy).toHaveBeenCalled();
|
||||||
expect(addPathSpy).toHaveBeenCalledWith(expPath);
|
expect(addPathSpy).toHaveBeenCalledWith(expPath);
|
||||||
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, true);
|
await finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, true, false);
|
||||||
expect(spyCoreAddPath).toHaveBeenCalled();
|
expect(spyCoreAddPath).toHaveBeenCalled();
|
||||||
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
expect(spyCoreExportVariable).toHaveBeenCalledWith(
|
||||||
'pythonLocation',
|
'pythonLocation',
|
||||||
|
@ -199,11 +209,67 @@ describe('Finder tests', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Finds stable Python version if it is not installed, but exists in the manifest, skipping newer pre-release', async () => {
|
||||||
|
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
|
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
||||||
|
|
||||||
|
const installSpy: jest.SpyInstance = jest.spyOn(
|
||||||
|
installer,
|
||||||
|
'installCpythonFromRelease'
|
||||||
|
);
|
||||||
|
installSpy.mockImplementation(async () => {
|
||||||
|
const pythonDir: string = path.join(toolDir, 'Python', '1.2.3', 'x64');
|
||||||
|
await io.mkdirP(pythonDir);
|
||||||
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
|
});
|
||||||
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.2', 'x64', false, false, false)
|
||||||
|
).resolves.toEqual({
|
||||||
|
impl: 'CPython',
|
||||||
|
version: '1.2.3'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Finds Python version if it is not installed, but exists in the manifest, pre-release fallback', async () => {
|
||||||
|
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
|
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
||||||
|
|
||||||
|
const installSpy: jest.SpyInstance = jest.spyOn(
|
||||||
|
installer,
|
||||||
|
'installCpythonFromRelease'
|
||||||
|
);
|
||||||
|
installSpy.mockImplementation(async () => {
|
||||||
|
const pythonDir: string = path.join(
|
||||||
|
toolDir,
|
||||||
|
'Python',
|
||||||
|
'1.1.0-beta.2',
|
||||||
|
'x64'
|
||||||
|
);
|
||||||
|
await io.mkdirP(pythonDir);
|
||||||
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
|
});
|
||||||
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.1', 'x64', false, false, false)
|
||||||
|
).rejects.toThrowError();
|
||||||
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.1', 'x64', false, false, true)
|
||||||
|
).resolves.toEqual({
|
||||||
|
impl: 'CPython',
|
||||||
|
version: '1.1.0-beta.2'
|
||||||
|
});
|
||||||
|
// Check 1.1.0 version specifier does not fallback to '1.1.0-beta.2'
|
||||||
|
await expect(
|
||||||
|
finder.useCpythonVersion('1.1.0', 'x64', false, false, true)
|
||||||
|
).rejects.toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
it('Errors if Python is not installed', async () => {
|
it('Errors if Python is not installed', async () => {
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
let thrown = false;
|
let thrown = false;
|
||||||
try {
|
try {
|
||||||
await finder.useCpythonVersion('3.300000', 'x64', true, false);
|
await finder.useCpythonVersion('3.300000', 'x64', true, false, false);
|
||||||
} catch {
|
} catch {
|
||||||
thrown = true;
|
thrown = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,12 @@ describe('findRelease', () => {
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}`
|
download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}`
|
||||||
};
|
};
|
||||||
|
const filesRC1: IPyPyManifestAsset = {
|
||||||
|
filename: `pypy3.6-v7.4.0rc1-${extensionName}`,
|
||||||
|
arch: architecture,
|
||||||
|
platform: process.platform,
|
||||||
|
download_url: `https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-${extensionName}`
|
||||||
|
};
|
||||||
|
|
||||||
let getBooleanInputSpy: jest.SpyInstance;
|
let getBooleanInputSpy: jest.SpyInstance;
|
||||||
let warningSpy: jest.SpyInstance;
|
let warningSpy: jest.SpyInstance;
|
||||||
|
@ -72,7 +78,13 @@ describe('findRelease', () => {
|
||||||
const pythonVersion = '3.6';
|
const pythonVersion = '3.6';
|
||||||
const pypyVersion = '7.3.7';
|
const pypyVersion = '7.3.7';
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual(null);
|
).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,7 +92,13 @@ describe('findRelease', () => {
|
||||||
const pythonVersion = '3.6';
|
const pythonVersion = '3.6';
|
||||||
const pypyVersion = '7.3.3';
|
const pypyVersion = '7.3.3';
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
foundAsset: files,
|
foundAsset: files,
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
@ -92,7 +110,13 @@ describe('findRelease', () => {
|
||||||
const pythonVersion = '3.6';
|
const pythonVersion = '3.6';
|
||||||
const pypyVersion = '7.x';
|
const pypyVersion = '7.x';
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
foundAsset: files,
|
foundAsset: files,
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
@ -104,7 +128,13 @@ describe('findRelease', () => {
|
||||||
const pythonVersion = '3.7';
|
const pythonVersion = '3.7';
|
||||||
const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2');
|
const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2');
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
foundAsset: {
|
foundAsset: {
|
||||||
filename: `test${extension}`,
|
filename: `test${extension}`,
|
||||||
|
@ -121,7 +151,13 @@ describe('findRelease', () => {
|
||||||
const pythonVersion = '3.6';
|
const pythonVersion = '3.6';
|
||||||
const pypyVersion = 'x';
|
const pypyVersion = 'x';
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
foundAsset: files,
|
foundAsset: files,
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
@ -129,12 +165,45 @@ describe('findRelease', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Python version and PyPy version matches semver (pre-release)', () => {
|
||||||
|
const pythonVersion = '3.6';
|
||||||
|
const pypyVersion = '7.4.x';
|
||||||
|
expect(
|
||||||
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
).toBeNull();
|
||||||
|
expect(
|
||||||
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
).toEqual({
|
||||||
|
foundAsset: filesRC1,
|
||||||
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
resolvedPyPyVersion: '7.4.0rc1'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Nightly release is found', () => {
|
it('Nightly release is found', () => {
|
||||||
const pythonVersion = '3.6';
|
const pythonVersion = '3.6';
|
||||||
const pypyVersion = 'nightly';
|
const pypyVersion = 'nightly';
|
||||||
const filename = IS_WINDOWS ? 'filename.zip' : 'filename.tar.bz2';
|
const filename = IS_WINDOWS ? 'filename.zip' : 'filename.tar.bz2';
|
||||||
expect(
|
expect(
|
||||||
installer.findRelease(releases, pythonVersion, pypyVersion, architecture)
|
installer.findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
false
|
||||||
|
)
|
||||||
).toEqual({
|
).toEqual({
|
||||||
foundAsset: {
|
foundAsset: {
|
||||||
filename: filename,
|
filename: filename,
|
||||||
|
@ -224,7 +293,7 @@ describe('installPyPy', () => {
|
||||||
|
|
||||||
it('throw if release is not found', async () => {
|
it('throw if release is not found', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
installer.installPyPy('7.3.3', '3.6.17', architecture, undefined)
|
installer.installPyPy('7.3.3', '3.6.17', architecture, false, undefined)
|
||||||
).rejects.toThrowError(
|
).rejects.toThrowError(
|
||||||
`PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found`
|
`PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found`
|
||||||
);
|
);
|
||||||
|
@ -244,7 +313,7 @@ describe('installPyPy', () => {
|
||||||
spyChmodSync.mockImplementation(() => undefined);
|
spyChmodSync.mockImplementation(() => undefined);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
installer.installPyPy('7.3.x', '3.6.12', architecture, undefined)
|
installer.installPyPy('7.x', '3.6.12', architecture, false, undefined)
|
||||||
).resolves.toEqual({
|
).resolves.toEqual({
|
||||||
installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
|
installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
|
||||||
resolvedPythonVersion: '3.6.12',
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
@ -257,4 +326,31 @@ describe('installPyPy', () => {
|
||||||
expect(spyCacheDir).toHaveBeenCalled();
|
expect(spyCacheDir).toHaveBeenCalled();
|
||||||
expect(spyExec).toHaveBeenCalled();
|
expect(spyExec).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('found and install PyPy, pre-release fallback', 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.4.x', '3.6.12', architecture, false, undefined)
|
||||||
|
).rejects.toThrowError();
|
||||||
|
await expect(
|
||||||
|
installer.installPyPy('7.4.x', '3.6.12', architecture, true, undefined)
|
||||||
|
).resolves.toEqual({
|
||||||
|
installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
|
||||||
|
resolvedPythonVersion: '3.6.12',
|
||||||
|
resolvedPyPyVersion: '7.4.0rc1'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spyHttpClient).toHaveBeenCalled();
|
||||||
|
expect(spyDownloadTool).toHaveBeenCalled();
|
||||||
|
expect(spyExistsSync).toHaveBeenCalled();
|
||||||
|
expect(spyCacheDir).toHaveBeenCalled();
|
||||||
|
expect(spyExec).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,9 @@ inputs:
|
||||||
update-environment:
|
update-environment:
|
||||||
description: "Set this option if you want the action to update environment variables."
|
description: "Set this option if you want the action to update environment variables."
|
||||||
default: true
|
default: true
|
||||||
|
allow-prereleases:
|
||||||
|
description: "When 'true', a version range passed to 'python-version' input will match prerelease versions if no GA versions are found. Only 'x.y' version range is supported for CPython."
|
||||||
|
default: false
|
||||||
outputs:
|
outputs:
|
||||||
python-version:
|
python-version:
|
||||||
description: "The installed Python or PyPy version. Useful when given a version range as input."
|
description: "The installed Python or PyPy version. Useful when given a version range as input."
|
||||||
|
|
|
@ -66237,7 +66237,7 @@ const utils_1 = __nccwpck_require__(1314);
|
||||||
const semver = __importStar(__nccwpck_require__(1383));
|
const semver = __importStar(__nccwpck_require__(1383));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const tc = __importStar(__nccwpck_require__(7784));
|
const tc = __importStar(__nccwpck_require__(7784));
|
||||||
function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLatest) {
|
function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLatest, allowPreReleases) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let resolvedPyPyVersion = '';
|
let resolvedPyPyVersion = '';
|
||||||
let resolvedPythonVersion = '';
|
let resolvedPythonVersion = '';
|
||||||
|
@ -66247,7 +66247,7 @@ function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLate
|
||||||
if (checkLatest) {
|
if (checkLatest) {
|
||||||
releases = yield pypyInstall.getAvailablePyPyVersions();
|
releases = yield pypyInstall.getAvailablePyPyVersions();
|
||||||
if (releases && releases.length > 0) {
|
if (releases && releases.length > 0) {
|
||||||
const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture);
|
const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture, false);
|
||||||
if (releaseData) {
|
if (releaseData) {
|
||||||
core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`);
|
core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`);
|
||||||
pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
|
pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
|
||||||
|
@ -66264,7 +66264,7 @@ function findPyPyVersion(versionSpec, architecture, updateEnvironment, checkLate
|
||||||
installDir,
|
installDir,
|
||||||
resolvedPythonVersion,
|
resolvedPythonVersion,
|
||||||
resolvedPyPyVersion
|
resolvedPyPyVersion
|
||||||
} = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture, releases));
|
} = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture, allowPreReleases, releases));
|
||||||
}
|
}
|
||||||
const pipDir = utils_1.IS_WINDOWS ? 'Scripts' : 'bin';
|
const pipDir = utils_1.IS_WINDOWS ? 'Scripts' : 'bin';
|
||||||
const _binDir = path.join(installDir, pipDir);
|
const _binDir = path.join(installDir, pipDir);
|
||||||
|
@ -66414,12 +66414,12 @@ function binDir(installDir) {
|
||||||
return path.join(installDir, 'bin');
|
return path.join(installDir, 'bin');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function useCpythonVersion(version, architecture, updateEnvironment, checkLatest) {
|
function useCpythonVersion(version, architecture, updateEnvironment, checkLatest, allowPreReleases) {
|
||||||
var _a;
|
var _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let manifest = null;
|
let manifest = null;
|
||||||
const desugaredVersionSpec = desugarDevVersion(version);
|
const desugaredVersionSpec = desugarDevVersion(version);
|
||||||
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec, allowPreReleases);
|
||||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||||
if (checkLatest) {
|
if (checkLatest) {
|
||||||
manifest = yield installer.getManifest();
|
manifest = yield installer.getManifest();
|
||||||
|
@ -66510,10 +66510,17 @@ function versionFromPath(installDir) {
|
||||||
* Python's prelease versions look like `3.7.0b2`.
|
* Python's prelease versions look like `3.7.0b2`.
|
||||||
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
||||||
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
||||||
|
*
|
||||||
|
* For easier use of the action, we also map 'x.y' to allow pre-release before 'x.y.0' release if allowPreReleases is true
|
||||||
*/
|
*/
|
||||||
function pythonVersionToSemantic(versionSpec) {
|
function pythonVersionToSemantic(versionSpec, allowPreReleases) {
|
||||||
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
||||||
return versionSpec.replace(prereleaseVersion, '$1-$2');
|
const majorMinor = /^(\d+)\.(\d+)$/;
|
||||||
|
let result = versionSpec.replace(prereleaseVersion, '$1-$2');
|
||||||
|
if (allowPreReleases) {
|
||||||
|
result = result.replace(majorMinor, '~$1.$2.0-0');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
exports.pythonVersionToSemantic = pythonVersionToSemantic;
|
exports.pythonVersionToSemantic = pythonVersionToSemantic;
|
||||||
|
|
||||||
|
@ -66558,6 +66565,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = exports.getAvailablePyPyVersions = exports.installPyPy = void 0;
|
exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = exports.getAvailablePyPyVersions = exports.installPyPy = void 0;
|
||||||
|
const os = __importStar(__nccwpck_require__(2037));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const tc = __importStar(__nccwpck_require__(7784));
|
const tc = __importStar(__nccwpck_require__(7784));
|
||||||
|
@ -66566,14 +66574,22 @@ const httpm = __importStar(__nccwpck_require__(9925));
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||||
const utils_1 = __nccwpck_require__(1314);
|
const utils_1 = __nccwpck_require__(1314);
|
||||||
function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
|
function installPyPy(pypyVersion, pythonVersion, architecture, allowPreReleases, releases) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let downloadDir;
|
let downloadDir;
|
||||||
releases = releases !== null && releases !== void 0 ? releases : (yield getAvailablePyPyVersions());
|
releases = releases !== null && releases !== void 0 ? releases : (yield getAvailablePyPyVersions());
|
||||||
if (!releases || releases.length === 0) {
|
if (!releases || releases.length === 0) {
|
||||||
throw new Error('No release was found in PyPy version.json');
|
throw new Error('No release was found in PyPy version.json');
|
||||||
}
|
}
|
||||||
const releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture);
|
let releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture, false);
|
||||||
|
if (allowPreReleases && (!releaseData || !releaseData.foundAsset)) {
|
||||||
|
// check for pre-release
|
||||||
|
core.info([
|
||||||
|
`Stable PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`,
|
||||||
|
`Trying pre-release versions`
|
||||||
|
].join(os.EOL));
|
||||||
|
releaseData = findRelease(releases, pythonVersion, pypyVersion, architecture, true);
|
||||||
|
}
|
||||||
if (!releaseData || !releaseData.foundAsset) {
|
if (!releaseData || !releaseData.foundAsset) {
|
||||||
throw new Error(`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`);
|
throw new Error(`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`);
|
||||||
}
|
}
|
||||||
|
@ -66656,12 +66672,13 @@ function installPip(pythonLocation) {
|
||||||
yield exec.exec(`${pythonLocation}/python -m pip install --ignore-installed pip`);
|
yield exec.exec(`${pythonLocation}/python -m pip install --ignore-installed pip`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function findRelease(releases, pythonVersion, pypyVersion, architecture) {
|
function findRelease(releases, pythonVersion, pypyVersion, architecture, includePrerelease) {
|
||||||
|
const options = { includePrerelease: includePrerelease };
|
||||||
const filterReleases = releases.filter(item => {
|
const filterReleases = releases.filter(item => {
|
||||||
const isPythonVersionSatisfied = semver.satisfies(semver.coerce(item.python_version), pythonVersion);
|
const isPythonVersionSatisfied = semver.satisfies(semver.coerce(item.python_version), pythonVersion);
|
||||||
const isPyPyNightly = utils_1.isNightlyKeyword(pypyVersion) && utils_1.isNightlyKeyword(item.pypy_version);
|
const isPyPyNightly = utils_1.isNightlyKeyword(pypyVersion) && utils_1.isNightlyKeyword(item.pypy_version);
|
||||||
const isPyPyVersionSatisfied = isPyPyNightly ||
|
const isPyPyVersionSatisfied = isPyPyNightly ||
|
||||||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
|
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion, options);
|
||||||
const isArchPresent = item.files &&
|
const isArchPresent = item.files &&
|
||||||
(utils_1.IS_WINDOWS
|
(utils_1.IS_WINDOWS
|
||||||
? isArchPresentForWindows(item, architecture)
|
? isArchPresentForWindows(item, architecture)
|
||||||
|
@ -66948,6 +66965,7 @@ function run() {
|
||||||
try {
|
try {
|
||||||
const versions = resolveVersionInput();
|
const versions = resolveVersionInput();
|
||||||
const checkLatest = core.getBooleanInput('check-latest');
|
const checkLatest = core.getBooleanInput('check-latest');
|
||||||
|
const allowPreReleases = core.getBooleanInput('allow-prereleases');
|
||||||
if (versions.length) {
|
if (versions.length) {
|
||||||
let pythonVersion = '';
|
let pythonVersion = '';
|
||||||
const arch = core.getInput('architecture') || os.arch();
|
const arch = core.getInput('architecture') || os.arch();
|
||||||
|
@ -66955,12 +66973,12 @@ function run() {
|
||||||
core.startGroup('Installed versions');
|
core.startGroup('Installed versions');
|
||||||
for (const version of versions) {
|
for (const version of versions) {
|
||||||
if (isPyPyVersion(version)) {
|
if (isPyPyVersion(version)) {
|
||||||
const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest);
|
const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest, allowPreReleases);
|
||||||
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
|
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
|
||||||
core.info(`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`);
|
core.info(`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment, checkLatest);
|
const installed = yield finder.useCpythonVersion(version, arch, updateEnvironment, checkLatest, allowPreReleases);
|
||||||
pythonVersion = installed.version;
|
pythonVersion = installed.version;
|
||||||
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
- [Linux](advanced-usage.md#linux)
|
- [Linux](advanced-usage.md#linux)
|
||||||
- [macOS](advanced-usage.md#macos)
|
- [macOS](advanced-usage.md#macos)
|
||||||
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
|
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
|
||||||
|
- [Allow pre-releases](advanced-usage.md#allow-pre-releases)
|
||||||
|
|
||||||
## Using the `python-version` input
|
## Using the `python-version` input
|
||||||
|
|
||||||
|
@ -568,3 +569,31 @@ Requests should now be authenticated. To verify that you are getting the higher
|
||||||
|
|
||||||
### No access to github.com
|
### No access to github.com
|
||||||
If the runner is not able to access github.com, any Python versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server@3.2/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.
|
If the runner is not able to access github.com, any Python versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server@3.2/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.
|
||||||
|
|
||||||
|
|
||||||
|
## Allow pre-releases
|
||||||
|
|
||||||
|
The `allow-prereleases` flag defaults to `false`.
|
||||||
|
If `allow-prereleases` is set to `true`, the action will allow falling back to pre-release versions of Python when a matching GA version of Python is not available.
|
||||||
|
This allows for example to simplify reuse of `python-version` as an input of nox for pre-releases of Python by not requiring manipulation of the `3.y-dev` specifier.
|
||||||
|
For CPython, `allow-prereleases` will only have effect for `x.y` version range (e.g. `3.12`).
|
||||||
|
Let's say that python 3.12 is not generally available, the following workflow will fallback to the most recent pre-release of python 3.12:
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: ${{ matrix.os }} / ${{ matrix.python_version }}
|
||||||
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [Ubuntu, Windows, macOS]
|
||||||
|
python_version: ["3.11", "3.12"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "${{ matrix.python_version }}"
|
||||||
|
- run: pipx run nox --error-on-missing-interpreters -s tests-${{ matrix.python_version }}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ export async function findPyPyVersion(
|
||||||
versionSpec: string,
|
versionSpec: string,
|
||||||
architecture: string,
|
architecture: string,
|
||||||
updateEnvironment: boolean,
|
updateEnvironment: boolean,
|
||||||
checkLatest: boolean
|
checkLatest: boolean,
|
||||||
|
allowPreReleases: boolean
|
||||||
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
|
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
|
||||||
let resolvedPyPyVersion = '';
|
let resolvedPyPyVersion = '';
|
||||||
let resolvedPythonVersion = '';
|
let resolvedPythonVersion = '';
|
||||||
|
@ -39,7 +40,8 @@ export async function findPyPyVersion(
|
||||||
releases,
|
releases,
|
||||||
pypyVersionSpec.pythonVersion,
|
pypyVersionSpec.pythonVersion,
|
||||||
pypyVersionSpec.pypyVersion,
|
pypyVersionSpec.pypyVersion,
|
||||||
architecture
|
architecture,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
if (releaseData) {
|
if (releaseData) {
|
||||||
|
@ -71,6 +73,7 @@ export async function findPyPyVersion(
|
||||||
pypyVersionSpec.pypyVersion,
|
pypyVersionSpec.pypyVersion,
|
||||||
pypyVersionSpec.pythonVersion,
|
pypyVersionSpec.pythonVersion,
|
||||||
architecture,
|
architecture,
|
||||||
|
allowPreReleases,
|
||||||
releases
|
releases
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,15 @@ export async function useCpythonVersion(
|
||||||
version: string,
|
version: string,
|
||||||
architecture: string,
|
architecture: string,
|
||||||
updateEnvironment: boolean,
|
updateEnvironment: boolean,
|
||||||
checkLatest: boolean
|
checkLatest: boolean,
|
||||||
|
allowPreReleases: boolean
|
||||||
): Promise<InstalledVersion> {
|
): Promise<InstalledVersion> {
|
||||||
let manifest: tc.IToolRelease[] | null = null;
|
let manifest: tc.IToolRelease[] | null = null;
|
||||||
const desugaredVersionSpec = desugarDevVersion(version);
|
const desugaredVersionSpec = desugarDevVersion(version);
|
||||||
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
let semanticVersionSpec = pythonVersionToSemantic(
|
||||||
|
desugaredVersionSpec,
|
||||||
|
allowPreReleases
|
||||||
|
);
|
||||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||||
|
|
||||||
if (checkLatest) {
|
if (checkLatest) {
|
||||||
|
@ -178,8 +182,18 @@ interface InstalledVersion {
|
||||||
* Python's prelease versions look like `3.7.0b2`.
|
* Python's prelease versions look like `3.7.0b2`.
|
||||||
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
|
||||||
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
|
||||||
|
*
|
||||||
|
* For easier use of the action, we also map 'x.y' to allow pre-release before 'x.y.0' release if allowPreReleases is true
|
||||||
*/
|
*/
|
||||||
export function pythonVersionToSemantic(versionSpec: string) {
|
export function pythonVersionToSemantic(
|
||||||
|
versionSpec: string,
|
||||||
|
allowPreReleases: boolean
|
||||||
|
) {
|
||||||
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
|
||||||
return versionSpec.replace(prereleaseVersion, '$1-$2');
|
const majorMinor = /^(\d+)\.(\d+)$/;
|
||||||
|
let result = versionSpec.replace(prereleaseVersion, '$1-$2');
|
||||||
|
if (allowPreReleases) {
|
||||||
|
result = result.replace(majorMinor, '~$1.$2.0-0');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
|
@ -19,6 +20,7 @@ export async function installPyPy(
|
||||||
pypyVersion: string,
|
pypyVersion: string,
|
||||||
pythonVersion: string,
|
pythonVersion: string,
|
||||||
architecture: string,
|
architecture: string,
|
||||||
|
allowPreReleases: boolean,
|
||||||
releases: IPyPyManifestRelease[] | undefined
|
releases: IPyPyManifestRelease[] | undefined
|
||||||
) {
|
) {
|
||||||
let downloadDir;
|
let downloadDir;
|
||||||
|
@ -29,13 +31,31 @@ export async function installPyPy(
|
||||||
throw new Error('No release was found in PyPy version.json');
|
throw new Error('No release was found in PyPy version.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
const releaseData = findRelease(
|
let releaseData = findRelease(
|
||||||
releases,
|
releases,
|
||||||
pythonVersion,
|
pythonVersion,
|
||||||
pypyVersion,
|
pypyVersion,
|
||||||
architecture
|
architecture,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (allowPreReleases && (!releaseData || !releaseData.foundAsset)) {
|
||||||
|
// check for pre-release
|
||||||
|
core.info(
|
||||||
|
[
|
||||||
|
`Stable PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`,
|
||||||
|
`Trying pre-release versions`
|
||||||
|
].join(os.EOL)
|
||||||
|
);
|
||||||
|
releaseData = findRelease(
|
||||||
|
releases,
|
||||||
|
pythonVersion,
|
||||||
|
pypyVersion,
|
||||||
|
architecture,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!releaseData || !releaseData.foundAsset) {
|
if (!releaseData || !releaseData.foundAsset) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`
|
`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`
|
||||||
|
@ -162,8 +182,10 @@ export function findRelease(
|
||||||
releases: IPyPyManifestRelease[],
|
releases: IPyPyManifestRelease[],
|
||||||
pythonVersion: string,
|
pythonVersion: string,
|
||||||
pypyVersion: string,
|
pypyVersion: string,
|
||||||
architecture: string
|
architecture: string,
|
||||||
|
includePrerelease: boolean
|
||||||
) {
|
) {
|
||||||
|
const options = {includePrerelease: includePrerelease};
|
||||||
const filterReleases = releases.filter(item => {
|
const filterReleases = releases.filter(item => {
|
||||||
const isPythonVersionSatisfied = semver.satisfies(
|
const isPythonVersionSatisfied = semver.satisfies(
|
||||||
semver.coerce(item.python_version)!,
|
semver.coerce(item.python_version)!,
|
||||||
|
@ -173,7 +195,11 @@ export function findRelease(
|
||||||
isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version);
|
isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version);
|
||||||
const isPyPyVersionSatisfied =
|
const isPyPyVersionSatisfied =
|
||||||
isPyPyNightly ||
|
isPyPyNightly ||
|
||||||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
|
semver.satisfies(
|
||||||
|
pypyVersionToSemantic(item.pypy_version),
|
||||||
|
pypyVersion,
|
||||||
|
options
|
||||||
|
);
|
||||||
const isArchPresent =
|
const isArchPresent =
|
||||||
item.files &&
|
item.files &&
|
||||||
(IS_WINDOWS
|
(IS_WINDOWS
|
||||||
|
|
|
@ -77,6 +77,7 @@ async function run() {
|
||||||
try {
|
try {
|
||||||
const versions = resolveVersionInput();
|
const versions = resolveVersionInput();
|
||||||
const checkLatest = core.getBooleanInput('check-latest');
|
const checkLatest = core.getBooleanInput('check-latest');
|
||||||
|
const allowPreReleases = core.getBooleanInput('allow-prereleases');
|
||||||
|
|
||||||
if (versions.length) {
|
if (versions.length) {
|
||||||
let pythonVersion = '';
|
let pythonVersion = '';
|
||||||
|
@ -89,7 +90,8 @@ async function run() {
|
||||||
version,
|
version,
|
||||||
arch,
|
arch,
|
||||||
updateEnvironment,
|
updateEnvironment,
|
||||||
checkLatest
|
checkLatest,
|
||||||
|
allowPreReleases
|
||||||
);
|
);
|
||||||
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
|
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
|
||||||
core.info(
|
core.info(
|
||||||
|
@ -100,7 +102,8 @@ async function run() {
|
||||||
version,
|
version,
|
||||||
arch,
|
arch,
|
||||||
updateEnvironment,
|
updateEnvironment,
|
||||||
checkLatest
|
checkLatest,
|
||||||
|
allowPreReleases
|
||||||
);
|
);
|
||||||
pythonVersion = installed.version;
|
pythonVersion = installed.version;
|
||||||
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
||||||
|
|
Loading…
Reference in New Issue