mirror of
https://code.forgejo.org/actions/setup-python
synced 2025-03-15 14:54:37 +01:00
Add support for .tool-versions file in setup-python (#1043)
* add support for .tool-versions file * update regex * optimize code * update test-python.yml for .tool-versions * fix format-check errors * fix formatting in test-python.yml * Fix test-python.yml error * workflow update with latest versions * update test cases * fix lint issue
This commit is contained in:
parent
6fd11e170a
commit
19e4675e06
5 changed files with 193 additions and 6 deletions
33
.github/workflows/test-python.yml
vendored
33
.github/workflows/test-python.yml
vendored
|
@ -245,6 +245,39 @@ jobs:
|
|||
- name: Run simple code
|
||||
run: python -c 'import math; print(math.factorial(5))'
|
||||
|
||||
setup-versions-from-tool-versions-file:
|
||||
name: Setup ${{ matrix.python }} ${{ matrix.os }} .tool-versions file
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
[
|
||||
macos-latest,
|
||||
windows-latest,
|
||||
ubuntu-20.04,
|
||||
ubuntu-22.04,
|
||||
macos-13,
|
||||
ubuntu-latest
|
||||
]
|
||||
python: [3.13.0, 3.14-dev, pypy3.11-7.3.18, graalpy-24.1.2]
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python: graalpy-24.1.2
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: build-tool-versions-file ${{ matrix.python }}
|
||||
run: |
|
||||
echo "python ${{ matrix.python }}" > .tool-versions
|
||||
|
||||
- name: setup-python using .tool-versions ${{ matrix.python }}
|
||||
id: setup-python-tool-versions
|
||||
uses: ./
|
||||
with:
|
||||
python-version-file: .tool-versions
|
||||
|
||||
setup-pre-release-version-from-manifest:
|
||||
name: Setup 3.14.0-alpha.1 ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
|
@ -15,7 +15,8 @@ import {
|
|||
getNextPageUrl,
|
||||
isGhes,
|
||||
IS_WINDOWS,
|
||||
getDownloadFileName
|
||||
getDownloadFileName,
|
||||
getVersionInputFromToolVersions
|
||||
} from '../src/utils';
|
||||
|
||||
jest.mock('@actions/cache');
|
||||
|
@ -139,6 +140,82 @@ describe('Version from file test', () => {
|
|||
expect(_fn(pythonVersionFilePath)).toEqual([]);
|
||||
}
|
||||
);
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = 'python 3.9.10\nnodejs 16';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.9.10']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with comment',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = '# python 3.8\npython 3.9';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.9']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with whitespace',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = ' python 3.10 ';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.10']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with v prefix',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = 'python v3.9.10';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.9.10']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with pypy version',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = 'python pypy3.10-7.3.14';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['pypy3.10-7.3.14']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with alpha Releases',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = 'python 3.14.0a5t';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.14.0a5t']);
|
||||
}
|
||||
);
|
||||
|
||||
it.each([getVersionInputFromToolVersions])(
|
||||
'Version from .tool-versions with dev suffix',
|
||||
async _fn => {
|
||||
const toolVersionFileName = '.tool-versions';
|
||||
const toolVersionFilePath = path.join(tempDir, toolVersionFileName);
|
||||
const toolVersionContent = 'python 3.14t-dev';
|
||||
fs.writeFileSync(toolVersionFilePath, toolVersionContent);
|
||||
expect(_fn(toolVersionFilePath)).toEqual(['3.14t-dev']);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('getNextPageUrl', () => {
|
||||
|
|
38
dist/setup/index.js
vendored
38
dist/setup/index.js
vendored
|
@ -100535,7 +100535,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromPlainFile = exports.getVersionInputFromTomlFile = exports.getOSInfo = exports.getLinuxInfo = exports.logWarning = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
|
||||
exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromToolVersions = exports.getVersionInputFromPlainFile = exports.getVersionInputFromTomlFile = exports.getOSInfo = exports.getLinuxInfo = exports.logWarning = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
|
||||
/* eslint no-unsafe-finally: "off" */
|
||||
const cache = __importStar(__nccwpck_require__(5116));
|
||||
const core = __importStar(__nccwpck_require__(7484));
|
||||
|
@ -100759,12 +100759,46 @@ function getVersionInputFromPlainFile(versionFile) {
|
|||
}
|
||||
exports.getVersionInputFromPlainFile = getVersionInputFromPlainFile;
|
||||
/**
|
||||
* Python version extracted from a plain or TOML file.
|
||||
* Python version extracted from a .tool-versions file.
|
||||
*/
|
||||
function getVersionInputFromToolVersions(versionFile) {
|
||||
var _a;
|
||||
if (!fs_1.default.existsSync(versionFile)) {
|
||||
core.warning(`File ${versionFile} does not exist.`);
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const fileContents = fs_1.default.readFileSync(versionFile, 'utf8');
|
||||
const lines = fileContents.split('\n');
|
||||
for (const line of lines) {
|
||||
// Skip commented lines
|
||||
if (line.trim().startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
const match = line.match(/^\s*python\s*v?\s*(?<version>[^\s]+)\s*$/);
|
||||
if (match) {
|
||||
return [((_a = match.groups) === null || _a === void 0 ? void 0 : _a.version.trim()) || ''];
|
||||
}
|
||||
}
|
||||
core.warning(`No Python version found in ${versionFile}`);
|
||||
return [];
|
||||
}
|
||||
catch (error) {
|
||||
core.error(`Error reading ${versionFile}: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
exports.getVersionInputFromToolVersions = getVersionInputFromToolVersions;
|
||||
/**
|
||||
* Python version extracted from a plain, .tool-versions or TOML file.
|
||||
*/
|
||||
function getVersionInputFromFile(versionFile) {
|
||||
if (versionFile.endsWith('.toml')) {
|
||||
return getVersionInputFromTomlFile(versionFile);
|
||||
}
|
||||
else if (versionFile.match('.tool-versions')) {
|
||||
return getVersionInputFromToolVersions(versionFile);
|
||||
}
|
||||
else {
|
||||
return getVersionInputFromPlainFile(versionFile);
|
||||
}
|
||||
|
|
|
@ -278,9 +278,9 @@ jobs:
|
|||
|
||||
## Using the `python-version-file` input
|
||||
|
||||
`setup-python` action can read the Python or PyPy version from a version file. `python-version-file` input is used to specify 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 an error.
|
||||
`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.
|
||||
|
||||
>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. The .tool-versions file supports version specifications in accordance with asdf standards, adhering to Semantic Versioning ([semver](https://semver.org)).
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
|
@ -300,6 +300,15 @@ steps:
|
|||
- run: python my_script.py
|
||||
```
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version-file: '.tool-versions' # Read python version from a file .tool-versions
|
||||
- run: python my_script.py
|
||||
```
|
||||
|
||||
## 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 or PyPy` version is always used.
|
||||
|
|
36
src/utils.ts
36
src/utils.ts
|
@ -279,11 +279,45 @@ export function getVersionInputFromPlainFile(versionFile: string): string[] {
|
|||
}
|
||||
|
||||
/**
|
||||
* Python version extracted from a plain or TOML file.
|
||||
* Python version extracted from a .tool-versions file.
|
||||
*/
|
||||
export function getVersionInputFromToolVersions(versionFile: string): string[] {
|
||||
if (!fs.existsSync(versionFile)) {
|
||||
core.warning(`File ${versionFile} does not exist.`);
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const fileContents = fs.readFileSync(versionFile, 'utf8');
|
||||
const lines = fileContents.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
// Skip commented lines
|
||||
if (line.trim().startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
const match = line.match(/^\s*python\s*v?\s*(?<version>[^\s]+)\s*$/);
|
||||
if (match) {
|
||||
return [match.groups?.version.trim() || ''];
|
||||
}
|
||||
}
|
||||
|
||||
core.warning(`No Python version found in ${versionFile}`);
|
||||
|
||||
return [];
|
||||
} catch (error) {
|
||||
core.error(`Error reading ${versionFile}: ${(error as Error).message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Python version extracted from a plain, .tool-versions or TOML file.
|
||||
*/
|
||||
export function getVersionInputFromFile(versionFile: string): string[] {
|
||||
if (versionFile.endsWith('.toml')) {
|
||||
return getVersionInputFromTomlFile(versionFile);
|
||||
} else if (versionFile.match('.tool-versions')) {
|
||||
return getVersionInputFromToolVersions(versionFile);
|
||||
} else {
|
||||
return getVersionInputFromPlainFile(versionFile);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue