Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
58a8109
add check-latest for python versions
dmitry-shibanov May 4, 2022
8723b8a
add check-latest for pypy
dmitry-shibanov May 6, 2022
7339590
add check-latest to the documentation
dmitry-shibanov May 9, 2022
381a73b
add licenses
dmitry-shibanov May 9, 2022
62079db
fix tests
dmitry-shibanov May 9, 2022
4841389
add check-latest for python versions
dmitry-shibanov May 4, 2022
73adf61
add check-latest for pypy
dmitry-shibanov May 6, 2022
71940d6
add check-latest to the documentation
dmitry-shibanov May 9, 2022
5dd8329
add licenses
dmitry-shibanov May 9, 2022
ee3a254
fix tests
dmitry-shibanov May 9, 2022
f50cbbf
Merge branch 'v-dmshib/add-check-latest' of https://github.com/dmitry…
dmitry-shibanov May 9, 2022
ca41e9d
fix tests
dmitry-shibanov May 9, 2022
bd01c0d
fix tests
dmitry-shibanov May 9, 2022
d43033c
add mock
dmitry-shibanov May 9, 2022
0c0e574
run format
dmitry-shibanov May 9, 2022
0753db1
fix tests
dmitry-shibanov May 9, 2022
ea1d6e9
Merge branch 'main' into v-dmshib/add-check-latest
dmitry-shibanov May 24, 2022
86e88a6
Merge branch 'main' into v-dmshib/add-check-latest
dmitry-shibanov May 31, 2022
6d01ca9
Merge branch 'main' into v-dmshib/add-check-latest
dmitry-shibanov Jun 15, 2022
614f5d9
rebuild dist
dmitry-shibanov Jun 15, 2022
0e03ef2
fix test-python.yml
dmitry-shibanov Jun 15, 2022
de4dd60
Merge branch 'main' into v-dmshib/add-check-latest
dmitry-shibanov Jul 7, 2022
2718326
resolve conflicts
dmitry-shibanov Jul 7, 2022
72e092b
format code
dmitry-shibanov Jul 7, 2022
1c2a569
Merge branch 'main' into v-dmshib/add-check-latest
dmitry-shibanov Jul 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add check-latest for pypy
  • Loading branch information
dmitry-shibanov committed May 9, 2022
commit 73adf61d1fc8b559902168b91ffacad6b71caae4
33 changes: 33 additions & 0 deletions .github/workflows/test-pypy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,36 @@ jobs:
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version
shell: bash

check-latest:
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'
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=${{ matrix.pypy }}
EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version
shell: bash
72 changes: 66 additions & 6 deletions __tests__/find-pypy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {HttpClient} from '@actions/http-client';
import * as ifm from '@actions/http-client/interfaces';
import * as tc from '@actions/tool-cache';
import * as exec from '@actions/exec';
import * as core from '@actions/core';

import * as path from 'path';
import * as semver from 'semver';
Expand All @@ -13,7 +14,6 @@ import * as finder from '../src/find-pypy';
import {
IPyPyManifestRelease,
IS_WINDOWS,
validateVersion,
getPyPyVersionFromPath
} from '../src/utils';

Expand Down Expand Up @@ -117,6 +117,8 @@ describe('findPyPyToolCache', () => {
});

