Skip to content

Commit f387444

Browse files
committed
feature: add version parsing from Pipfile
1 parent 8d9ed9a commit f387444

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
@@ -290,6 +290,108 @@ jobs:
290290
with:
291291
python-version-file: .tool-versions
292292

293+
setup-versions-from-pipfile-with-python_version:
294+
name: Setup ${{ matrix.python }} ${{ matrix.os }} Pipfile with python_version
295+
runs-on: ${{ matrix.os }}
296+
strategy:
297+
fail-fast: false
298+
matrix:
299+
os:
300+
[
301+
macos-latest,
302+
windows-latest,
303+
ubuntu-20.04,
304+
ubuntu-22.04,
305+
ubuntu-22.04-arm,
306+
macos-13,
307+
ubuntu-latest,
308+
ubuntu-24.04-arm
309+
]
310+
python: [3.9.13, 3.10.11, 3.11.9, 3.13.2]
311+
steps:
312+
- name: Checkout
313+
uses: actions/checkout@v4
314+
315+
- name: build-version-file ${{ matrix.python }}
316+
run: |
317+
echo '[requires]
318+
python_version = "${{ matrix.python }}"
319+
' > Pipenv
320+
321+
- name: setup-python ${{ matrix.python }}
322+
id: setup-python
323+
uses: ./
324+
with:
325+
python-version-file: Pipenv
326+
327+
- name: Check python-path
328+
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
329+
shell: bash
330+
331+
- name: Validate version
332+
run: |
333+
$pythonVersion = (python --version)
334+
if ("Python ${{ matrix.python }}".replace("==", "") -ne "$pythonVersion"){
335+
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
336+
exit 1
337+
}
338+
$pythonVersion
339+
shell: pwsh
340+
341+
- name: Run simple code
342+
run: python -c 'import math; print(math.factorial(5))'
343+
344+
setup-versions-from-pipfile-with-python_full_version:
345+
name: Setup ${{ matrix.python }} ${{ matrix.os }} Pipfile with python_full_version
346+
runs-on: ${{ matrix.os }}
347+
strategy:
348+
fail-fast: false
349+
matrix:
350+
os:
351+
[
352+
macos-latest,
353+
windows-latest,
354+
ubuntu-20.04,
355+
ubuntu-22.04,
356+
ubuntu-22.04-arm,
357+
macos-13,
358+
ubuntu-latest,
359+
ubuntu-24.04-arm
360+
]
361+
python: [3.9.13, 3.10.11, 3.11.9, 3.13.2]
362+
steps:
363+
- name: Checkout
364+
uses: actions/checkout@v4
365+
366+
- name: build-version-file ${{ matrix.python }}
367+
run: |
368+
echo '[requires]
369+
python_full_version = "${{ matrix.python }}"
370+
' > Pipenv
371+
372+
- name: setup-python ${{ matrix.python }}
373+
id: setup-python
374+
uses: ./
375+
with:
376+
python-version-file: Pipenv
377+
378+
- name: Check python-path
379+
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
380+
shell: bash
381+
382+
- name: Validate version
383+
run: |
384+
$pythonVersion = (python --version)
385+
if ("Python ${{ matrix.python }}".replace("==", "") -ne "$pythonVersion"){
386+
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
387+
exit 1
388+
}
389+
$pythonVersion
390+
shell: pwsh
391+
392+
- name: Run simple code
393+
run: python -c 'import math; print(math.factorial(5))'
394+
293395
setup-pre-release-version-from-manifest:
294396
name: Setup 3.14.0-alpha.6 ${{ matrix.os }}
295397
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
getVersionInputFromPlainFile,
1414
getVersionInputFromTomlFile,
15+
getVersionInputFromPipfileFile,
1516
getNextPageUrl,
1617
isGhes,
1718
IS_WINDOWS,
@@ -216,6 +217,44 @@ describe('Version from file test', () => {
216217
expect(_fn(toolVersionFilePath)).toEqual(['3.14t-dev']);
217218
}
218219
);
220+
221+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
222+
'Version from python_version in Pipfile',
223+
async _fn => {
224+
await io.mkdirP(tempDir);
225+
const pythonVersionFileName = 'Pipfile';
226+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
227+
const pythonVersion = '3.7';
228+
const pythonVersionFileContent = `[requires]\npython_version = "${pythonVersion}"`;
229+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
230+
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
231+
}
232+
);
233+
234+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
235+
'Version from python_full_version in Pipfile',
236+
async _fn => {
237+
await io.mkdirP(tempDir);
238+
const pythonVersionFileName = 'Pipfile';
239+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
240+
const pythonVersion = '3.7.0';
241+
const pythonVersionFileContent = `[requires]\npython_full_version = "${pythonVersion}"`;
242+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
243+
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
244+
}
245+
);
246+
247+
it.each([getVersionInputFromPipfileFile, getVersionInputFromFile])(
248+
'Pipfile undefined version',
249+
async _fn => {
250+
await io.mkdirP(tempDir);
251+
const pythonVersionFileName = 'Pipfile';
252+
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
253+
const pythonVersionFileContent = ``;
254+
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
255+
expect(_fn(pythonVersionFilePath)).toEqual([]);
256+
}
257+
);
219258
});
220259

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

dist/setup/index.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97759,7 +97759,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9775997759
return (mod && mod.__esModule) ? mod : { "default": mod };
9776097760
};
9776197761
Object.defineProperty(exports, "__esModule", ({ value: true }));
97762-
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;
97762+
exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromPipfileFile = 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;
9776397763
/* eslint no-unsafe-finally: "off" */
9776497764
const cache = __importStar(__nccwpck_require__(5116));
9776597765
const core = __importStar(__nccwpck_require__(7484));
@@ -98014,7 +98014,37 @@ function getVersionInputFromToolVersions(versionFile) {
9801498014
}
9801598015
exports.getVersionInputFromToolVersions = getVersionInputFromToolVersions;
9801698016
/**
98017-
* Python version extracted from a plain, .tool-versions or TOML file.
98017+
* Python version extracted from the Pipfile file.
98018+
*/
98019+
function getVersionInputFromPipfileFile(versionFile) {
98020+
core.debug(`Trying to resolve version form ${versionFile}`);
98021+
let pipfileFile = fs_1.default.readFileSync(versionFile, 'utf8');
98022+
// Normalize the line endings in the pipfileFile
98023+
pipfileFile = pipfileFile.replace(/\r\n/g, '\n');
98024+
const pipfileConfig = toml.parse(pipfileFile);
98025+
const keys = ['requires'];
98026+
if (!('requires' in pipfileConfig)) {
98027+
core.warning(`No Python version found in ${versionFile}`);
98028+
return [];
98029+
}
98030+
if ('python_full_version' in pipfileConfig['requires']) {
98031+
// specifies a full python version
98032+
keys.push('python_full_version');
98033+
}
98034+
else {
98035+
keys.push('python_version');
98036+
}
98037+
const versions = [];
98038+
const version = extractValue(pipfileConfig, keys);
98039+
if (version !== undefined) {
98040+
versions.push(version);
98041+
}
98042+
core.info(`Extracted ${versions} from ${versionFile}`);
98043+
return [extractValue(pipfileConfig, keys)];
98044+
}
98045+
exports.getVersionInputFromPipfileFile = getVersionInputFromPipfileFile;
98046+
/**
98047+
* Python version extracted from a plain, .tool-versions, Pipfile or TOML file.
9801898048
*/
9801998049
function getVersionInputFromFile(versionFile) {
9802098050
if (versionFile.endsWith('.toml')) {
@@ -98023,6 +98053,9 @@ function getVersionInputFromFile(versionFile) {
9802398053
else if (versionFile.match('.tool-versions')) {
9802498054
return getVersionInputFromToolVersions(versionFile);
9802598055
}
98056+
else if (versionFile.match('Pipfile')) {
98057+
return getVersionInputFromPipfileFile(versionFile);
98058+
}
9802698059
else {
9802798060
return getVersionInputFromPlainFile(versionFile);
9802898061
}

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
@@ -310,14 +310,50 @@ export function getVersionInputFromToolVersions(versionFile: string): string[] {
310310
return [];
311311
}
312312
}
313+
314+
/**
315+
* Python version extracted from the Pipfile file.
316+
*/
317+
export function getVersionInputFromPipfileFile(versionFile: string): string[] {
318+
core.debug(`Trying to resolve version form ${versionFile}`);
319+
320+
let pipfileFile = fs.readFileSync(versionFile, 'utf8');
321+
// Normalize the line endings in the pipfileFile
322+
pipfileFile = pipfileFile.replace(/\r\n/g, '\n');
323+
324+
const pipfileConfig = toml.parse(pipfileFile);
325+
const keys = ['requires'];
326+
327+
if (!('requires' in pipfileConfig)) {
328+
core.warning(`No Python version found in ${versionFile}`);
329+
return [];
330+
}
331+
if ('python_full_version' in (pipfileConfig['requires'] as toml.JsonMap)) {
332+
// specifies a full python version
333+
keys.push('python_full_version');
334+
} else {
335+
keys.push('python_version');
336+
}
337+
const versions = [];
338+
const version = extractValue(pipfileConfig, keys);
339+
if (version !== undefined) {
340+
versions.push(version);
341+
}
342+
343+
core.info(`Extracted ${versions} from ${versionFile}`);
344+
return [extractValue(pipfileConfig, keys)] as string[];
345+
}
346+
313347
/**
314-
* Python version extracted from a plain, .tool-versions or TOML file.
348+
* Python version extracted from a plain, .tool-versions, Pipfile or TOML file.
315349
*/
316350
export function getVersionInputFromFile(versionFile: string): string[] {
317351
if (versionFile.endsWith('.toml')) {
318352
return getVersionInputFromTomlFile(versionFile);
319353
} else if (versionFile.match('.tool-versions')) {
320354
return getVersionInputFromToolVersions(versionFile);
355+
} else if (versionFile.match('Pipfile')) {
356+
return getVersionInputFromPipfileFile(versionFile);
321357
} else {
322358
return getVersionInputFromPlainFile(versionFile);
323359
}

0 commit comments

Comments
 (0)