From ff566a4e9a4d1008d81d8ac2975b4a062b3545f5 Mon Sep 17 00:00:00 2001 From: priya-kinthali Date: Wed, 22 Oct 2025 18:58:45 +0530 Subject: [PATCH] enhance error logging and implement retry --- dist/setup/index.js | 108 +++++++++++++++++++------ package-lock.json | 1 - src/distributions/base-installer.ts | 120 +++++++++++++++++++++------- 3 files changed, 174 insertions(+), 55 deletions(-) diff --git a/dist/setup/index.js b/dist/setup/index.js index c4e8ec9ef..116d49448 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -129856,6 +129856,7 @@ class JavaBase { this.checkLatest = installerOptions.checkLatest; } setupJava() { + var _a, _b; return __awaiter(this, void 0, void 0, function* () { let foundJava = this.findInToolcache(); if (foundJava && !this.checkLatest) { @@ -129863,40 +129864,95 @@ class JavaBase { } else { core.info('Trying to resolve the latest version from remote'); - try { - const javaRelease = yield this.findPackageForDownload(this.version); - core.info(`Resolved latest version as ${javaRelease.version}`); - if ((foundJava === null || foundJava === void 0 ? void 0 : foundJava.version) === javaRelease.version) { - core.info(`Resolved Java ${foundJava.version} from tool-cache`); - } - else { - core.info('Trying to download...'); - foundJava = yield this.downloadTool(javaRelease); - core.info(`Java ${foundJava.version} was downloaded`); - } - } - catch (error) { - if (error instanceof tc.HTTPError) { - if (error.httpStatusCode === 403) { - core.error('HTTP 403: Permission denied or access restricted.'); + let retries = 4; + const retryableCodes = [ + 'ETIMEDOUT', + 'ECONNRESET', + 'ENOTFOUND', + 'ECONNREFUSED' + ]; + while (retries > 0) { + try { + // Clear console timers before each attempt to prevent conflicts + if (retries < 4 && core.isDebug()) { + const consoleAny = console; + (_b = (_a = consoleAny._times) === null || _a === void 0 ? void 0 : _a.clear) === null || _b === void 0 ? void 0 : _b.call(_a); } - else if (error.httpStatusCode === 429) { - core.warning('HTTP 429: Rate limit exceeded. Please retry later.'); + const javaRelease = yield this.findPackageForDownload(this.version); + core.info(`Resolved latest version as ${javaRelease.version}`); + if ((foundJava === null || foundJava === void 0 ? void 0 : foundJava.version) === javaRelease.version) { + core.info(`Resolved Java ${foundJava.version} from tool-cache`); } else { - core.error(`HTTP ${error.httpStatusCode}: ${error.message}`); + core.info('Trying to download...'); + foundJava = yield this.downloadTool(javaRelease); + core.info(`Java ${foundJava.version} was downloaded`); } + break; } - else { - const message = error instanceof Error ? error.message : JSON.stringify(error); - core.error(`Java setup failed due to network issue or timeout: ${message}`); - } - if (error instanceof Error && error.stack) { - core.debug(error.stack); + catch (error) { + retries--; + // Check if error is retryable (including aggregate errors) + const isRetryable = (error instanceof tc.HTTPError && + error.httpStatusCode && + [429, 502, 503, 504].includes(error.httpStatusCode)) || + retryableCodes.includes(error === null || error === void 0 ? void 0 : error.code) || + ((error === null || error === void 0 ? void 0 : error.errors) && + Array.isArray(error.errors) && + error.errors.some((err) => retryableCodes.includes(err === null || err === void 0 ? void 0 : err.code))); + if (retries > 0 && isRetryable) { + core.debug(`Attempt failed due to network or timeout issues, initiating retry... (${retries} attempts left)`); + yield new Promise(r => setTimeout(r, 2000)); + continue; + } + if (error instanceof tc.HTTPError) { + if (error.httpStatusCode === 403) { + core.error('HTTP 403: Permission denied or access restricted.'); + } + else if (error.httpStatusCode === 429) { + core.warning('HTTP 429: Rate limit exceeded. Please retry later.'); + } + else { + core.error(`HTTP ${error.httpStatusCode}: ${error.message}`); + } + } + else if (error && error.errors && Array.isArray(error.errors)) { + core.error(`Java setup failed due to network or configuration error(s)`); + if (error instanceof Error && error.stack) { + core.debug(error.stack); + } + for (const err of error.errors) { + const endpoint = (err === null || err === void 0 ? void 0 : err.address) || (err === null || err === void 0 ? void 0 : err.hostname) || ''; + const port = (err === null || err === void 0 ? void 0 : err.port) ? `:${err.port}` : ''; + const message = (err === null || err === void 0 ? void 0 : err.message) || 'Aggregate error'; + const logMessage = `${message}${!message.includes(endpoint) ? ` ${endpoint}${port}` : ''}${err.localAddress && err.localPort ? ` - Local (${err.localAddress}:${err.localPort})` : ''}`; + core.error(logMessage); + core.debug(`${err.stack || err.message}`); + Object.entries(err).forEach(([key, value]) => { + core.debug(`"${key}": ${JSON.stringify(value)}`); + }); + } + } + else { + const message = error instanceof Error ? error.message : JSON.stringify(error); + core.error(`Java setup process failed due to: ${message}`); + if (typeof (error === null || error === void 0 ? void 0 : error.code) === 'string') { + core.debug(error.stack); + } + const errorDetails = Object.assign({ name: error.name, message: error.message }, Object.getOwnPropertyNames(error) + .filter(prop => !['name', 'message', 'stack'].includes(prop)) + .reduce((acc, prop) => (Object.assign(Object.assign({}, acc), { [prop]: error[prop] })), {})); + Object.entries(errorDetails).forEach(([key, value]) => { + core.debug(`"${key}": ${JSON.stringify(value)}`); + }); + } + throw error; } - throw error; } } + if (!foundJava) { + throw new Error('Failed to resolve Java version'); + } // JDK folder may contain postfix "Contents/Home" on macOS const macOSPostfixPath = path_1.default.join(foundJava.path, constants_1.MACOS_JAVA_CONTENT_POSTFIX); if (process.platform === 'darwin' && fs.existsSync(macOSPostfixPath)) { diff --git a/package-lock.json b/package-lock.json index c99ed7e91..cf7501446 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,4 +1,3 @@ - { "name": "setup-java", "version": "5.0.0", diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 4a83897f7..8dcf7577b 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -51,39 +51,103 @@ export abstract class JavaBase { core.info(`Resolved Java ${foundJava.version} from tool-cache`); } else { core.info('Trying to resolve the latest version from remote'); - try { - const javaRelease = await this.findPackageForDownload(this.version); - core.info(`Resolved latest version as ${javaRelease.version}`); - if (foundJava?.version === javaRelease.version) { - core.info(`Resolved Java ${foundJava.version} from tool-cache`); - } else { - core.info('Trying to download...'); - foundJava = await this.downloadTool(javaRelease); - core.info(`Java ${foundJava.version} was downloaded`); - } - } catch (error: any) { - if (error instanceof tc.HTTPError) { - if (error.httpStatusCode === 403) { - core.error('HTTP 403: Permission denied or access restricted.'); - } else if (error.httpStatusCode === 429) { - core.warning('HTTP 429: Rate limit exceeded. Please retry later.'); + let retries = 4; + const retryableCodes = [ + 'ETIMEDOUT', + 'ECONNRESET', + 'ENOTFOUND', + 'ECONNREFUSED' + ]; + while (retries > 0) { + try { + // Clear console timers before each attempt to prevent conflicts + if (retries < 4 && core.isDebug()) { + const consoleAny = console as any; + consoleAny._times?.clear?.(); + } + const javaRelease = await this.findPackageForDownload(this.version); + core.info(`Resolved latest version as ${javaRelease.version}`); + if (foundJava?.version === javaRelease.version) { + core.info(`Resolved Java ${foundJava.version} from tool-cache`); } else { - core.error(`HTTP ${error.httpStatusCode}: ${error.message}`); + core.info('Trying to download...'); + foundJava = await this.downloadTool(javaRelease); + core.info(`Java ${foundJava.version} was downloaded`); } - } else { - const message = - error instanceof Error ? error.message : JSON.stringify(error); - core.error( - `Java setup failed due to network issue or timeout: ${message}` - ); - } - if (error instanceof Error && error.stack) { - core.debug(error.stack); + break; + } catch (error: any) { + retries--; + // Check if error is retryable (including aggregate errors) + const isRetryable = + (error instanceof tc.HTTPError && + error.httpStatusCode && + [429, 502, 503, 504].includes(error.httpStatusCode)) || + retryableCodes.includes(error?.code) || + (error?.errors && + Array.isArray(error.errors) && + error.errors.some((err: any) => + retryableCodes.includes(err?.code) + )); + if (retries > 0 && isRetryable) { + core.debug( + `Attempt failed due to network or timeout issues, initiating retry... (${retries} attempts left)` + ); + await new Promise(r => setTimeout(r, 2000)); + continue; + } + if (error instanceof tc.HTTPError) { + if (error.httpStatusCode === 403) { + core.error('HTTP 403: Permission denied or access restricted.'); + } else if (error.httpStatusCode === 429) { + core.warning( + 'HTTP 429: Rate limit exceeded. Please retry later.' + ); + } else { + core.error(`HTTP ${error.httpStatusCode}: ${error.message}`); + } + } else if (error && error.errors && Array.isArray(error.errors)) { + core.error( + `Java setup failed due to network or configuration error(s)` + ); + if (error instanceof Error && error.stack) { + core.debug(error.stack); + } + for (const err of error.errors) { + const endpoint = err?.address || err?.hostname || ''; + const port = err?.port ? `:${err.port}` : ''; + const message = err?.message || 'Aggregate error'; + const logMessage = `${message}${!message.includes(endpoint) ? ` ${endpoint}${port}` : ''}${err.localAddress && err.localPort ? ` - Local (${err.localAddress}:${err.localPort})` : ''}`; + core.error(logMessage); + core.debug(`${err.stack || err.message}`); + Object.entries(err).forEach(([key, value]) => { + core.debug(`"${key}": ${JSON.stringify(value)}`); + }); + } + } else { + const message = + error instanceof Error ? error.message : JSON.stringify(error); + core.error(`Java setup process failed due to: ${message}`); + if (typeof error?.code === 'string') { + core.debug(error.stack); + } + const errorDetails = { + name: error.name, + message: error.message, + ...Object.getOwnPropertyNames(error) + .filter(prop => !['name', 'message', 'stack'].includes(prop)) + .reduce((acc, prop) => ({...acc, [prop]: error[prop]}), {}) + }; + Object.entries(errorDetails).forEach(([key, value]) => { + core.debug(`"${key}": ${JSON.stringify(value)}`); + }); + } + throw error; } - throw error; } } - + if (!foundJava) { + throw new Error('Failed to resolve Java version'); + } // JDK folder may contain postfix "Contents/Home" on macOS const macOSPostfixPath = path.join( foundJava.path,