Skip to content

Commit c44ab2e

Browse files
committed
feature: add version parsing from Pipfile
1 parent 5db1cf9 commit c44ab2e

File tree

5 files changed

+222
-3
lines changed

5 files changed

+222
-3
lines changed

.github/workflows/test-python.yml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,108 @@ jobs:
284284
with:
285285
python-version-file: .tool-versions
286286

287+
setup-versions-from-pipfile-with-python_version:
288+
name: Setup ${{ matrix.python }} ${{ matrix.os }} Pipfile with python_version
289+
runs-on: ${{ matrix.os }}
290+
strategy:
291+
fail-fast: false
292+
matrix:
293+
os:
294+
[
295+
macos-latest,
296+
windows-latest,
297+
ubuntu-20.04,
298+
ubuntu-22.04,
299+
ubuntu-22.04-arm,
300+
macos-13,
301+
ubuntu-latest,
302+
ubuntu-24.04-arm
303+
]
304+
python: [3.9.13, 3.10.11, 3.11.9, 3.13.2]
305+
steps:
306+
- name: Checkout
307+
uses: actions/checkout@v4
308+
309+
- name: build-version-file ${{ matrix.python }}
310+
run: |
311+
echo '[requires]
312+
python_version = "${{ matrix.python }}"
313+
' > Pipenv
314+
315+
- name: setup-python ${{ matrix.python }}
316+
id: setup-python
317+
uses: ./
318+
with:
319+
python-version-file: Pipenv
320+
321+
- name: Check python-path
322+
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
323+
shell: bash
324+
325+
- name: Validate version
326+
run: |
327+
$pythonVersion = (python --version)
328+
if ("Python ${{ matrix.python }}".replace("==", "") -ne "$pythonVersion"){
329+
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
330+
exit 1
331+
}
332+
$pythonVersion
333+
shell: pwsh
334+
335+
- name: Run simple code
336+
run: python -c 'import math; print(math.factorial(5))'
337+
338+
setup-versions-from-pipfile-with-python_full_version:
339+
name: Setup ${{ matrix.python }} ${{ matrix.os }} Pipfile with python_full_version
340+
runs-on: ${{ matrix.os }}
341+
strategy:
342+
fail-fast: false
343+
matrix:
344+
os:
345+
[
346+
macos-latest,
347+
windows-latest,
348+
ubuntu-20.04,
349+
ubuntu-22.04,
350+
ubuntu-22.04-arm,
351+
macos-13,
352+
ubuntu-latest,
353+
ubuntu-24.04-arm
354+
]
355+
python: [3.9.13, 3.10.11, 3.11.9, 3.13.2]
356+
steps:
357+
- name: Checkout
358+
uses: actions/checkout@v4
359+
360+
- name: build-version-file ${{ matrix.python }}
361+
run: |
362+
echo '[requires]
363+
python_full_version = "${{ matrix.python }}"
364+
' > Pipenv
365+
366+
- name: setup-python ${{ matrix.python }}
367+
id: setup-python
368+
uses: ./
369+
with:
370+
python-version-file: Pipenv
371+
372+
- name: Check python-path
373+
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
374+
shell: bash
375+
376+
- name: Validate version
377+
run: |
378+
$pythonVersion = (python --version)
379+
if ("Python ${{ matrix.python }}".replace("==", "") -ne "$pythonVersion"){
380+
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
381+
exit 1
382+
}
383+
$pythonVersion
384+
shell: pwsh
385+
386+
- name: Run simple code
387+
run: python -c 'import math; print(math.factorial(5))'
388+
287389
setup-pre-release-version-from-manifest:
288390
name: Setup 3.14.0-alpha.6 ${{ matrix.os }}
289391
runs-on: ${{ matrix.os }}

__tests__/utils.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getVersionInputFromFile,
1313
getVersionsInputFromPlainFile,
1414
getVersionInputFromTomlFile,
15+
getVersionInputFromPipfileFile,
1516
getNextPageUrl,
1617
isGhes,
1718
IS_WINDOWS,
@@ -244,6 +245,44 @@ describe('Version from file test', () => {
244245
expect(_fn(toolVersionFilePath)).toEqual(['3.14t-dev']);
245246
}
246247
);
248+
249+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
250+
'Version from python_version in Pipfile',
251+
async _fn => {
252+
await io.mkdirP(tempDir);
253+
const pythonVersionFileName = 'Pipfile';
254+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
255+
const pythonVersion = '3.13';
256+
const pythonVersionFileContent = `[requires]\npython_version = "${pythonVersion}"`;
257+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
258+
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
259+
}
260+
);
261+
262+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
263+
'Version from python_full_version in Pipfile',
264+
async _fn => {
265+
await io.mkdirP(tempDir);
266+
const pythonVersionFileName = 'Pipfile';
267+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
268+
const pythonVersion = '3.13.0';
269+
const pythonVersionFileContent = `[requires]\npython_full_version = "${pythonVersion}"`;
270+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
271+
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
272+
}
273+
);
274+
275+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
276+
'Pipfile undefined version',
277+
async _fn => {
278+
await io.mkdirP(tempDir);
279+
const pythonVersionFileName = 'Pipfile';
280+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
281+
const pythonVersionFileContent = ``;
282+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
283+
expect(_fn(pythonVersionFilePath)).toEqual([]);
284+
}
285+
);
247286
});
248287