describe('findPyPyVersion', () => {
let getBooleanInputSpy: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let tcFind: jest.SpyInstance;
let spyExtractZip: jest.SpyInstance;
let spyExtractTar: jest.SpyInstance;
Expand All @@ -132,6 +134,12 @@ describe('findPyPyVersion', () => {
let spyChmodSync: jest.SpyInstance;

beforeEach(() => {
getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
getBooleanInputSpy.mockImplementation(() => false);

infoSpy = jest.spyOn(core, 'info');
infoSpy.mockImplementation(() => {});

tcFind = jest.spyOn(tc, 'find');
tcFind.mockImplementation((tool: string, version: string) => {
const semverRange = new semver.Range(version);
Expand Down Expand Up @@ -193,7 +201,7 @@ describe('findPyPyVersion', () => {

it('found PyPy in toolcache', async () => {
await expect(
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture)
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, false)
).resolves.toEqual({
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3'
Expand All @@ -202,13 +210,13 @@ describe('findPyPyVersion', () => {

it('throw on invalid input format', async () => {
await expect(
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, false)
).rejects.toThrow();
});

it('throw on invalid input format pypy3.7-7.3.x', async () => {
await expect(
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, false)
).rejects.toThrow();
});

Expand All @@ -220,7 +228,7 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
Expand All @@ -229,9 +237,61 @@ describe('findPyPyVersion', () => {

it('throw if release is not found', async () => {
await expect(
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture)
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, false)
).rejects.toThrowError(
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
);
});

it('check-latest enabled version found and used from toolcache', async () => {
await expect(
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3'
});

expect(infoSpy).toHaveBeenCalledWith(
'Resolved as PyPy 7.3.3 with Python (3.6.12)'
);
});

it('check-latest enabled version found and install successfully', async () => {
spyCacheDir = jest.spyOn(tc, 'cacheDir');
spyCacheDir.mockImplementation(() =>
path.join(toolDir, 'PyPy', '3.7.7', architecture)
);
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
});
expect(infoSpy).toHaveBeenCalledWith(
'Resolved as PyPy 7.3.3 with Python (3.7.9)'
);
});

it('check-latest enabled version is not found and used from toolcache', async () => {
tcFind.mockImplementationOnce((tool: string, version: string) => {
const semverRange = new semver.Range(version);
let pypyPath = '';
if (semver.satisfies('3.8.8', semverRange)) {
pypyPath = path.join(toolDir, 'PyPy', '3.8.8', architecture);
}
return pypyPath;
});
await expect(
finder.findPyPyVersion('pypy-3.8-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.8.8',
resolvedPyPyVersion: '7.3.3'
});

expect(infoSpy).toHaveBeenCalledWith(
'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
);
});
});
10 changes: 5 additions & 5 deletions __tests__/finder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Finder tests', () => {
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 finder.useCpythonVersion('3.x', 'x64');
await finder.useCpythonVersion('3.x', 'x64', false);
});

it('Finds stable Python version if it is not installed, but exists in the manifest', async () => {
Expand All @@ -60,7 +60,7 @@ describe('Finder tests', () => {
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 finder.useCpythonVersion('1.2.3', 'x64');
await finder.useCpythonVersion('1.2.3', 'x64', false);
});

it('Finds pre-release Python version in the manifest', async () => {
Expand All @@ -85,7 +85,7 @@ describe('Finder tests', () => {
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
});
// 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');
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false);
});

it('Check-latest true, finds the latest version in the manifest', async () => {
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('Finder tests', () => {

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 finder.useCpythonVersion('1.2', 'x64');
await finder.useCpythonVersion('1.2', 'x64', true);

expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
expect(infoSpy).toHaveBeenCalledWith('Version 1.2.3 was not found in the local cache');
Expand All @@ -139,7 +139,7 @@ describe('Finder tests', () => {
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
let thrown = false;
try {
await finder.useCpythonVersion('3.300000', 'x64');
await finder.useCpythonVersion('3.300000', 'x64', false);
} catch {
thrown = true;
}
Expand Down
34 changes: 25 additions & 9 deletions dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5612,16 +5612,17 @@ function run() {
}
try {
const version = core.getInput('python-version');
const checkLatest = core.getBooleanInput('check-latest');
if (version) {
let pythonVersion;
const arch = core.getInput('architecture') || os.arch();
if (isPyPyVersion(version)) {
const installed = yield finderPyPy.findPyPyVersion(version, arch);
const installed = yield finderPyPy.findPyPyVersion(version, arch, 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);
const installed = yield finder.useCpythonVersion(version, arch, checkLatest);
pythonVersion = installed.version;
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
}
Expand Down Expand Up @@ -9742,7 +9743,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.findAssetForMacOrLinux = exports.findAssetForWindows = exports.isArchPresentForMacOrLinux = exports.isArchPresentForWindows = exports.pypyVersionToSemantic = exports.getPyPyBinaryPath = exports.findRelease = 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 path = __importStar(__webpack_require__(622));
const core = __importStar(__webpack_require__(470));
const tc = __importStar(__webpack_require__(533));
Expand All @@ -9751,10 +9752,10 @@ const httpm = __importStar(__webpack_require__(539));
const exec = __importStar(__webpack_require__(986));
const fs_1 = __importDefault(__webpack_require__(747));
const utils_1 = __webpack_require__(163);
function installPyPy(pypyVersion, pythonVersion, architecture) {
function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
return __awaiter(this, void 0, void 0, function* () {
let downloadDir;
const releases = yield getAvailablePyPyVersions();
releases !== null && releases !== void 0 ? releases : (releases = yield getAvailablePyPyVersions());
if (!releases || releases.length === 0) {
throw new Error('No release was found in PyPy version.json');
}
Expand Down Expand Up @@ -9800,6 +9801,7 @@ function getAvailablePyPyVersions() {
return response.result;
});
}
exports.getAvailablePyPyVersions = getAvailablePyPyVersions;
function createPyPySymlink(pypyBinaryPath, pythonVersion) {
return __awaiter(this, void 0, void 0, function* () {
const version = semver.coerce(pythonVersion);
Expand Down Expand Up @@ -52251,19 +52253,34 @@ const utils_1 = __webpack_require__(163);
const semver = __importStar(__webpack_require__(876));
const core = __importStar(__webpack_require__(470));
const tc = __importStar(__webpack_require__(533));
function findPyPyVersion(versionSpec, architecture) {
function findPyPyVersion(versionSpec, architecture, checkLatest) {
return __awaiter(this, void 0, void 0, function* () {
let resolvedPyPyVersion = '';
let resolvedPythonVersion = '';
let installDir;
let releases;
const pypyVersionSpec = parsePyPyVersion(versionSpec);
if (checkLatest) {
releases = yield pypyInstall.getAvailablePyPyVersions();
if (releases && releases.length > 0) {
const releaseData = pypyInstall.findRelease(releases, pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture);
if (releaseData) {
core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`);
pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion;
}
else {
core.info(`Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest`);
}
}
}
({ installDir, resolvedPythonVersion, resolvedPyPyVersion } = findPyPyToolCache(pypyVersionSpec.pythonVersion, pypyVersionSpec.pypyVersion, architecture));
if (!installDir) {
({
installDir,
resolvedPythonVersion,
resolvedPyPyVersion
} = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture));
} = yield pypyInstall.installPyPy(pypyVersionSpec.pypyVersion, pypyVersionSpec.pythonVersion, architecture, releases));
}
const pipDir = utils_1.IS_WINDOWS ? 'Scripts' : 'bin';
const _binDir = path.join(installDir, pipDir);
Expand Down Expand Up @@ -56883,14 +56900,13 @@ function binDir(installDir) {
return path.join(installDir, 'bin');
}
}
function useCpythonVersion(version, architecture) {
function useCpythonVersion(version, architecture, checkLatest) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let manifest = null;
const desugaredVersionSpec = desugarDevVersion(version);
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
const checkLatest = core.getBooleanInput('check-latest');
if (checkLatest) {
manifest = yield installer.getManifest();
const resolvedVersion = (_a = (yield installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest))) === null || _a === void 0 ? void 0 : _a.version;
Expand Down
30 changes: 27 additions & 3 deletions src/find-pypy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
validateVersion,
getPyPyVersionFromPath,
readExactPyPyVersionFile,
validatePythonVersionFormatForPyPy
validatePythonVersionFormatForPyPy,
IPyPyManifestRelease
} from './utils';

import * as semver from 'semver';
Expand All @@ -20,14 +21,36 @@ interface IPyPyVersionSpec {

export async function findPyPyVersion(
versionSpec: string,
architecture: string
architecture: string,
checkLatest: boolean
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
let resolvedPyPyVersion = '';
let resolvedPythonVersion = '';
let installDir: string | null;
let releases: IPyPyManifestRelease[] | undefined;

const pypyVersionSpec = parsePyPyVersion(versionSpec);

if (checkLatest) {
releases = await pypyInstall.getAvailablePyPyVersions();
if (releases && releases.length > 0) {
const releaseData = pypyInstall.findRelease(
releases,
pypyVersionSpec.pythonVersion,
pypyVersionSpec.pypyVersion,
architecture
);

if(releaseData) {
core.info(`Resolved as PyPy ${releaseData.resolvedPyPyVersion} with Python (${releaseData.resolvedPythonVersion})`);
pypyVersionSpec.pythonVersion = releaseData.resolvedPythonVersion;
pypyVersionSpec.pypyVersion = releaseData.resolvedPyPyVersion;
} else {
core.info(`Failed to resolve PyPy ${pypyVersionSpec.pypyVersion} with Python (${pypyVersionSpec.pythonVersion}) from manifest`);
}
}
}

({installDir, resolvedPythonVersion, resolvedPyPyVersion} = findPyPyToolCache(
pypyVersionSpec.pythonVersion,
pypyVersionSpec.pypyVersion,
Expand All @@ -42,7 +65,8 @@ export async function findPyPyVersion(
} = await pypyInstall.installPyPy(
pypyVersionSpec.pypyVersion,
pypyVersionSpec.pythonVersion,
architecture
architecture,
releases
));
}

Expand Down
5 changes: 2 additions & 3 deletions src/find-python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ function binDir(installDir: string): string {

export async function useCpythonVersion(
version: string,
architecture: string
architecture: string,
checkLatest: boolean
): Promise<InstalledVersion> {
let manifest: tc.IToolRelease[] | null = null;
const desugaredVersionSpec = desugarDevVersion(version);
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);

const checkLatest = core.getBooleanInput('check-latest');

if (checkLatest) {
manifest = await installer.getManifest();
const resolvedVersion = (await installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest))?.version;
Expand Down
Loading