From 892baae68b3d7dbaa676d65914e7c51988e43aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Ifr=C3=A1n?= Date: Tue, 17 Jan 2023 18:33:06 -0300 Subject: [PATCH 1/3] Add support to .tool-version file format Create a function to parse tool-version (asdf-vm) format, add the associated tests, and updated the documentation Ticket-ID: #571 --- __tests__/utils.test.ts | 15 +++++++++++++++ docs/advanced-usage.md | 5 +++-- src/setup-python.ts | 17 +++++++++++++---- src/utils.ts | 16 ++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index 30fc61c..7722fb3 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -1,6 +1,7 @@ import * as cache from '@actions/cache'; import * as core from '@actions/core'; import { + parsePythonVersionFile, validateVersion, validatePythonVersionFormatForPyPy, isCacheFeatureAvailable @@ -9,6 +10,20 @@ import { jest.mock('@actions/cache'); jest.mock('@actions/core'); +describe('parsePythonVersionFile', () => { + it('handle the content of a .python-version file', () => { + expect(parsePythonVersionFile('3.6')).toEqual('3.6') + }); + + it('trims extra spaces at the end of the content', () => { + expect(parsePythonVersionFile('3.7 ')).toEqual('3.7') + }); + + it('parses correctly the content of .tool-version files', () => { + expect(parsePythonVersionFile('python 3.7')).toEqual('3.7') + }); +}); + describe('validatePythonVersionFormatForPyPy', () => { it.each([ ['3.6', true], diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 1483da9..718a4f5 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -239,9 +239,10 @@ jobs: ## Using the `python-version-file` input -`setup-python` action can read Python or PyPy version from a version file. `python-version-file` input is used for specifying the path to the version file. If the file that was supplied to `python-version-file` input doesn't exist, the action will fail with error. +The python-version-file input accepts a path to a file containing the version of Python to be used by a project, for example .python-version, or .tool-versions. +If both the python-version and the python-version-file inputs are provided then the python-version input is used. ->In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority. +> The action will search for the python version file relative to the repository root. ```yaml steps: diff --git a/src/setup-python.ts b/src/setup-python.ts index 7e9725e..1ef7506 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as os from 'os'; import fs from 'fs'; import {getCacheDistributor} from './cache-distributions/cache-factory'; -import {isCacheFeatureAvailable, logWarning, IS_MAC} from './utils'; +import {parsePythonVersionFile, isCacheFeatureAvailable, logWarning, IS_MAC} from './utils'; function isPyPyVersion(versionSpec: string) { return versionSpec.startsWith('pypy'); @@ -37,20 +37,29 @@ function resolveVersionInput() { } if (versionFile) { - if (!fs.existsSync(versionFile)) { + const versionFilePath = path.join( + process.env.GITHUB_WORKSPACE!, + versionFile + ); + + if (!fs.existsSync(versionFilePath)) { throw new Error( - `The specified python version file at: ${versionFile} doesn't exist.` + `The specified python version file at: ${versionFilePath} doesn't exist.` ); } - const version = fs.readFileSync(versionFile, 'utf8'); + + const version = parsePythonVersionFile(fs.readFileSync(versionFilePath, 'utf8')); core.info(`Resolved ${versionFile} as ${version}`); + return [version]; } logWarning( "Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file." ); + versionFile = '.python-version'; + if (fs.existsSync(versionFile)) { const version = fs.readFileSync(versionFile, 'utf8'); core.info(`Resolved ${versionFile} as ${version}`); diff --git a/src/utils.ts b/src/utils.ts index 5a5866e..9d5f231 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -28,6 +28,22 @@ export interface IPyPyManifestRelease { files: IPyPyManifestAsset[]; } +export function parsePythonVersionFile(contents: string): string { + let pythonVersion: string | undefined; + + // Try to find the version in tool-version file + const found = contents.match(/^(?:python\s+)?v?(?[^\s]+)$/m); + pythonVersion = found?.groups?.version; + + // In the case of an unknown format, + // return as is and evaluate the version separately. + if (!pythonVersion) { + pythonVersion = contents.trim(); + } + + return pythonVersion as string; +} + /** create Symlinks for downloaded PyPy * It should be executed only for downloaded versions in runtime, because * toolcache versions have this setup. From 3d009a5143b6f3c3dfa05b9adaf126d479ac6c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Ifr=C3=A1n?= Date: Wed, 18 Jan 2023 08:21:22 -0300 Subject: [PATCH 2/3] Fix suggestios done in code review Rollback a not abot advanced usage on how to use the file and not use the GITHUB_WORKSPACE since it was removed in a previous PR --- docs/advanced-usage.md | 2 +- src/setup-python.ts | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 718a4f5..9bdd456 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -242,7 +242,7 @@ jobs: The python-version-file input accepts a path to a file containing the version of Python to be used by a project, for example .python-version, or .tool-versions. If both the python-version and the python-version-file inputs are provided then the python-version input is used. -> The action will search for the python version file relative to the repository root. +> In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority. ```yaml steps: diff --git a/src/setup-python.ts b/src/setup-python.ts index 1ef7506..a10b751 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -37,18 +37,13 @@ function resolveVersionInput() { } if (versionFile) { - const versionFilePath = path.join( - process.env.GITHUB_WORKSPACE!, - versionFile - ); - - if (!fs.existsSync(versionFilePath)) { + if (!fs.existsSync(versionFile)) { throw new Error( - `The specified python version file at: ${versionFilePath} doesn't exist.` + `The specified python version file at: ${versionFile} doesn't exist.` ); } - const version = parsePythonVersionFile(fs.readFileSync(versionFilePath, 'utf8')); + const version = parsePythonVersionFile(fs.readFileSync(versionFile, 'utf8')); core.info(`Resolved ${versionFile} as ${version}`); return [version]; From 59a78899a90b6def5f13ccbcf54f583d63283d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Ifr=C3=A1n?= Date: Wed, 18 Jan 2023 10:00:38 -0300 Subject: [PATCH 3/3] Fix style issues and build Build the project using `npm run build` and run prettier using `npm run format` --- __tests__/utils.test.ts | 12 +++++++++--- docs/advanced-usage.md | 2 +- src/find-pypy.ts | 19 +++++++++++-------- src/setup-python.ts | 11 +++++++++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index 7722fb3..87f4d77 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -12,15 +12,21 @@ jest.mock('@actions/core'); describe('parsePythonVersionFile', () => { it('handle the content of a .python-version file', () => { - expect(parsePythonVersionFile('3.6')).toEqual('3.6') + expect(parsePythonVersionFile('3.6')).toEqual('3.6'); }); it('trims extra spaces at the end of the content', () => { - expect(parsePythonVersionFile('3.7 ')).toEqual('3.7') + expect(parsePythonVersionFile('3.7 ')).toEqual('3.7'); }); it('parses correctly the content of .tool-version files', () => { - expect(parsePythonVersionFile('python 3.7')).toEqual('3.7') + expect(parsePythonVersionFile('python 3.7')).toEqual('3.7'); + }); + + it('parses correctly pypy version content of the .tool-version files', () => { + expect(parsePythonVersionFile('python pypy3.9-7.3.10')).toEqual( + 'pypy3.9-7.3.10' + ); }); }); diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 9bdd456..174b6df 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -242,7 +242,7 @@ jobs: The python-version-file input accepts a path to a file containing the version of Python to be used by a project, for example .python-version, or .tool-versions. If both the python-version and the python-version-file inputs are provided then the python-version input is used. -> In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority. +>In case both `python-version` and `python-version-file` inputs are supplied, the `python-version-file` input will be ignored due to its lower priority. ```yaml steps: diff --git a/src/find-pypy.ts b/src/find-pypy.ts index a87dc84..77b3b5b 100644 --- a/src/find-pypy.ts +++ b/src/find-pypy.ts @@ -65,14 +65,17 @@ export async function findPyPyVersion( )); if (!installDir) { - ({installDir, resolvedPythonVersion, resolvedPyPyVersion} = - await pypyInstall.installPyPy( - pypyVersionSpec.pypyVersion, - pypyVersionSpec.pythonVersion, - architecture, - allowPreReleases, - releases - )); + ({ + installDir, + resolvedPythonVersion, + resolvedPyPyVersion + } = await pypyInstall.installPyPy( + pypyVersionSpec.pypyVersion, + pypyVersionSpec.pythonVersion, + architecture, + allowPreReleases, + releases + )); } const pipDir = IS_WINDOWS ? 'Scripts' : 'bin'; diff --git a/src/setup-python.ts b/src/setup-python.ts index a10b751..e64dda3 100644 --- a/src/setup-python.ts +++ b/src/setup-python.ts @@ -5,7 +5,12 @@ import * as path from 'path'; import * as os from 'os'; import fs from 'fs'; import {getCacheDistributor} from './cache-distributions/cache-factory'; -import {parsePythonVersionFile, isCacheFeatureAvailable, logWarning, IS_MAC} from './utils'; +import { + parsePythonVersionFile, + isCacheFeatureAvailable, + logWarning, + IS_MAC +} from './utils'; function isPyPyVersion(versionSpec: string) { return versionSpec.startsWith('pypy'); @@ -43,7 +48,9 @@ function resolveVersionInput() { ); } - const version = parsePythonVersionFile(fs.readFileSync(versionFile, 'utf8')); + const version = parsePythonVersionFile( + fs.readFileSync(versionFile, 'utf8') + ); core.info(`Resolved ${versionFile} as ${version}`); return [version];