249288
describe('getNextPageUrl', () => {

dist/setup/index.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97066,7 +97066,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9706697066
return (mod && mod.__esModule) ? mod : { "default": mod };
9706797067
};
9706897068
Object.defineProperty(exports, "__esModule", ({ value: true }));
97069-
exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromToolVersions = exports.getVersionsInputFromPlainFile = 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;
97069+
exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromPipfileFile = exports.getVersionInputFromToolVersions = exports.getVersionsInputFromPlainFile = 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;
9707097070
/* eslint no-unsafe-finally: "off" */
9707197071
const cache = __importStar(__nccwpck_require__(5116));
9707297072
const core = __importStar(__nccwpck_require__(7484));
@@ -97336,7 +97336,37 @@ function getVersionInputFromToolVersions(versionFile) {
9733697336
}
9733797337
exports.getVersionInputFromToolVersions = getVersionInputFromToolVersions;
9733897338
/**
97339-
* Python version extracted from a plain, .tool-versions or TOML file.
97339+
* Python version extracted from the Pipfile file.
97340+
*/
97341+
function getVersionInputFromPipfileFile(versionFile) {
97342+
core.debug(`Trying to resolve version form ${versionFile}`);
97343+
let pipfileFile = fs_1.default.readFileSync(versionFile, 'utf8');
97344+
// Normalize the line endings in the pipfileFile
97345+
pipfileFile = pipfileFile.replace(/\r\n/g, '\n');
97346+
const pipfileConfig = toml.parse(pipfileFile);
97347+
const keys = ['requires'];
97348+
if (!('requires' in pipfileConfig)) {
97349+
core.warning(`No Python version found in ${versionFile}`);
97350+
return [];
97351+
}
97352+
if ('python_full_version' in pipfileConfig['requires']) {
97353+
// specifies a full python version
97354+
keys.push('python_full_version');
97355+
}
97356+
else {
97357+
keys.push('python_version');
97358+
}
97359+
const versions = [];
97360+
const version = extractValue(pipfileConfig, keys);
97361+
if (version !== undefined) {
97362+
versions.push(version);
97363+
}
97364+
core.info(`Extracted ${versions} from ${versionFile}`);
97365+
return [extractValue(pipfileConfig, keys)];
97366+
}
97367+
exports.getVersionInputFromPipfileFile = getVersionInputFromPipfileFile;
97368+
/**
97369+
* Python version extracted from a plain, .tool-versions, Pipfile or TOML file.
9734097370
*/
9734197371
function getVersionInputFromFile(versionFile) {
9734297372
if (versionFile.endsWith('.toml')) {
@@ -97345,6 +97375,9 @@ function getVersionInputFromFile(versionFile) {
9734597375
else if (versionFile.match('.tool-versions')) {
9734697376
return getVersionInputFromToolVersions(versionFile);
9734797377
}
97378+
else if (versionFile.match('Pipfile')) {
97379+
return getVersionInputFromPipfileFile(versionFile);
97380+
}
9734897381
else {
9734997382
return getVersionsInputFromPlainFile(versionFile);
9735097383
}

docs/advanced-usage.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,15 @@ steps:
309309
- run: python my_script.py
310310
```
311311

312+
```yaml
313+
steps:
314+
- uses: actions/checkout@v4
315+
- uses: actions/setup-python@v5
316+
with:
317+
python-version-file: 'Pipfile' # Read python version from a file Pipfile
318+
- run: python my_script.py
319+
```
320+
312321
## Check latest version
313322

314323
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.

src/utils.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,14 +325,50 @@ export function getVersionInputFromToolVersions(versionFile: string): string[] {
325325
return [];
326326
}
327327
}
328+
329+
/**
330+
* Python version extracted from the Pipfile file.
331+
*/
332+
export function getVersionInputFromPipfileFile(versionFile: string): string[] {
333+
core.debug(`Trying to resolve version form ${versionFile}`);
334+
335+
let pipfileFile = fs.readFileSync(versionFile, 'utf8');
336+
// Normalize the line endings in the pipfileFile
337+
pipfileFile = pipfileFile.replace(/\r\n/g, '\n');
338+
339+
const pipfileConfig = toml.parse(pipfileFile);
340+
const keys = ['requires'];
341+
342+
if (!('requires' in pipfileConfig)) {
343+
core.warning(`No Python version found in ${versionFile}`);
344+
return [];
345+
}
346+
if ('python_full_version' in (pipfileConfig['requires'] as toml.JsonMap)) {
347+
// specifies a full python version
348+
keys.push('python_full_version');
349+
} else {
350+
keys.push('python_version');
351+
}
352+
const versions = [];
353+
const version = extractValue(pipfileConfig, keys);
354+
if (version !== undefined) {
355+
versions.push(version);
356+
}
357+
358+
core.info(`Extracted ${versions} from ${versionFile}`);
359+
return [extractValue(pipfileConfig, keys)] as string[];
360+
}
361+
328362
/**
329-
* Python version extracted from a plain, .tool-versions or TOML file.
363+
* Python version extracted from a plain, .tool-versions, Pipfile or TOML file.
330364
*/
331365
export function getVersionInputFromFile(versionFile: string): string[] {
332366
if (versionFile.endsWith('.toml')) {
333367
return getVersionInputFromTomlFile(versionFile);
334368
} else if (versionFile.match('.tool-versions')) {
335369
return getVersionInputFromToolVersions(versionFile);
370+
} else if (versionFile.match('Pipfile')) {
371+
return getVersionInputFromPipfileFile(versionFile);
336372
} else {
337373
return getVersionsInputFromPlainFile(versionFile);
338374
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy