From ba0d4b0591677f14797410855de5e03c5a4067c4 Mon Sep 17 00:00:00 2001 From: gowridurgad Date: Thu, 23 Jul 2026 11:43:54 +0530 Subject: [PATCH 1/5] Version suffix --- dist/cache-save/index.js | 31 +++++++++++++++++++++++ dist/setup/index.js | 53 ++++++++++++++++++++++++++++++++++++++-- src/find-python.ts | 15 +++++++++--- src/install-python.ts | 30 ++++++++++++++++++++++- src/utils.ts | 26 ++++++++++++++++++++ 5 files changed, 149 insertions(+), 6 deletions(-) diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index 489447525..4c879b256 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -97477,6 +97477,37 @@ function getDownloadFileName(downloadUrl) { ? path.join(tempDir, path.basename(downloadUrl)) : undefined; } +function getVersionCacheSuffix() { + if (!utils_IS_LINUX) + return ''; + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') + return ''; + try { + const content = fs.readFileSync('/etc/os-release', 'utf8'); + const map = {}; + for (const line of content.split('\n')) { + const eq = line.indexOf('='); + if (eq <= 0) + continue; + const k = line.slice(0, eq).trim(); + const v = line + .slice(eq + 1) + .trim() + .replace(/^"|"$/g, ''); + if (k && v) + map[k] = v; + } + const id = map['ID']; + const versionId = map['VERSION_ID']; + if (!id || !versionId) + return ''; + const safe = `${id}-${versionId}`.replace(/[^A-Za-z0-9-]/g, '-'); + return `-${safe}`; + } + catch { + return ''; + } +} ;// CONCATENATED MODULE: ./src/cache-distributions/cache-distributor.ts diff --git a/dist/setup/index.js b/dist/setup/index.js index af2263ef0..5a3f1a5fc 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97469,6 +97469,37 @@ function getDownloadFileName(downloadUrl) { ? external_path_.join(tempDir, external_path_.basename(downloadUrl)) : undefined; } +function getVersionCacheSuffix() { + if (!IS_LINUX) + return ''; + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') + return ''; + try { + const content = external_fs_default().readFileSync('/etc/os-release', 'utf8'); + const map = {}; + for (const line of content.split('\n')) { + const eq = line.indexOf('='); + if (eq <= 0) + continue; + const k = line.slice(0, eq).trim(); + const v = line + .slice(eq + 1) + .trim() + .replace(/^"|"$/g, ''); + if (k && v) + map[k] = v; + } + const id = map['ID']; + const versionId = map['VERSION_ID']; + if (!id || !versionId) + return ''; + const safe = `${id}-${versionId}`.replace(/[^A-Za-z0-9-]/g, '-'); + return `-${safe}`; + } + catch { + return ''; + } +} ;// CONCATENATED MODULE: ./node_modules/@actions/tool-cache/lib/manifest.js var manifest_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { @@ -98488,6 +98519,24 @@ async function installCpythonFromRelease(release) { } info('Execute installation script'); await installPython(pythonExtractedFolder); + const suffix = getVersionCacheSuffix(); + if (suffix) { + const toolCache = process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (toolCache) { + const origDir = external_path_.join(toolCache, 'Python', release.version); + const newDir = external_path_.join(toolCache, 'Python', release.version + suffix); + try { + if (external_fs_namespaceObject.existsSync(origDir) && !external_fs_namespaceObject.existsSync(newDir)) { + external_fs_namespaceObject.renameSync(origDir, newDir); + info(`Renamed cache dir for OS scoping: ${origDir} -> ${newDir}`); + } + } + catch (e) { + warning(`Failed to rename Python cache dir for OS scoping: ${e.message}`); + } + } + } } catch (err) { if (err instanceof HTTPError) { @@ -98575,14 +98624,14 @@ async function useCpythonVersion(version, architecture, updateEnvironment, check info(`Failed to resolve version ${semanticVersionSpec} from manifest`); } } - let installDir = find('Python', semanticVersionSpec, architecture); + let installDir = find('Python', semanticVersionSpec + getVersionCacheSuffix(), architecture); if (!installDir) { info(`Version ${semanticVersionSpec} was not found in the local cache`); const foundRelease = await findReleaseFromManifest(semanticVersionSpec, architecture, manifest); if (foundRelease && foundRelease.files && foundRelease.files.length > 0) { info(`Version ${semanticVersionSpec} is available for downloading`); await installCpythonFromRelease(foundRelease); - installDir = find('Python', semanticVersionSpec, architecture); + installDir = find('Python', semanticVersionSpec + getVersionCacheSuffix(), architecture); } } if (!installDir) { diff --git a/src/find-python.ts b/src/find-python.ts index 665188887..3d762d042 100644 --- a/src/find-python.ts +++ b/src/find-python.ts @@ -1,6 +1,11 @@ import * as os from 'os'; import * as path from 'path'; -import {IS_WINDOWS, IS_LINUX, getOSInfo} from './utils.js'; +import { + IS_WINDOWS, + IS_LINUX, + getOSInfo, + getVersionCacheSuffix +} from './utils.js'; import * as semver from 'semver'; @@ -101,7 +106,7 @@ export async function useCpythonVersion( let installDir: string | null = tc.find( 'Python', - semanticVersionSpec, + semanticVersionSpec + getVersionCacheSuffix(), architecture ); if (!installDir) { @@ -118,7 +123,11 @@ export async function useCpythonVersion( core.info(`Version ${semanticVersionSpec} is available for downloading`); await installer.installCpythonFromRelease(foundRelease); - installDir = tc.find('Python', semanticVersionSpec, architecture); + installDir = tc.find( + 'Python', + semanticVersionSpec + getVersionCacheSuffix(), + architecture + ); } } diff --git a/src/install-python.ts b/src/install-python.ts index c787def70..29b2dd8e4 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -6,7 +6,12 @@ import {ExecOptions} from '@actions/exec'; import * as httpm from '@actions/http-client'; import * as fs from 'fs'; import * as semver from 'semver'; -import {IS_WINDOWS, IS_LINUX, getDownloadFileName} from './utils.js'; +import { + IS_WINDOWS, + IS_LINUX, + getDownloadFileName, + getVersionCacheSuffix +} from './utils.js'; import {IToolRelease} from '@actions/tool-cache'; const TOKEN = core.getInput('token'); @@ -302,6 +307,29 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { core.info('Execute installation script'); await installPython(pythonExtractedFolder); + + const suffix = getVersionCacheSuffix(); + if (suffix) { + const toolCache = + process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (toolCache) { + const origDir = path.join(toolCache, 'Python', release.version); + const newDir = path.join(toolCache, 'Python', release.version + suffix); + try { + if (fs.existsSync(origDir) && !fs.existsSync(newDir)) { + fs.renameSync(origDir, newDir); + core.info( + `Renamed cache dir for OS scoping: ${origDir} -> ${newDir}` + ); + } + } catch (e) { + core.warning( + `Failed to rename Python cache dir for OS scoping: ${(e as Error).message}` + ); + } + } + } } catch (err) { if (err instanceof tc.HTTPError) { // Rate limit? diff --git a/src/utils.ts b/src/utils.ts index c75d17dcd..efd293831 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -445,3 +445,29 @@ export function getDownloadFileName(downloadUrl: string): string | undefined { ? path.join(tempDir, path.basename(downloadUrl)) : undefined; } + +export function getVersionCacheSuffix(): string { + if (!IS_LINUX) return ''; + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') return ''; + try { + const content = fs.readFileSync('/etc/os-release', 'utf8'); + const map: Record = {}; + for (const line of content.split('\n')) { + const eq = line.indexOf('='); + if (eq <= 0) continue; + const k = line.slice(0, eq).trim(); + const v = line + .slice(eq + 1) + .trim() + .replace(/^"|"$/g, ''); + if (k && v) map[k] = v; + } + const id = map['ID']; + const versionId = map['VERSION_ID']; + if (!id || !versionId) return ''; + const safe = `${id}-${versionId}`.replace(/[^A-Za-z0-9-]/g, '-'); + return `-${safe}`; + } catch { + return ''; + } +} From bc169548e5a55b7519441cb2e655f4c46c245797 Mon Sep 17 00:00:00 2001 From: gowridurgad Date: Thu, 23 Jul 2026 12:16:41 +0530 Subject: [PATCH 2/5] updated --- src/find-python.ts | 43 +++++++++++++++++++++++++++++++++++-------- src/install-python.ts | 5 +++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/find-python.ts b/src/find-python.ts index 3d762d042..f168550c6 100644 --- a/src/find-python.ts +++ b/src/find-python.ts @@ -1,5 +1,6 @@ import * as os from 'os'; import * as path from 'path'; +import * as fs from 'fs'; import { IS_WINDOWS, IS_LINUX, @@ -57,6 +58,37 @@ async function installPip(pythonLocation: string) { } } +function findScopedPython( + semanticVersionSpec: string, + architecture: string +): string | null { + const suffix = getVersionCacheSuffix(); + const toolCache = + process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (!suffix || !toolCache) { + return tc.find('Python', semanticVersionSpec, architecture); + } + const pythonRoot = path.join(toolCache, 'Python'); + if (!fs.existsSync(pythonRoot)) return null; + let bestVer: string | null = null; + let bestDir: string | null = null; + for (const entry of fs.readdirSync(pythonRoot)) { + if (!entry.endsWith(suffix)) continue; + const ver = entry.slice(0, entry.length - suffix.length); + if (!semver.valid(ver)) continue; + if (!semver.satisfies(ver, semanticVersionSpec)) continue; + const candidate = path.join(pythonRoot, entry, architecture); + const marker = path.join(pythonRoot, entry + '.complete'); + if (!fs.existsSync(candidate) || !fs.existsSync(marker)) continue; + if (!bestVer || semver.gt(ver, bestVer)) { + bestVer = ver; + bestDir = candidate; + } + } + return bestDir; +} + export async function useCpythonVersion( version: string, architecture: string, @@ -104,9 +136,8 @@ export async function useCpythonVersion( } } - let installDir: string | null = tc.find( - 'Python', - semanticVersionSpec + getVersionCacheSuffix(), + let installDir: string | null = findScopedPython( + semanticVersionSpec, architecture ); if (!installDir) { @@ -123,11 +154,7 @@ export async function useCpythonVersion( core.info(`Version ${semanticVersionSpec} is available for downloading`); await installer.installCpythonFromRelease(foundRelease); - installDir = tc.find( - 'Python', - semanticVersionSpec + getVersionCacheSuffix(), - architecture - ); + installDir = findScopedPython(semanticVersionSpec, architecture); } } diff --git a/src/install-python.ts b/src/install-python.ts index 29b2dd8e4..c7054263e 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -316,6 +316,8 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { if (toolCache) { const origDir = path.join(toolCache, 'Python', release.version); const newDir = path.join(toolCache, 'Python', release.version + suffix); + const origMarker = origDir + '.complete'; + const newMarker = newDir + '.complete'; try { if (fs.existsSync(origDir) && !fs.existsSync(newDir)) { fs.renameSync(origDir, newDir); @@ -323,6 +325,9 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { `Renamed cache dir for OS scoping: ${origDir} -> ${newDir}` ); } + if (fs.existsSync(origMarker) && !fs.existsSync(newMarker)) { + fs.renameSync(origMarker, newMarker); + } } catch (e) { core.warning( `Failed to rename Python cache dir for OS scoping: ${(e as Error).message}` From 50a6e605130e9853070f951f357c2686e21e67e0 Mon Sep 17 00:00:00 2001 From: gowridurgad Date: Thu, 23 Jul 2026 12:20:12 +0530 Subject: [PATCH 3/5] dist --- dist/setup/index.js | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 5a3f1a5fc..a61903cd1 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -98526,11 +98526,16 @@ async function installCpythonFromRelease(release) { if (toolCache) { const origDir = external_path_.join(toolCache, 'Python', release.version); const newDir = external_path_.join(toolCache, 'Python', release.version + suffix); + const origMarker = origDir + '.complete'; + const newMarker = newDir + '.complete'; try { if (external_fs_namespaceObject.existsSync(origDir) && !external_fs_namespaceObject.existsSync(newDir)) { external_fs_namespaceObject.renameSync(origDir, newDir); info(`Renamed cache dir for OS scoping: ${origDir} -> ${newDir}`); } + if (external_fs_namespaceObject.existsSync(origMarker) && !external_fs_namespaceObject.existsSync(newMarker)) { + external_fs_namespaceObject.renameSync(origMarker, newMarker); + } } catch (e) { warning(`Failed to rename Python cache dir for OS scoping: ${e.message}`); @@ -98567,6 +98572,7 @@ async function installCpythonFromRelease(release) { + // Python has "scripts" or "bin" directories where command-line tools that come with packages are installed. // This is where pip is, along with anything that pip installs. // There is a separate directory for `pip install --user`. @@ -98599,6 +98605,37 @@ async function installPip(pythonLocation) { await exec_exec(`${pythonLocation}/python -m pip install --upgrade pip==${pipVersion} --disable-pip-version-check --no-warn-script-location`); } } +function findScopedPython(semanticVersionSpec, architecture) { + const suffix = getVersionCacheSuffix(); + const toolCache = process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (!suffix || !toolCache) { + return find('Python', semanticVersionSpec, architecture); + } + const pythonRoot = external_path_.join(toolCache, 'Python'); + if (!external_fs_namespaceObject.existsSync(pythonRoot)) + return null; + let bestVer = null; + let bestDir = null; + for (const entry of external_fs_namespaceObject.readdirSync(pythonRoot)) { + if (!entry.endsWith(suffix)) + continue; + const ver = entry.slice(0, entry.length - suffix.length); + if (!node_modules_semver.valid(ver)) + continue; + if (!node_modules_semver.satisfies(ver, semanticVersionSpec)) + continue; + const candidate = external_path_.join(pythonRoot, entry, architecture); + const marker = external_path_.join(pythonRoot, entry + '.complete'); + if (!external_fs_namespaceObject.existsSync(candidate) || !external_fs_namespaceObject.existsSync(marker)) + continue; + if (!bestVer || node_modules_semver.gt(ver, bestVer)) { + bestVer = ver; + bestDir = candidate; + } + } + return bestDir; +} async function useCpythonVersion(version, architecture, updateEnvironment, checkLatest, allowPreReleases, freethreaded) { let manifest = null; const { version: desugaredVersionSpec, freethreaded: versionFreethreaded } = desugarVersion(version); @@ -98624,14 +98661,14 @@ async function useCpythonVersion(version, architecture, updateEnvironment, check info(`Failed to resolve version ${semanticVersionSpec} from manifest`); } } - let installDir = find('Python', semanticVersionSpec + getVersionCacheSuffix(), architecture); + let installDir = findScopedPython(semanticVersionSpec, architecture); if (!installDir) { info(`Version ${semanticVersionSpec} was not found in the local cache`); const foundRelease = await findReleaseFromManifest(semanticVersionSpec, architecture, manifest); if (foundRelease && foundRelease.files && foundRelease.files.length > 0) { info(`Version ${semanticVersionSpec} is available for downloading`); await installCpythonFromRelease(foundRelease); - installDir = find('Python', semanticVersionSpec + getVersionCacheSuffix(), architecture); + installDir = findScopedPython(semanticVersionSpec, architecture); } } if (!installDir) { From 36c6871d568b92642509f65d3b0c1667a9fbd216 Mon Sep 17 00:00:00 2001 From: gowridurgad Date: Thu, 23 Jul 2026 12:25:03 +0530 Subject: [PATCH 4/5] loosen gate, force overwrite dst, add debug logs" --- dist/cache-save/index.js | 23 ++++++++++++++++-- dist/setup/index.js | 51 +++++++++++++++++++++++++++++++++++----- src/install-python.ts | 35 +++++++++++++++++++++++---- src/utils.ts | 23 +++++++++++++++++- 4 files changed, 118 insertions(+), 14 deletions(-) diff --git a/dist/cache-save/index.js b/dist/cache-save/index.js index 4c879b256..0b2edf639 100644 --- a/dist/cache-save/index.js +++ b/dist/cache-save/index.js @@ -97480,8 +97480,27 @@ function getDownloadFileName(downloadUrl) { function getVersionCacheSuffix() { if (!utils_IS_LINUX) return ''; - if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') - return ''; + // Skip only for true GitHub-hosted VMs, detected by presence of the + // pre-installed hostedtoolcache Python at the un-scoped path. + // bbq-beets / Partner runners also report RUNNER_ENVIRONMENT=github-hosted + // but do NOT have pre-installed Python, so they still need scoping. + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') { + const root = process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (root && fs.existsSync(path.join(root, 'Python'))) { + // Check if there's a *non-scoped* pre-installed Python (any dir under + // Python/ that is a plain semver, not already OS-suffixed). + try { + const entries = fs.readdirSync(path.join(root, 'Python')); + const hasPreinstalled = entries.some(e => /^\d+\.\d+\.\d+$/.test(e) && !e.includes('-')); + if (hasPreinstalled) + return ''; + } + catch { + /* fall through */ + } + } + } try { const content = fs.readFileSync('/etc/os-release', 'utf8'); const map = {}; diff --git a/dist/setup/index.js b/dist/setup/index.js index a61903cd1..0ab302f44 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97472,8 +97472,27 @@ function getDownloadFileName(downloadUrl) { function getVersionCacheSuffix() { if (!IS_LINUX) return ''; - if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') - return ''; + // Skip only for true GitHub-hosted VMs, detected by presence of the + // pre-installed hostedtoolcache Python at the un-scoped path. + // bbq-beets / Partner runners also report RUNNER_ENVIRONMENT=github-hosted + // but do NOT have pre-installed Python, so they still need scoping. + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') { + const root = process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (root && external_fs_default().existsSync(external_path_.join(root, 'Python'))) { + // Check if there's a *non-scoped* pre-installed Python (any dir under + // Python/ that is a plain semver, not already OS-suffixed). + try { + const entries = external_fs_default().readdirSync(external_path_.join(root, 'Python')); + const hasPreinstalled = entries.some(e => /^\d+\.\d+\.\d+$/.test(e) && !e.includes('-')); + if (hasPreinstalled) + return ''; + } + catch { + /* fall through */ + } + } + } try { const content = external_fs_default().readFileSync('/etc/os-release', 'utf8'); const map = {}; @@ -98520,6 +98539,7 @@ async function installCpythonFromRelease(release) { info('Execute installation script'); await installPython(pythonExtractedFolder); const suffix = getVersionCacheSuffix(); + info(`[1087] version-suffix: suffix='${suffix}' RUNNER_ENVIRONMENT='${process.env['RUNNER_ENVIRONMENT'] || ''}'`); if (suffix) { const toolCache = process.env['AGENT_TOOLSDIRECTORY']?.trim() || process.env['RUNNER_TOOL_CACHE']; @@ -98529,18 +98549,37 @@ async function installCpythonFromRelease(release) { const origMarker = origDir + '.complete'; const newMarker = newDir + '.complete'; try { - if (external_fs_namespaceObject.existsSync(origDir) && !external_fs_namespaceObject.existsSync(newDir)) { + if (external_fs_namespaceObject.existsSync(newDir)) { + info(`[1087] version-suffix: removing stale ${newDir} before rename`); + external_fs_namespaceObject.rmSync(newDir, { recursive: true, force: true }); + } + if (external_fs_namespaceObject.existsSync(newMarker)) { + external_fs_namespaceObject.rmSync(newMarker, { force: true }); + } + if (external_fs_namespaceObject.existsSync(origDir)) { external_fs_namespaceObject.renameSync(origDir, newDir); - info(`Renamed cache dir for OS scoping: ${origDir} -> ${newDir}`); + info(`[1087] version-suffix: renamed ${origDir} -> ${newDir}`); + } + else { + warning(`[1087] version-suffix: expected ${origDir} to exist after install but it did not`); } - if (external_fs_namespaceObject.existsSync(origMarker) && !external_fs_namespaceObject.existsSync(newMarker)) { + if (external_fs_namespaceObject.existsSync(origMarker)) { external_fs_namespaceObject.renameSync(origMarker, newMarker); + info(`[1087] version-suffix: renamed marker ${origMarker} -> ${newMarker}`); + } + else { + // setup.sh should always write the marker; if it didn't, write our own + external_fs_namespaceObject.writeFileSync(newMarker, ''); + info(`[1087] version-suffix: wrote marker ${newMarker}`); } } catch (e) { - warning(`Failed to rename Python cache dir for OS scoping: ${e.message}`); + warning(`[1087] version-suffix: rename failed: ${e.message}`); } } + else { + warning('[1087] version-suffix: no AGENT_TOOLSDIRECTORY/RUNNER_TOOL_CACHE'); + } } } catch (err) { diff --git a/src/install-python.ts b/src/install-python.ts index c7054263e..074150a39 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -309,6 +309,9 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { await installPython(pythonExtractedFolder); const suffix = getVersionCacheSuffix(); + core.info( + `[1087] version-suffix: suffix='${suffix}' RUNNER_ENVIRONMENT='${process.env['RUNNER_ENVIRONMENT'] || ''}'` + ); if (suffix) { const toolCache = process.env['AGENT_TOOLSDIRECTORY']?.trim() || @@ -319,20 +322,42 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { const origMarker = origDir + '.complete'; const newMarker = newDir + '.complete'; try { - if (fs.existsSync(origDir) && !fs.existsSync(newDir)) { - fs.renameSync(origDir, newDir); + if (fs.existsSync(newDir)) { core.info( - `Renamed cache dir for OS scoping: ${origDir} -> ${newDir}` + `[1087] version-suffix: removing stale ${newDir} before rename` + ); + fs.rmSync(newDir, {recursive: true, force: true}); + } + if (fs.existsSync(newMarker)) { + fs.rmSync(newMarker, {force: true}); + } + if (fs.existsSync(origDir)) { + fs.renameSync(origDir, newDir); + core.info(`[1087] version-suffix: renamed ${origDir} -> ${newDir}`); + } else { + core.warning( + `[1087] version-suffix: expected ${origDir} to exist after install but it did not` ); } - if (fs.existsSync(origMarker) && !fs.existsSync(newMarker)) { + if (fs.existsSync(origMarker)) { fs.renameSync(origMarker, newMarker); + core.info( + `[1087] version-suffix: renamed marker ${origMarker} -> ${newMarker}` + ); + } else { + // setup.sh should always write the marker; if it didn't, write our own + fs.writeFileSync(newMarker, ''); + core.info(`[1087] version-suffix: wrote marker ${newMarker}`); } } catch (e) { core.warning( - `Failed to rename Python cache dir for OS scoping: ${(e as Error).message}` + `[1087] version-suffix: rename failed: ${(e as Error).message}` ); } + } else { + core.warning( + '[1087] version-suffix: no AGENT_TOOLSDIRECTORY/RUNNER_TOOL_CACHE' + ); } } } catch (err) { diff --git a/src/utils.ts b/src/utils.ts index efd293831..c598242dd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -448,7 +448,28 @@ export function getDownloadFileName(downloadUrl: string): string | undefined { export function getVersionCacheSuffix(): string { if (!IS_LINUX) return ''; - if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') return ''; + // Skip only for true GitHub-hosted VMs, detected by presence of the + // pre-installed hostedtoolcache Python at the un-scoped path. + // bbq-beets / Partner runners also report RUNNER_ENVIRONMENT=github-hosted + // but do NOT have pre-installed Python, so they still need scoping. + if (process.env['RUNNER_ENVIRONMENT'] === 'github-hosted') { + const root = + process.env['AGENT_TOOLSDIRECTORY']?.trim() || + process.env['RUNNER_TOOL_CACHE']; + if (root && fs.existsSync(path.join(root, 'Python'))) { + // Check if there's a *non-scoped* pre-installed Python (any dir under + // Python/ that is a plain semver, not already OS-suffixed). + try { + const entries = fs.readdirSync(path.join(root, 'Python')); + const hasPreinstalled = entries.some( + e => /^\d+\.\d+\.\d+$/.test(e) && !e.includes('-') + ); + if (hasPreinstalled) return ''; + } catch { + /* fall through */ + } + } + } try { const content = fs.readFileSync('/etc/os-release', 'utf8'); const map: Record = {}; From 3ce793f41d2b0e2e453dde3f8c6f1389dd2db5fc Mon Sep 17 00:00:00 2001 From: gowridurgad Date: Thu, 23 Jul 2026 12:47:26 +0530 Subject: [PATCH 5/5] removes debug --- src/install-python.ts | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/install-python.ts b/src/install-python.ts index 074150a39..95847bf51 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -309,9 +309,6 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { await installPython(pythonExtractedFolder); const suffix = getVersionCacheSuffix(); - core.info( - `[1087] version-suffix: suffix='${suffix}' RUNNER_ENVIRONMENT='${process.env['RUNNER_ENVIRONMENT'] || ''}'` - ); if (suffix) { const toolCache = process.env['AGENT_TOOLSDIRECTORY']?.trim() || @@ -323,9 +320,6 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { const newMarker = newDir + '.complete'; try { if (fs.existsSync(newDir)) { - core.info( - `[1087] version-suffix: removing stale ${newDir} before rename` - ); fs.rmSync(newDir, {recursive: true, force: true}); } if (fs.existsSync(newMarker)) { @@ -333,31 +327,17 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { } if (fs.existsSync(origDir)) { fs.renameSync(origDir, newDir); - core.info(`[1087] version-suffix: renamed ${origDir} -> ${newDir}`); - } else { - core.warning( - `[1087] version-suffix: expected ${origDir} to exist after install but it did not` - ); } if (fs.existsSync(origMarker)) { fs.renameSync(origMarker, newMarker); - core.info( - `[1087] version-suffix: renamed marker ${origMarker} -> ${newMarker}` - ); } else { - // setup.sh should always write the marker; if it didn't, write our own fs.writeFileSync(newMarker, ''); - core.info(`[1087] version-suffix: wrote marker ${newMarker}`); } } catch (e) { core.warning( - `[1087] version-suffix: rename failed: ${(e as Error).message}` + `Failed to rename Python cache dir for OS scoping: ${(e as Error).message}` ); } - } else { - core.warning( - '[1087] version-suffix: no AGENT_TOOLSDIRECTORY/RUNNER_TOOL_CACHE' - ); } } } catch (err) {