Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 33 additions & 0 deletions 33 .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
79 changes: 78 additions & 1 deletion 79 __tests__/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
getNextPageUrl,
isGhes,
IS_WINDOWS,
getDownloadFileName
getDownloadFileName,
getVersionInputFromToolVersions
} from '../src/utils';

jest.mock('@actions/cache');
Expand Down Expand Up @@ -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', () => {
Expand Down
38 changes: 36 additions & 2 deletions 38 dist/setup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100494,7 +100494,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));
Expand Down Expand Up @@ -100718,12 +100718,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);
}
Expand Down
13 changes: 11 additions & 2 deletions 13 docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand Down
36 changes: 35 additions & 1 deletion 36 src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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*$/);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nit: the [^\s] can be replaced with just \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);
}
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.