Skip to content

Commit 8156cbe

Browse files
committed
feature: fallback to pre-release when no stable version is found
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`)
1 parent 98c991d commit 8156cbe

9 files changed

+354
-32
lines changed

__tests__/data/pypy.json

+85-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,88 @@
11
[
2+
{
3+
"pypy_version": "7.3.8rc2",
4+
"python_version": "3.8.12",
5+
"stable": false,
6+
"latest_pypy": false,
7+
"date": "2022-02-11",
8+
"files": [
9+
{
10+
"filename": "pypy3.8-v7.3.8rc2-linux32.tar.bz2",
11+
"arch": "i686",
12+
"platform": "linux",
13+
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux32.tar.bz2"
14+
},
15+
{
16+
"filename": "pypy3.8-v7.3.8rc2-linux64.tar.bz2",
17+
"arch": "x64",
18+
"platform": "linux",
19+
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux64.tar.bz2"
20+
},
21+
{
22+
"filename": "pypy3.8-v7.3.8rc2-darwin64.tar.bz2",
23+
"arch": "x64",
24+
"platform": "darwin",
25+
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-darwin64.tar.bz2"
26+
},
27+
{
28+
"filename": "pypy3.8-v7.3.8rc2-s390x.tar.bz2",
29+
"arch": "s390x",
30+
"platform": "linux",
31+
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-s390x.tar.bz2"
32+
},
33+
{
34+
"filename": "pypy3.8-v7.3.8rc2-win64.zip",
35+
"arch": "x64",
36+
"platform": "win64",
37+
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win64.zip"
38+
}
39+
]
40+
},
41+
{
42+
"pypy_version": "7.4.0rc1",
43+
"python_version": "3.6.12",
44+
"stable": false,
45+
"latest_pypy": false,
46+
"date": "2021-11-11",
47+
"files": [
48+
{
49+
"filename": "pypy3.6-v7.4.0rc1-aarch64.tar.bz2",
50+
"arch": "aarch64",
51+
"platform": "linux",
52+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-aarch64.tar.bz2"
53+
},
54+
{
55+
"filename": "pypy3.6-v7.4.0rc1-linux32.tar.bz2",
56+
"arch": "i686",
57+
"platform": "linux",
58+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux32.tar.bz2"
59+
},
60+
{
61+
"filename": "pypy3.6-v7.4.0rc1-linux64.tar.bz2",
62+
"arch": "x64",
63+
"platform": "linux",
64+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux64.tar.bz2"
65+
},
66+
{
67+
"filename": "pypy3.6-v7.4.0rc1-darwin64.tar.bz2",
68+
"arch": "x64",
69+
"platform": "darwin",
70+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-darwin64.tar.bz2"
71+
},
72+
{
73+
"filename": "pypy3.6-v7.4.0rc1-win32.zip",
74+
"arch": "x86",
75+
"platform": "win32",
76+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-win32.zip"
77+
},
78+
{
79+
"filename": "pypy3.6-v7.4.0rc1-s390x.tar.bz2",
80+
"arch": "s390x",
81+
"platform": "linux",
82+
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-s390x.tar.bz2"
83+
}
84+
]
85+
},
286
{
387
"pypy_version": "7.3.3",
488
"python_version": "3.6.12",
@@ -530,4 +614,4 @@
530614
}
531615
]
532616
}
533-
]
617+
]

__tests__/data/versions-manifest.json

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
11
[
2+
{
3+
"version": "1.2.4-beta.2",
4+
"stable": false,
5+
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5",
6+
"files": [
7+
{
8+
"filename": "sometool-1.2.4-linux-x64.tar.gz",
9+
"arch": "x64",
10+
"platform": "linux",
11+
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-linux-x64.tar.gz"
12+
},
13+
{
14+
"filename": "sometool-1.2.4-darwin-x64.tar.gz",
15+
"arch": "x64",
16+
"platform": "darwin",
17+
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-darwin-x64.tar.gz"
18+
},
19+
{
20+
"filename": "sometool-1.2.4-win32-x64.tar.gz",
21+
"arch": "x64",
22+
"platform": "win32",
23+
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-win32-x64.tar.gz"
24+
}
25+
]
26+
},
227
{
328
"version": "1.2.3",
429
"stable": true,
@@ -25,28 +50,28 @@
2550
]
2651
},
2752
{
28-
"version": "1.2.3-beta.2",
53+
"version": "1.1.0-beta.2",
2954
"stable": false,
30-
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5",
55+
"release_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5",
3156
"files": [
3257
{
33-
"filename": "sometool-1.2.3-linux-x64.tar.gz",
58+
"filename": "sometool-1.1.0-linux-x64.tar.gz",
3459
"arch": "x64",
3560
"platform": "linux",
36-
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5/sometool-1.2.3-linux-x64.tar.gz"
61+
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-linux-x64.tar.gz"
3762
},
3863
{
39-
"filename": "sometool-1.2.3-darwin-x64.tar.gz",
64+
"filename": "sometool-1.1.0-darwin-x64.tar.gz",
4065
"arch": "x64",
4166
"platform": "darwin",
42-
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-darwin-x64.tar.gz"
67+
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-darwin-x64.tar.gz"
4368
},
4469
{
45-
"filename": "sometool-1.2.3-win32-x64.tar.gz",
70+
"filename": "sometool-1.1.0-win32-x64.tar.gz",
4671
"arch": "x64",
4772
"platform": "win32",
48-
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-win32-x64.tar.gz"
73+
"download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-win32-x64.tar.gz"
4974
}
5075
]
5176
}
52-
]
77+
]

__tests__/find-pypy.test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -401,4 +401,19 @@ describe('findPyPyVersion', () => {
401401
'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
402402
);
403403
});
404+
405+
it('found and install successfully, pre-release fallback', async () => {
406+
spyCacheDir = jest.spyOn(tc, 'cacheDir');
407+
spyCacheDir.mockImplementation(() =>
408+
path.join(toolDir, 'PyPy', '3.8.12', architecture)
409+
);
410+
spyChmodSync = jest.spyOn(fs, 'chmodSync');
411+
spyChmodSync.mockImplementation(() => undefined);
412+
await expect(
413+
finder.findPyPyVersion('pypy3.8', architecture, false, false)
414+
).resolves.toEqual({
415+
resolvedPythonVersion: '3.8.12',
416+
resolvedPyPyVersion: '7.3.8rc2'
417+
});
418+
});
404419
});

__tests__/finder.test.ts

+63-4
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,12 @@ describe('Finder tests', () => {
9595
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
9696
});
9797
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
98-
await finder.useCpythonVersion('1.2.3', 'x64', true, false);
98+
await expect(
99+
finder.useCpythonVersion('1.2.3', 'x64', true, false)
100+
).resolves.toEqual({
101+
impl: 'CPython',
102+
version: '1.2.3'
103+
});
99104
expect(spyCoreAddPath).toHaveBeenCalled();
100105
expect(spyCoreExportVariable).toHaveBeenCalledWith(
101106
'pythonLocation',
@@ -122,14 +127,19 @@ describe('Finder tests', () => {
122127
const pythonDir: string = path.join(
123128
toolDir,
124129
'Python',
125-
'1.2.3-beta.2',
130+
'1.2.4-beta.2',
126131
'x64'
127132
);
128133
await io.mkdirP(pythonDir);
129134
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
130135
});
131136
// This will throw if it doesn't find it in the manifest (because no such version exists)
132-
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, false);
137+
await expect(
138+
finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, false)
139+
).resolves.toEqual({
140+
impl: 'CPython',
141+
version: '1.2.4-beta.2'
142+
});
133143
});
134144

135145
it('Check-latest true, finds the latest version in the manifest', async () => {
@@ -187,7 +197,7 @@ describe('Finder tests', () => {
187197
);
188198
expect(installSpy).toHaveBeenCalled();
189199
expect(addPathSpy).toHaveBeenCalledWith(expPath);
190-
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, true);
200+
await finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, true);
191201
expect(spyCoreAddPath).toHaveBeenCalled();
192202
expect(spyCoreExportVariable).toHaveBeenCalledWith(
193203
'pythonLocation',
@@ -199,6 +209,55 @@ describe('Finder tests', () => {
199209
);
200210
});
201211

212+
it('Finds stable Python version if it is not installed, but exists in the manifest, skipping newer pre-release', async () => {
213+
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
214+
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
215+
216+
const installSpy: jest.SpyInstance = jest.spyOn(
217+
installer,
218+
'installCpythonFromRelease'
219+
);
220+
installSpy.mockImplementation(async () => {
221+
const pythonDir: string = path.join(toolDir, 'Python', '1.2.3', 'x64');
222+
await io.mkdirP(pythonDir);
223+
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
224+
});
225+
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
226+
await expect(
227+
finder.useCpythonVersion('1.2', 'x64', false, false)
228+
).resolves.toEqual({
229+
impl: 'CPython',
230+
version: '1.2.3'
231+
});
232+
});
233+
234+
it('Finds Python version if it is not installed, but exists in the manifest, pre-release fallback', async () => {
235+
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
236+
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
237+
238+
const installSpy: jest.SpyInstance = jest.spyOn(
239+
installer,
240+
'installCpythonFromRelease'
241+
);
242+
installSpy.mockImplementation(async () => {
243+
const pythonDir: string = path.join(
244+
toolDir,
245+
'Python',
246+
'1.1.0-beta.2',
247+
'x64'
248+
);
249+
await io.mkdirP(pythonDir);
250+
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
251+
});
252+
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
253+
await expect(
254+
finder.useCpythonVersion('1.1', 'x64', false, false)
255+
).resolves.toEqual({
256+
impl: 'CPython',
257+
version: '1.1.0-beta.2'
258+
});
259+
});
260+
202261
it('Errors if Python is not installed', async () => {
203262
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
204263
let thrown = false;

0 commit comments

Comments
 (0)