From 1795a8204773304f6e565c7f4c4f7730f1578df9 Mon Sep 17 00:00:00 2001 From: Aparna Jyothi Date: Mon, 14 Apr 2025 12:07:05 +0530 Subject: [PATCH 1/5] candidates not iterable --- .github/workflows/e2e-cache.yml | 2 ++ __tests__/install-python.test.ts | 23 +++++++++++-- dist/setup/index.js | 57 ++++++++++++++++++++++++-------- src/install-python.ts | 49 +++++++++++++++++++++++---- 4 files changed, 109 insertions(+), 22 deletions(-) diff --git a/.github/workflows/e2e-cache.yml b/.github/workflows/e2e-cache.yml index 4675b869..a3c9a2ba 100644 --- a/.github/workflows/e2e-cache.yml +++ b/.github/workflows/e2e-cache.yml @@ -82,6 +82,8 @@ jobs: python-version: pypy-3.10-v7.x - os: ubuntu-22.04-arm python-version: pypy-3.11-v7.x + - os: ubuntu-22.04-arm + python-version: pypy-3.10-v7.x steps: - uses: actions/checkout@v4 - name: Setup Python diff --git a/__tests__/install-python.test.ts b/__tests__/install-python.test.ts index c3a6e7b4..51f9fa77 100644 --- a/__tests__/install-python.test.ts +++ b/__tests__/install-python.test.ts @@ -8,10 +8,29 @@ import * as tc from '@actions/tool-cache'; jest.mock('@actions/http-client'); jest.mock('@actions/tool-cache'); - -const mockManifest = [{version: '1.0.0'}]; +jest.mock('@actions/tool-cache', () => ({ + getManifestFromRepo: jest.fn() +})); +const mockManifest = [ + { + version: '1.0.0', + stable: true, + files: [ + { + filename: 'tool-v1.0.0-linux-x64.tar.gz', + platform: 'linux', + arch: 'x64', + download_url: 'https://example.com/tool-v1.0.0-linux-x64.tar.gz' + } + ] + } +]; describe('getManifest', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + it('should return manifest from repo', async () => { (tc.getManifestFromRepo as jest.Mock).mockResolvedValue(mockManifest); const manifest = await getManifest(); diff --git a/dist/setup/index.js b/dist/setup/index.js index 2cdcfaad..8dd57530 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97461,15 +97461,36 @@ function findReleaseFromManifest(semanticVersionSpec, architecture, manifest) { }); } exports.findReleaseFromManifest = findReleaseFromManifest; +function isIToolRelease(obj) { + return (typeof obj === 'object' && + obj !== null && + typeof obj.version === 'string' && + typeof obj.stable === 'boolean' && + Array.isArray(obj.files) && + obj.files.every((file) => typeof file.filename === 'string' && + typeof file.platform === 'string' && + typeof file.arch === 'string' && + typeof file.download_url === 'string')); +} function getManifest() { return __awaiter(this, void 0, void 0, function* () { try { - return yield getManifestFromRepo(); + const repoManifest = yield getManifestFromRepo(); + if (Array.isArray(repoManifest) && + repoManifest.length && + repoManifest.every(isIToolRelease)) { + return repoManifest; + } + throw new Error('The repository manifest is invalid or does not include any valid tool release (IToolRelease) entries.'); } catch (err) { - core.debug('Fetching the manifest via the API failed.'); + core.debug('Failed to fetch the manifest from the repository API.'); if (err instanceof Error) { - core.debug(err.message); + core.debug(`Error message: ${err.message}`); + core.debug(`Error stack: ${err.stack}`); + } + else { + core.error('An unexpected error occurred while fetching the manifest.'); } } return yield getManifestFromURL(); @@ -97477,17 +97498,17 @@ function getManifest() { } exports.getManifest = getManifest; function getManifestFromRepo() { - core.debug(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`); + core.info(`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); } exports.getManifestFromRepo = getManifestFromRepo; function getManifestFromURL() { return __awaiter(this, void 0, void 0, function* () { - core.debug('Falling back to fetching the manifest using raw URL.'); + core.info('Falling back to fetching the manifest using raw URL.'); const http = new httpm.HttpClient('tool-cache'); const response = yield http.getJson(exports.MANIFEST_URL); if (!response.result) { - throw new Error(`Unable to get manifest from ${exports.MANIFEST_URL}`); + throw new Error(`Unable to get manifest from ${exports.MANIFEST_URL}. HTTP status: ${response.statusCode}`); } return response.result; }); @@ -97518,6 +97539,9 @@ function installPython(workingDirectory) { } function installCpythonFromRelease(release) { return __awaiter(this, void 0, void 0, function* () { + if (!release.files || release.files.length === 0) { + throw new Error('No files found in the release to download.'); + } const downloadUrl = release.files[0].download_url; core.info(`Download from "${downloadUrl}"`); let pythonPath = ''; @@ -97537,15 +97561,22 @@ function installCpythonFromRelease(release) { } catch (err) { if (err instanceof tc.HTTPError) { - // Rate limit? - if (err.httpStatusCode === 403 || err.httpStatusCode === 429) { - core.info(`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`); + const statusCode = err.httpStatusCode; + if (statusCode === 403 || statusCode === 429) { + const rateLimitMessage = `HTTP ${statusCode} - Rate limit likely exceeded. This is typically due to too many requests or insufficient permissions.`; + core.info(rateLimitMessage); + if (err.stack) { + core.debug(err.stack); + } + throw new Error(rateLimitMessage); } else { - core.info(err.message); - } - if (err.stack) { - core.debug(err.stack); + const genericErrorMessage = `HTTP ${statusCode} - ${err.message}`; + core.error(genericErrorMessage); + if (err.stack) { + core.debug(err.stack); + } + throw new Error(genericErrorMessage); } } throw err; diff --git a/src/install-python.ts b/src/install-python.ts index d3421bf8..137dc9d9 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -5,6 +5,7 @@ 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, getDownloadFileName} from './utils'; +import {IToolRelease} from '@actions/tool-cache'; const TOKEN = core.getInput('token'); const AUTH = !TOKEN ? undefined : `token ${TOKEN}`; @@ -31,21 +32,49 @@ export async function findReleaseFromManifest( return foundRelease; } - +function isIToolRelease(obj: any): obj is IToolRelease { + return ( + typeof obj === 'object' && + obj !== null && + typeof obj.version === 'string' && + typeof obj.stable === 'boolean' && + Array.isArray(obj.files) && + obj.files.every( + (file: any) => + typeof file.filename === 'string' && + typeof file.platform === 'string' && + typeof file.arch === 'string' && + typeof file.download_url === 'string' + ) + ); +} export async function getManifest(): Promise { try { - return await getManifestFromRepo(); + const repoManifest = await getManifestFromRepo(); + if ( + Array.isArray(repoManifest) && + repoManifest.length && + repoManifest.every(isIToolRelease) + ) { + return repoManifest; + } + throw new Error( + 'The repository manifest is invalid or does not include any valid tool release (IToolRelease) entries.' + ); } catch (err) { - core.debug('Fetching the manifest via the API failed.'); + core.debug('Failed to fetch the manifest from the repository API.'); if (err instanceof Error) { - core.debug(err.message); + core.debug(`Error message: ${err.message}`); + core.debug(`Error stack: ${err.stack}`); + } else { + core.error('An unexpected error occurred while fetching the manifest.'); } } return await getManifestFromURL(); } export function getManifestFromRepo(): Promise { - core.debug( + core.info( `Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}` ); return tc.getManifestFromRepo( @@ -57,12 +86,14 @@ export function getManifestFromRepo(): Promise { } export async function getManifestFromURL(): Promise { - core.debug('Falling back to fetching the manifest using raw URL.'); + core.info('Falling back to fetching the manifest using raw URL.'); const http: httpm.HttpClient = new httpm.HttpClient('tool-cache'); const response = await http.getJson(MANIFEST_URL); if (!response.result) { - throw new Error(`Unable to get manifest from ${MANIFEST_URL}`); + throw new Error( + `Unable to get manifest from ${MANIFEST_URL}. HTTP status: ${response.statusCode}` + ); } return response.result; } @@ -93,6 +124,10 @@ async function installPython(workingDirectory: string) { } export async function installCpythonFromRelease(release: tc.IToolRelease) { + + if (!release.files || release.files.length === 0) { + throw new Error('No files found in the release to download.'); + } const downloadUrl = release.files[0].download_url; core.info(`Download from "${downloadUrl}"`); From 93e3e0287762958a95f36a77b4d803d4d8c6034a Mon Sep 17 00:00:00 2001 From: Aparna Jyothi Date: Mon, 14 Apr 2025 12:13:43 +0530 Subject: [PATCH 2/5] update the error message --- dist/setup/index.js | 25 ++++++++++++------------- src/install-python.ts | 21 +++++++++++++++------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 8dd57530..ce71b369 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97562,21 +97562,20 @@ function installCpythonFromRelease(release) { catch (err) { if (err instanceof tc.HTTPError) { const statusCode = err.httpStatusCode; - if (statusCode === 403 || statusCode === 429) { - const rateLimitMessage = `HTTP ${statusCode} - Rate limit likely exceeded. This is typically due to too many requests or insufficient permissions.`; - core.info(rateLimitMessage); - if (err.stack) { - core.debug(err.stack); - } - throw new Error(rateLimitMessage); + if (statusCode === 429) { + // Too Many Requests - usually temporary and can be retried + core.info(`Received HTTP status code ${statusCode}. This usually indicates the rate limit has been exceeded. Consider retrying after some time.`); + } + else if (statusCode === 403) { + // Forbidden - likely a permanent issue + core.error(`Received HTTP status code ${statusCode}. Access is forbidden. Please check your credentials or permissions.`); } else { - const genericErrorMessage = `HTTP ${statusCode} - ${err.message}`; - core.error(genericErrorMessage); - if (err.stack) { - core.debug(err.stack); - } - throw new Error(genericErrorMessage); + // Other HTTP errors + core.info(`Received HTTP error ${statusCode}: ${err.message}`); + } + if (err.stack) { + core.debug(`Stack trace: ${err.stack}`); } } throw err; diff --git a/src/install-python.ts b/src/install-python.ts index 137dc9d9..ab3b2096 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -124,7 +124,6 @@ async function installPython(workingDirectory: string) { } export async function installCpythonFromRelease(release: tc.IToolRelease) { - if (!release.files || release.files.length === 0) { throw new Error('No files found in the release to download.'); } @@ -147,18 +146,28 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { await installPython(pythonExtractedFolder); } catch (err) { if (err instanceof tc.HTTPError) { - // Rate limit? - if (err.httpStatusCode === 403 || err.httpStatusCode === 429) { + const statusCode = err.httpStatusCode; + + if (statusCode === 429) { + // Too Many Requests - usually temporary and can be retried core.info( - `Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded` + `Received HTTP status code ${statusCode}. This usually indicates the rate limit has been exceeded. Consider retrying after some time.` + ); + } else if (statusCode === 403) { + // Forbidden - likely a permanent issue + core.error( + `Received HTTP status code ${statusCode}. Access is forbidden. Please check your credentials or permissions.` ); } else { - core.info(err.message); + // Other HTTP errors + core.info(`Received HTTP error ${statusCode}: ${err.message}`); } + if (err.stack) { - core.debug(err.stack); + core.debug(`Stack trace: ${err.stack}`); } } + throw err; } } From 7faf95d67ad924328e84b56448608e065ff155c0 Mon Sep 17 00:00:00 2001 From: Aparna Jyothi Date: Mon, 14 Apr 2025 13:12:15 +0530 Subject: [PATCH 3/5] update error to debug --- dist/setup/index.js | 17 +++++++---------- src/install-python.ts | 24 +++++++++--------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index ce71b369..33a3e567 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97561,21 +97561,18 @@ function installCpythonFromRelease(release) { } catch (err) { if (err instanceof tc.HTTPError) { - const statusCode = err.httpStatusCode; - if (statusCode === 429) { - // Too Many Requests - usually temporary and can be retried - core.info(`Received HTTP status code ${statusCode}. This usually indicates the rate limit has been exceeded. Consider retrying after some time.`); + // Rate limit? + if (err.httpStatusCode === 403) { + core.error(`Received HTTP status code 403 (Forbidden). This usually indicates that the request is not authorized. Please check your credentials or permissions.`); } - else if (statusCode === 403) { - // Forbidden - likely a permanent issue - core.error(`Received HTTP status code ${statusCode}. Access is forbidden. Please check your credentials or permissions.`); + else if (err.httpStatusCode === 429) { + core.info(`Received HTTP status code 429 (Too Many Requests). This usually indicates that the rate limit has been exceeded. Please wait and try again later.`); } else { - // Other HTTP errors - core.info(`Received HTTP error ${statusCode}: ${err.message}`); + core.info(err.message); } if (err.stack) { - core.debug(`Stack trace: ${err.stack}`); + core.debug(err.stack); } } throw err; diff --git a/src/install-python.ts b/src/install-python.ts index ab3b2096..34a4b026 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -146,28 +146,22 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { await installPython(pythonExtractedFolder); } catch (err) { if (err instanceof tc.HTTPError) { - const statusCode = err.httpStatusCode; - - if (statusCode === 429) { - // Too Many Requests - usually temporary and can be retried - core.info( - `Received HTTP status code ${statusCode}. This usually indicates the rate limit has been exceeded. Consider retrying after some time.` - ); - } else if (statusCode === 403) { - // Forbidden - likely a permanent issue + // Rate limit? + if (err.httpStatusCode === 403) { core.error( - `Received HTTP status code ${statusCode}. Access is forbidden. Please check your credentials or permissions.` + `Received HTTP status code 403 (Forbidden). This usually indicates that the request is not authorized. Please check your credentials or permissions.` + ); + } else if (err.httpStatusCode === 429) { + core.info( + `Received HTTP status code 429 (Too Many Requests). This usually indicates that the rate limit has been exceeded. Please wait and try again later.` ); } else { - // Other HTTP errors - core.info(`Received HTTP error ${statusCode}: ${err.message}`); + core.info(err.message); } - if (err.stack) { - core.debug(`Stack trace: ${err.stack}`); + core.debug(err.stack); } } - throw err; } } From cc6c47bafbd62f02f0e4506301c6286ef2e0a32a Mon Sep 17 00:00:00 2001 From: Aparna Jyothi Date: Mon, 14 Apr 2025 13:27:39 +0530 Subject: [PATCH 4/5] update debug to info --- dist/setup/index.js | 2 +- src/install-python.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 33a3e567..9ce85b6a 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97572,7 +97572,7 @@ function installCpythonFromRelease(release) { core.info(err.message); } if (err.stack) { - core.debug(err.stack); + core.info(err.stack); } } throw err; diff --git a/src/install-python.ts b/src/install-python.ts index 34a4b026..2435b8ed 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -159,7 +159,7 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { core.info(err.message); } if (err.stack) { - core.debug(err.stack); + core.info(err.stack); } } throw err; From 1032141ebd84945eed09831feceb5c034f5d40c0 Mon Sep 17 00:00:00 2001 From: Aparna Jyothi Date: Mon, 14 Apr 2025 16:56:54 +0530 Subject: [PATCH 5/5] error message updates --- dist/setup/index.js | 17 ++++++++--------- src/install-python.ts | 19 ++++++++----------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index 9ce85b6a..ec5261ef 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -97484,10 +97484,9 @@ function getManifest() { throw new Error('The repository manifest is invalid or does not include any valid tool release (IToolRelease) entries.'); } catch (err) { - core.debug('Failed to fetch the manifest from the repository API.'); + core.debug('Fetching the manifest via the API failed.'); if (err instanceof Error) { - core.debug(`Error message: ${err.message}`); - core.debug(`Error stack: ${err.stack}`); + core.debug(err.message); } else { core.error('An unexpected error occurred while fetching the manifest.'); @@ -97498,17 +97497,17 @@ function getManifest() { } exports.getManifest = getManifest; function getManifestFromRepo() { - core.info(`Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}`); + 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); } exports.getManifestFromRepo = getManifestFromRepo; function getManifestFromURL() { return __awaiter(this, void 0, void 0, function* () { - core.info('Falling back to fetching the manifest using raw URL.'); + core.debug('Falling back to fetching the manifest using raw URL.'); const http = new httpm.HttpClient('tool-cache'); const response = yield http.getJson(exports.MANIFEST_URL); if (!response.result) { - throw new Error(`Unable to get manifest from ${exports.MANIFEST_URL}. HTTP status: ${response.statusCode}`); + throw new Error(`Unable to get manifest from ${exports.MANIFEST_URL}`); } return response.result; }); @@ -97563,16 +97562,16 @@ function installCpythonFromRelease(release) { if (err instanceof tc.HTTPError) { // Rate limit? if (err.httpStatusCode === 403) { - core.error(`Received HTTP status code 403 (Forbidden). This usually indicates that the request is not authorized. Please check your credentials or permissions.`); + core.error(`Received HTTP status code 403. This indicates a permission issue or restricted access.`); } else if (err.httpStatusCode === 429) { - core.info(`Received HTTP status code 429 (Too Many Requests). This usually indicates that the rate limit has been exceeded. Please wait and try again later.`); + core.info(`Received HTTP status code 429. This usually indicates the rate limit has been exceeded`); } else { core.info(err.message); } if (err.stack) { - core.info(err.stack); + core.debug(err.stack); } } throw err; diff --git a/src/install-python.ts b/src/install-python.ts index 2435b8ed..bef0161c 100644 --- a/src/install-python.ts +++ b/src/install-python.ts @@ -62,10 +62,9 @@ export async function getManifest(): Promise { 'The repository manifest is invalid or does not include any valid tool release (IToolRelease) entries.' ); } catch (err) { - core.debug('Failed to fetch the manifest from the repository API.'); + core.debug('Fetching the manifest via the API failed.'); if (err instanceof Error) { - core.debug(`Error message: ${err.message}`); - core.debug(`Error stack: ${err.stack}`); + core.debug(err.message); } else { core.error('An unexpected error occurred while fetching the manifest.'); } @@ -74,7 +73,7 @@ export async function getManifest(): Promise { } export function getManifestFromRepo(): Promise { - core.info( + core.debug( `Getting manifest from ${MANIFEST_REPO_OWNER}/${MANIFEST_REPO_NAME}@${MANIFEST_REPO_BRANCH}` ); return tc.getManifestFromRepo( @@ -86,14 +85,12 @@ export function getManifestFromRepo(): Promise { } export async function getManifestFromURL(): Promise { - core.info('Falling back to fetching the manifest using raw URL.'); + core.debug('Falling back to fetching the manifest using raw URL.'); const http: httpm.HttpClient = new httpm.HttpClient('tool-cache'); const response = await http.getJson(MANIFEST_URL); if (!response.result) { - throw new Error( - `Unable to get manifest from ${MANIFEST_URL}. HTTP status: ${response.statusCode}` - ); + throw new Error(`Unable to get manifest from ${MANIFEST_URL}`); } return response.result; } @@ -149,17 +146,17 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) { // Rate limit? if (err.httpStatusCode === 403) { core.error( - `Received HTTP status code 403 (Forbidden). This usually indicates that the request is not authorized. Please check your credentials or permissions.` + `Received HTTP status code 403. This indicates a permission issue or restricted access.` ); } else if (err.httpStatusCode === 429) { core.info( - `Received HTTP status code 429 (Too Many Requests). This usually indicates that the rate limit has been exceeded. Please wait and try again later.` + `Received HTTP status code 429. This usually indicates the rate limit has been exceeded` ); } else { core.info(err.message); } if (err.stack) { - core.info(err.stack); + core.debug(err.stack); } } throw err;