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)