Skip to content
Permalink
Browse files
Add check-latest functionality (#406)
  • Loading branch information
Dmitry Shibanov authored and GitHub committed Jul 25, 2022
1 parent 49a521f commit 2f06e9da25e11351919e97ebc9d3cd20dc7208ab
Show file tree
Hide file tree
Showing 14 changed files with 440 additions and 82 deletions.
@@ -91,3 +91,36 @@ jobs:

- name: Run simple code
run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'

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="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
@@ -172,3 +172,27 @@ jobs:

- name: Run simple code
run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'

check-latest:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- name: Setup Python and check latest
uses: ./
with:
python-version: ${{ matrix.python-version }}
check-latest: true
- name: Validate version
run: |
$pythonVersion = (python --version)
if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
exit 1
}
$pythonVersion
shell: pwsh

This file was deleted.

@@ -259,6 +259,24 @@ pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy

Note: `pypy2` and `pypy3` have been removed in v3. Use the format above instead.

# Check latest version

The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python/PyPy` version is always used.

If `check-latest` is set to `true`, the action first checks if the cached version is the latest one. If the locally cached version is not the most up-to-date, a `Python/PyPy` version will then be downloaded. Set `check-latest` to `true` if you want the most up-to-date `Python/PyPy` version to always be used.

> Setting `check-latest` to `true` has performance implications as downloading `Python/PyPy` versions is slower than using cached versions.
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: '3.7'
check-latest: true
- run: python my_script.py
```

# Caching packages dependencies

The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default.
@@ -14,7 +14,6 @@ import * as finder from '../src/find-pypy';
import {
IPyPyManifestRelease,
IS_WINDOWS,
validateVersion,
getPyPyVersionFromPath
} from '../src/utils';

@@ -82,6 +81,12 @@ describe('findPyPyToolCache', () => {
const pypyPath = path.join('PyPy', actualPythonVersion, architecture);
let tcFind: jest.SpyInstance;
let spyReadExactPyPyVersion: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance;
let addPathSpy: jest.SpyInstance;
let exportVariableSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;

beforeEach(() => {
tcFind = jest.spyOn(tc, 'find');
@@ -94,6 +99,24 @@ describe('findPyPyToolCache', () => {

spyReadExactPyPyVersion = jest.spyOn(utils, 'readExactPyPyVersionFile');
spyReadExactPyPyVersion.mockImplementation(() => actualPyPyVersion);

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

warningSpy = jest.spyOn(core, 'warning');
warningSpy.mockImplementation(() => null);

debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(() => null);

addPathSpy = jest.spyOn(core, 'addPath');
addPathSpy.mockImplementation(() => null);

exportVariableSpy = jest.spyOn(core, 'exportVariable');
exportVariableSpy.mockImplementation(() => null);

setOutputSpy = jest.spyOn(core, 'setOutput');
setOutputSpy.mockImplementation(() => null);
});

afterEach(() => {
@@ -136,6 +159,13 @@ describe('findPyPyToolCache', () => {
});

describe('findPyPyVersion', () => {
let getBooleanInputSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance;
let infoSpy: jest.SpyInstance;
let addPathSpy: jest.SpyInstance;
let exportVariableSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;
let tcFind: jest.SpyInstance;
let spyExtractZip: jest.SpyInstance;
let spyExtractTar: jest.SpyInstance;
@@ -154,6 +184,27 @@ describe('findPyPyVersion', () => {
const env = process.env;

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

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

warningSpy = jest.spyOn(core, 'warning');
warningSpy.mockImplementation(() => null);

debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(() => null);

addPathSpy = jest.spyOn(core, 'addPath');
addPathSpy.mockImplementation(() => null);

exportVariableSpy = jest.spyOn(core, 'exportVariable');
exportVariableSpy.mockImplementation(() => null);

setOutputSpy = jest.spyOn(core, 'setOutput');
setOutputSpy.mockImplementation(() => null);

jest.resetModules();
process.env = {...env};
tcFind = jest.spyOn(tc, 'find');
@@ -222,7 +273,7 @@ describe('findPyPyVersion', () => {

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

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

@@ -258,7 +309,7 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true, false)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
@@ -282,7 +333,7 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false)
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, false)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
@@ -293,9 +344,61 @@ describe('findPyPyVersion', () => {

it('throw if release is not found', async () => {
await expect(
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true)
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true, 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, false, 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, false, 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, false, 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'
);
});
});

0 comments on commit 2f06e9d

Please sign in to comment.