From 036a5236741fd24c89eea80d1b76179e8e5f9214 Mon Sep 17 00:00:00 2001 From: Priya Gupta <147705955+priyagupta108@users.noreply.github.com> Date: Mon, 5 Aug 2024 22:53:34 +0530 Subject: [PATCH 1/3] Fix: Add `.zip` extension to Windows package downloads for `Expand-Archive` Compatibility (#916) * Fix: specify filename during Windows package download * Changed unit test download urls --- __tests__/utils.test.ts | 38 +++++++++++++++++++++++++++++++++++++- dist/setup/index.js | 22 +++++++++++++++++++--- src/install-pypy.ts | 6 ++++-- src/install-python.ts | 5 +++-- src/utils.ts | 14 ++++++++++++++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index f5e36478..c2c6bca5 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -12,7 +12,9 @@ import { getVersionInputFromFile, getVersionInputFromPlainFile, getVersionInputFromTomlFile, - getNextPageUrl + getNextPageUrl, + IS_WINDOWS, + getDownloadFileName } from '../src/utils'; jest.mock('@actions/cache'); @@ -159,3 +161,37 @@ describe('getNextPageUrl', () => { expect(getNextPageUrl(generateResponse(page2Links))).toBeNull(); }); }); + +describe('getDownloadFileName', () => { + const originalEnv = process.env; + const tempDir = path.join(__dirname, 'runner', 'temp'); + + beforeEach(() => { + process.env = {...originalEnv}; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it('should return the correct path on Windows', () => { + if (IS_WINDOWS) { + process.env['RUNNER_TEMP'] = tempDir; + const downloadUrl = + 'https://github.com/actions/sometool/releases/tag/1.2.3-20200402.6/sometool-1.2.3-win32-x64.zip'; + const expectedPath = path.join( + process.env.RUNNER_TEMP, + path.basename(downloadUrl) + ); + expect(getDownloadFileName(downloadUrl)).toBe(expectedPath); + } + }); + + it('should return undefined on non-Windows', () => { + if (!IS_WINDOWS) { + const downloadUrl = + 'https://github.com/actions/sometool/releases/tag/1.2.3-20200402.6/sometool-1.2.3-linux-x64.tar.gz'; + expect(getDownloadFileName(downloadUrl)).toBeUndefined(); + } + }); +}); diff --git a/dist/setup/index.js b/dist/setup/index.js index 039a5f5b..e3bb93ba 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -91441,7 +91441,8 @@ function installPyPy(pypyVersion, pythonVersion, architecture, allowPreReleases, const downloadUrl = `${foundAsset.download_url}`; core.info(`Downloading PyPy from "${downloadUrl}" ...`); try { - const pypyPath = yield tc.downloadTool(downloadUrl); + const fileName = (0, utils_1.getDownloadFileName)(downloadUrl); + const pypyPath = yield tc.downloadTool(downloadUrl, fileName); core.info('Extracting downloaded archive...'); if (utils_1.IS_WINDOWS) { downloadDir = yield tc.extractZip(pypyPath); @@ -91703,7 +91704,8 @@ function installCpythonFromRelease(release) { core.info(`Download from "${downloadUrl}"`); let pythonPath = ''; try { - pythonPath = yield tc.downloadTool(downloadUrl, undefined, AUTH); + const fileName = (0, utils_1.getDownloadFileName)(downloadUrl); + pythonPath = yield tc.downloadTool(downloadUrl, fileName, AUTH); core.info('Extract downloaded archive'); let pythonExtractedFolder; if (utils_1.IS_WINDOWS) { @@ -91938,7 +91940,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -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.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__(7799)); const core = __importStar(__nccwpck_require__(2186)); @@ -92198,6 +92200,20 @@ function getNextPageUrl(response) { return null; } exports.getNextPageUrl = getNextPageUrl; +/** + * Add temporary fix for Windows + * On Windows, it is necessary to retain the .zip extension for proper extraction. + * because the tc.extractZip() failure due to tc.downloadTool() not adding .zip extension. + * Related issue: https://github.com/actions/toolkit/issues/1179 + * Related issue: https://github.com/actions/setup-python/issues/819 + */ +function getDownloadFileName(downloadUrl) { + const tempDir = process.env.RUNNER_TEMP || '.'; + return exports.IS_WINDOWS + ? path.join(tempDir, path.basename(downloadUrl)) + : undefined; +} +exports.getDownloadFileName = getDownloadFileName; /***/ }), diff --git a/src/install-pypy.ts b/src/install-pypy.ts index b624f1d7..75922110 100644 --- a/src/install-pypy.ts +++ b/src/install-pypy.ts @@ -14,7 +14,8 @@ import { createSymlinkInFolder, isNightlyKeyword, writeExactPyPyVersionFile, - getBinaryDirectory + getBinaryDirectory, + getDownloadFileName } from './utils'; export async function installPyPy( @@ -69,7 +70,8 @@ export async function installPyPy( core.info(`Downloading PyPy from "${downloadUrl}" ...`); try { - const pypyPath = await tc.downloadTool(downloadUrl); + const fileName = getDownloadFileName(downloadUrl); + const pypyPath = await tc.downloadTool(downloadUrl, fileName); core.info('Extracting downloaded archive...'); if (IS_WINDOWS) { diff --git a/src/install-python.ts b/src/install-python.ts index 3abdfde3..d3421bf8 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -4,7 +4,7 @@ import * as tc from '@actions/tool-cache'; import * as exec from '@actions/exec'; import * as httpm from '@actions/http-client'; import {ExecOptions} from '@actions/exec/lib/interfaces'; -import {IS_WINDOWS, IS_LINUX} from './utils'; +import {IS_WINDOWS, IS_LINUX, getDownloadFileName} from './utils'; const TOKEN = core.getInput('token'); const AUTH = !TOKEN ? undefined : `token ${TOKEN}`; @@ -98,7 +98,8 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { core.info(`Download from "${downloadUrl}"`); let pythonPath = ''; try { - pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH); + const fileName = getDownloadFileName(downloadUrl); + pythonPath = await tc.downloadTool(downloadUrl, fileName, AUTH); core.info('Extract downloaded archive'); let pythonExtractedFolder; if (IS_WINDOWS) { diff --git a/src/utils.ts b/src/utils.ts index 644b4af5..3d1b3dff 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -310,3 +310,17 @@ export function getNextPageUrl(response: ifm.TypedResponse) { } return null; } + +/** + * Add temporary fix for Windows + * On Windows, it is necessary to retain the .zip extension for proper extraction. + * because the tc.extractZip() failure due to tc.downloadTool() not adding .zip extension. + * Related issue: https://github.com/actions/toolkit/issues/1179 + * Related issue: https://github.com/actions/setup-python/issues/819 + */ +export function getDownloadFileName(downloadUrl: string): string | undefined { + const tempDir = process.env.RUNNER_TEMP || '.'; + return IS_WINDOWS + ? path.join(tempDir, path.basename(downloadUrl)) + : undefined; +} From 80b49d3ed89312896dbdcbefc2ddb159c7f8ca43 Mon Sep 17 00:00:00 2001 From: Zxilly <31370133+Zxilly@users.noreply.github.com> Date: Thu, 8 Aug 2024 04:12:32 +0800 Subject: [PATCH 2/3] fix: add arch to cache key (#896) * fix: add arch to cache key * test: update tests accordingly --- __tests__/cache-restore.test.ts | 6 +++--- dist/setup/index.js | 12 ++++++------ src/cache-distributions/pip-cache.ts | 8 ++++---- src/cache-distributions/pipenv-cache.ts | 2 +- src/cache-distributions/poetry-cache.ts | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts index a1a8d8d2..d84c2296 100644 --- a/__tests__/cache-restore.test.ts +++ b/__tests__/cache-restore.test.ts @@ -186,15 +186,15 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py if (process.platform === 'linux' && packageManager === 'pip') { expect(infoSpy).toHaveBeenCalledWith( - `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-20.04-Ubuntu-python-${pythonVersion}-${packageManager}-${fileHash}` + `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-${process.arch}-20.04-Ubuntu-python-${pythonVersion}-${packageManager}-${fileHash}` ); } else if (packageManager === 'poetry') { expect(infoSpy).toHaveBeenCalledWith( - `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-v2-${fileHash}` + `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-${process.arch}-python-${pythonVersion}-${packageManager}-v2-${fileHash}` ); } else { expect(infoSpy).toHaveBeenCalledWith( - `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-${fileHash}` + `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-${process.arch}-python-${pythonVersion}-${packageManager}-${fileHash}` ); } }, diff --git a/dist/setup/index.js b/dist/setup/index.js index e3bb93ba..0530081c 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -90423,12 +90423,12 @@ class PipCache extends cache_distributor_1.default { let restoreKey = ''; if (utils_1.IS_LINUX) { const osInfo = yield (0, utils_1.getLinuxInfo)(); - primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; - restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`; + primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`; } else { - primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; - restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`; + primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}`; } return { primaryKey, @@ -90514,7 +90514,7 @@ class PipenvCache extends cache_distributor_1.default { computeKeys() { return __awaiter(this, void 0, void 0, function* () { const hash = yield glob.hashFiles(this.patterns); - const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${process.arch}-${this.pythonVersion}-${this.packageManager}-${hash}`; const restoreKey = undefined; return { primaryKey, @@ -90627,7 +90627,7 @@ class PoetryCache extends cache_distributor_1.default { return __awaiter(this, void 0, void 0, function* () { const hash = yield glob.hashFiles(this.patterns); // "v2" is here to invalidate old caches of this cache distributor, which were created broken: - const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`; + const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`; const restoreKey = undefined; return { primaryKey, diff --git a/src/cache-distributions/pip-cache.ts b/src/cache-distributions/pip-cache.ts index 2ec3f9b0..d64ae931 100644 --- a/src/cache-distributions/pip-cache.ts +++ b/src/cache-distributions/pip-cache.ts @@ -67,11 +67,11 @@ class PipCache extends CacheDistributor { if (IS_LINUX) { const osInfo = await getLinuxInfo(); - primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; - restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`; + primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`; } else { - primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; - restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`; + primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}`; } return { diff --git a/src/cache-distributions/pipenv-cache.ts b/src/cache-distributions/pipenv-cache.ts index fd1994a6..8ddcbed8 100644 --- a/src/cache-distributions/pipenv-cache.ts +++ b/src/cache-distributions/pipenv-cache.ts @@ -32,7 +32,7 @@ class PipenvCache extends CacheDistributor { protected async computeKeys() { const hash = await glob.hashFiles(this.patterns); - const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; + const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; const restoreKey = undefined; return { primaryKey, diff --git a/src/cache-distributions/poetry-cache.ts b/src/cache-distributions/poetry-cache.ts index c31fb05d..cd3a189b 100644 --- a/src/cache-distributions/poetry-cache.ts +++ b/src/cache-distributions/poetry-cache.ts @@ -47,7 +47,7 @@ class PoetryCache extends CacheDistributor { protected async computeKeys() { const hash = await glob.hashFiles(this.patterns); // "v2" is here to invalidate old caches of this cache distributor, which were created broken: - const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`; + const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`; const restoreKey = undefined; return { primaryKey, From 2bd53f9a4d1dd1cd21eaffcc01a7b91a8e73ea4c Mon Sep 17 00:00:00 2001 From: gowridurgad <159780674+gowridurgad@users.noreply.github.com> Date: Thu, 8 Aug 2024 23:24:56 +0530 Subject: [PATCH 3/3] Documentation update for caching poetry dependencies (#908) * Create testing.yml * Update testing.yml * Fix for parsing version number from TOML 1.0.0 pyproject.toml file * Delete .github/workflows/testing.yml * fixed license issue * updated the Note * updated doc * updated the doc * npm run build * Mark up corrections --------- Co-authored-by: gowridurgad Co-authored-by: HarithaVattikuti <73516759+HarithaVattikuti@users.noreply.github.com> --- dist/setup/index.js | 2 +- docs/advanced-usage.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 0530081c..126f4a32 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -90514,7 +90514,7 @@ class PipenvCache extends cache_distributor_1.default { computeKeys() { return __awaiter(this, void 0, void 0, function* () { const hash = yield glob.hashFiles(this.patterns); - const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${process.arch}-${this.pythonVersion}-${this.packageManager}-${hash}`; + const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${process.arch}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; const restoreKey = undefined; return { primaryKey, diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 501c8fd4..65ccda28 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -319,6 +319,7 @@ steps: - run: poetry install - run: poetry run pytest ``` +>**Note:** If the `setup-python` version does not match the version specified in `pyproject.toml` and the python version in `pyproject.toml` is less than the runner's python version, `poetry install` will default to using the runner's Python version. **Using a list of file paths to cache dependencies** ```yaml