mirror of
https://github.com/actions/setup-python.git
synced 2025-04-24 07:22:14 +00:00
add check-latest for python versions
This commit is contained in:
parent
c57f79353b
commit
4841389b47
9 changed files with 2136 additions and 1635 deletions
23
.github/workflows/test-python.yml
vendored
23
.github/workflows/test-python.yml
vendored
|
@ -91,3 +91,26 @@ jobs:
|
||||||
- name: Run simple code
|
- name: Run simple code
|
||||||
run: python -c 'import math; print(math.factorial(5))'
|
run: python -c 'import math; print(math.factorial(5))'
|
||||||
|
|
||||||
|
check-latest:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
python-version: ["3.8", "3.9", "3.10"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup Python and check latest
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
check-latest: true
|
||||||
|
- name: Validate version
|
||||||
|
run: |
|
||||||
|
$pythonVersion = (python --version)
|
||||||
|
if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){
|
||||||
|
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$pythonVersion
|
||||||
|
shell: pwsh
|
|
@ -1,6 +1,7 @@
|
||||||
import io = require('@actions/io');
|
import * as io from '@actions/io';
|
||||||
import fs = require('fs');
|
const fs = require('fs');
|
||||||
import path = require('path');
|
const path = require('path');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
const toolDir = path.join(
|
const toolDir = path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
@ -19,6 +20,7 @@ process.env['RUNNER_TOOL_CACHE'] = toolDir;
|
||||||
process.env['RUNNER_TEMP'] = tempDir;
|
process.env['RUNNER_TEMP'] = tempDir;
|
||||||
|
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as core from '@actions/core';
|
||||||
import * as finder from '../src/find-python';
|
import * as finder from '../src/find-python';
|
||||||
import * as installer from '../src/install-python';
|
import * as installer from '../src/install-python';
|
||||||
|
|
||||||
|
@ -31,6 +33,9 @@ describe('Finder tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Finds Python if it is installed', async () => {
|
it('Finds Python if it is installed', async () => {
|
||||||
|
const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
|
||||||
|
getBooleanInputSpy.mockImplementation((input) => false);
|
||||||
|
|
||||||
const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
|
const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
|
||||||
await io.mkdirP(pythonDir);
|
await io.mkdirP(pythonDir);
|
||||||
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
|
@ -42,6 +47,9 @@ describe('Finder tests', () => {
|
||||||
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
||||||
|
|
||||||
|
const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
|
||||||
|
getBooleanInputSpy.mockImplementation((input) => false);
|
||||||
|
|
||||||
const installSpy: jest.SpyInstance = jest.spyOn(
|
const installSpy: jest.SpyInstance = jest.spyOn(
|
||||||
installer,
|
installer,
|
||||||
'installCpythonFromRelease'
|
'installCpythonFromRelease'
|
||||||
|
@ -59,6 +67,9 @@ describe('Finder tests', () => {
|
||||||
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
||||||
|
|
||||||
|
const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
|
||||||
|
getBooleanInputSpy.mockImplementation((input) => false);
|
||||||
|
|
||||||
const installSpy: jest.SpyInstance = jest.spyOn(
|
const installSpy: jest.SpyInstance = jest.spyOn(
|
||||||
installer,
|
installer,
|
||||||
'installCpythonFromRelease'
|
'installCpythonFromRelease'
|
||||||
|
@ -77,6 +88,53 @@ describe('Finder tests', () => {
|
||||||
await finder.useCpythonVersion('1.2.3-beta.2', 'x64');
|
await finder.useCpythonVersion('1.2.3-beta.2', 'x64');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Check-latest true, finds the latest version in the manifest', async () => {
|
||||||
|
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
|
||||||
|
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
|
||||||
|
|
||||||
|
const getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput');
|
||||||
|
getBooleanInputSpy.mockImplementation((input) => true);
|
||||||
|
|
||||||
|
const cnSpy: jest.SpyInstance = jest.spyOn(process.stdout, 'write');
|
||||||
|
cnSpy.mockImplementation(line => {
|
||||||
|
// uncomment to debug
|
||||||
|
// process.stderr.write('write:' + line + '\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
const infoSpy: jest.SpyInstance = jest.spyOn(core, 'info');
|
||||||
|
infoSpy.mockImplementation(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const debugSpy: jest.SpyInstance = jest.spyOn(core, 'debug');
|
||||||
|
debugSpy.mockImplementation(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const pythonDir: string = path.join(toolDir, 'Python', '1.2.2', 'x64');
|
||||||
|
const expPath: string = path.join(toolDir, 'Python', '1.2.3', 'x64');
|
||||||
|
|
||||||
|
const installSpy: jest.SpyInstance = jest.spyOn(
|
||||||
|
installer,
|
||||||
|
'installCpythonFromRelease'
|
||||||
|
);
|
||||||
|
installSpy.mockImplementation(async () => {
|
||||||
|
await io.mkdirP(expPath);
|
||||||
|
fs.writeFileSync(`${expPath}.complete`, 'hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
await io.mkdirP(pythonDir);
|
||||||
|
await io.rmRF(expPath);
|
||||||
|
|
||||||
|
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
|
||||||
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
|
await finder.useCpythonVersion('1.2', 'x64');
|
||||||
|
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
|
||||||
|
expect(infoSpy).toHaveBeenCalledWith('Version 1.2.3 was not found in the local cache');
|
||||||
|
expect(cnSpy).toHaveBeenCalledWith(`::add-path::${expPath}${os.EOL}`);
|
||||||
|
});
|
||||||
|
|
||||||
it('Errors if Python is not installed', async () => {
|
it('Errors if Python is not installed', async () => {
|
||||||
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
|
||||||
let thrown = false;
|
let thrown = false;
|
||||||
|
|
|
@ -11,6 +11,9 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
architecture:
|
architecture:
|
||||||
description: 'The target architecture (x86, x64) of the Python interpreter.'
|
description: 'The target architecture (x86, x64) of the Python interpreter.'
|
||||||
|
check-latest:
|
||||||
|
description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec.'
|
||||||
|
default: false
|
||||||
token:
|
token:
|
||||||
description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.
|
description: Used to pull python distributions from actions/python-versions. Since there's a default, this is typically not supplied by the user.
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
|
|
1986
dist/cache-save/index.js
vendored
1986
dist/cache-save/index.js
vendored
File diff suppressed because it is too large
Load diff
1603
dist/setup/index.js
vendored
1603
dist/setup/index.js
vendored
File diff suppressed because it is too large
Load diff
48
package-lock.json
generated
48
package-lock.json
generated
|
@ -10,7 +10,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^2.0.2",
|
"@actions/cache": "^2.0.2",
|
||||||
"@actions/core": "^1.2.3",
|
"@actions/core": "^1.7.0",
|
||||||
"@actions/exec": "^1.1.0",
|
"@actions/exec": "^1.1.0",
|
||||||
"@actions/glob": "^0.2.0",
|
"@actions/glob": "^0.2.0",
|
||||||
"@actions/io": "^1.0.2",
|
"@actions/io": "^1.0.2",
|
||||||
|
@ -55,14 +55,6 @@
|
||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/cache/node_modules/@actions/http-client": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
|
||||||
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
|
||||||
"dependencies": {
|
|
||||||
"tunnel": "0.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/cache/node_modules/semver": {
|
"node_modules/@actions/cache/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
|
@ -72,9 +64,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/core": {
|
"node_modules/@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.7.0.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-7fPSS7yKOhTpgLMbw7lBLc1QJWvJBBAgyTX2PEhagWcKK8t0H8AKCoPMfnrHqIm5cRYH4QFPqD1/ruhuUE7YcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/http-client": "^1.0.11"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/exec": {
|
"node_modules/@actions/exec": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
@ -94,9 +89,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/http-client": {
|
"node_modules/@actions/http-client": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tunnel": "0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
|
@ -11362,14 +11357,6 @@
|
||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/http-client": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
|
||||||
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
|
||||||
"requires": {
|
|
||||||
"tunnel": "0.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
|
@ -11378,9 +11365,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.7.0.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-7fPSS7yKOhTpgLMbw7lBLc1QJWvJBBAgyTX2PEhagWcKK8t0H8AKCoPMfnrHqIm5cRYH4QFPqD1/ruhuUE7YcQ==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/http-client": "^1.0.11"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"@actions/exec": {
|
"@actions/exec": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
@ -11400,9 +11390,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@actions/http-client": {
|
"@actions/http-client": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz",
|
||||||
"integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==",
|
"integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tunnel": "0.0.6"
|
"tunnel": "0.0.6"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^2.0.2",
|
"@actions/cache": "^2.0.2",
|
||||||
"@actions/core": "^1.2.3",
|
"@actions/core": "^1.7.0",
|
||||||
"@actions/exec": "^1.1.0",
|
"@actions/exec": "^1.1.0",
|
||||||
"@actions/glob": "^0.2.0",
|
"@actions/glob": "^0.2.0",
|
||||||
"@actions/io": "^1.0.2",
|
"@actions/io": "^1.0.2",
|
||||||
|
|
|
@ -34,10 +34,25 @@ export async function useCpythonVersion(
|
||||||
version: string,
|
version: string,
|
||||||
architecture: string
|
architecture: string
|
||||||
): Promise<InstalledVersion> {
|
): Promise<InstalledVersion> {
|
||||||
|
let manifest: tc.IToolRelease[] | null = null;
|
||||||
const desugaredVersionSpec = desugarDevVersion(version);
|
const desugaredVersionSpec = desugarDevVersion(version);
|
||||||
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
|
||||||
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
|
||||||
|
|
||||||
|
const checkLatest = core.getBooleanInput('check-latest');
|
||||||
|
|
||||||
|
if (checkLatest) {
|
||||||
|
manifest = await installer.getManifest();
|
||||||
|
const resolvedVersion = (await installer.findReleaseFromManifest(semanticVersionSpec, architecture, manifest))?.version;
|
||||||
|
|
||||||
|
if(resolvedVersion) {
|
||||||
|
semanticVersionSpec = resolvedVersion;
|
||||||
|
core.info(`Resolved as '${semanticVersionSpec}'`);
|
||||||
|
} else {
|
||||||
|
core.info(`Failed to resolve version ${semanticVersionSpec} from manifest`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let installDir: string | null = tc.find(
|
let installDir: string | null = tc.find(
|
||||||
'Python',
|
'Python',
|
||||||
semanticVersionSpec,
|
semanticVersionSpec,
|
||||||
|
@ -49,7 +64,8 @@ export async function useCpythonVersion(
|
||||||
);
|
);
|
||||||
const foundRelease = await installer.findReleaseFromManifest(
|
const foundRelease = await installer.findReleaseFromManifest(
|
||||||
semanticVersionSpec,
|
semanticVersionSpec,
|
||||||
architecture
|
architecture,
|
||||||
|
manifest
|
||||||
);
|
);
|
||||||
|
|
||||||
if (foundRelease && foundRelease.files && foundRelease.files.length > 0) {
|
if (foundRelease && foundRelease.files && foundRelease.files.length > 0) {
|
||||||
|
|
|
@ -14,20 +14,26 @@ export const MANIFEST_URL = `https://raw.githubusercontent.com/${MANIFEST_REPO_O
|
||||||
|
|
||||||
export async function findReleaseFromManifest(
|
export async function findReleaseFromManifest(
|
||||||
semanticVersionSpec: string,
|
semanticVersionSpec: string,
|
||||||
architecture: string
|
architecture: string,
|
||||||
|
manifest: tc.IToolRelease[] | null
|
||||||
): Promise<tc.IToolRelease | undefined> {
|
): Promise<tc.IToolRelease | undefined> {
|
||||||
const manifest: tc.IToolRelease[] = await tc.getManifestFromRepo(
|
if(!manifest) {
|
||||||
MANIFEST_REPO_OWNER,
|
manifest = await getManifest();
|
||||||
MANIFEST_REPO_NAME,
|
}
|
||||||
AUTH,
|
|
||||||
MANIFEST_REPO_BRANCH
|
const foundRelease = await tc.findFromManifest(
|
||||||
);
|
|
||||||
return await tc.findFromManifest(
|
|
||||||
semanticVersionSpec,
|
semanticVersionSpec,
|
||||||
false,
|
false,
|
||||||
manifest,
|
manifest,
|
||||||
architecture
|
architecture
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return foundRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getManifest(): Promise<tc.IToolRelease[]> {
|
||||||
|
core.debug(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`);
|
||||||
|
return tc.getManifestFromRepo(MANIFEST_REPO_OWNER, MANIFEST_REPO_NAME, AUTH, MANIFEST_REPO_BRANCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function installPython(workingDirectory: string) {
|
async function installPython(workingDirectory: string) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue