From d78498f5805c104415cbccf8e0e218c40d44e88a Mon Sep 17 00:00:00 2001 From: chiranjib-swain Date: Fri, 13 Feb 2026 10:00:23 +0530 Subject: [PATCH 1/3] Refactor error handling for version not found cases across multiple installers --- __tests__/distributors/base-installer.test.ts | 116 +++++++++++++++--- .../distributors/dragonwell-installer.test.ts | 2 +- .../distributors/graalvm-installer.test.ts | 23 ++-- .../distributors/liberica-installer.test.ts | 2 +- .../liberica-linux-installer.test.ts | 2 +- .../liberica-windows-installer.test.ts | 2 +- .../distributors/sapmachine-installer.test.ts | 2 +- __tests__/distributors/zulu-installer.test.ts | 2 +- .../distributors/zulu-linux-installer.test.ts | 2 +- .../zulu-windows-installer.test.ts | 2 +- dist/setup/index.js | 110 ++++++++--------- package-lock.json | 7 -- src/distributions/adopt/installer.ts | 11 +- src/distributions/base-installer.ts | 36 ++++++ src/distributions/corretto/installer.ts | 11 +- src/distributions/dragonwell/installer.ts | 5 +- src/distributions/graalvm/installer.ts | 13 +- src/distributions/jetbrains/installer.ts | 11 +- src/distributions/liberica/installer.ts | 11 +- src/distributions/microsoft/installer.ts | 7 +- src/distributions/oracle/installer.ts | 2 +- src/distributions/sapmachine/installer.ts | 5 +- src/distributions/semeru/installer.ts | 18 +-- src/distributions/temurin/installer.ts | 11 +- src/distributions/zulu/installer.ts | 11 +- 25 files changed, 254 insertions(+), 170 deletions(-) diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts index 08a95828c..befa2d254 100644 --- a/__tests__/distributors/base-installer.test.ts +++ b/__tests__/distributors/base-installer.test.ts @@ -38,7 +38,7 @@ class EmptyJavaBase extends JavaBase { ): Promise { const availableVersion = '11.0.9'; if (!semver.satisfies(availableVersion, range)) { - throw new Error('Available version not found'); + throw this.createVersionNotFoundError(range, [availableVersion]); } return { @@ -530,19 +530,16 @@ describe('setupJava', () => { checkLatest: false } ] - ])( - 'should throw an error for Available version not found for %s', - async input => { - mockJavaBase = new EmptyJavaBase(input); - await expect(mockJavaBase.setupJava()).rejects.toThrow( - 'Available version not found' - ); - expect(spyTcFindAllVersions).toHaveBeenCalled(); - expect(spyCoreAddPath).not.toHaveBeenCalled(); - expect(spyCoreExportVariable).not.toHaveBeenCalled(); - expect(spyCoreSetOutput).not.toHaveBeenCalled(); - } - ); + ])('should throw an error for version not found for %s', async input => { + mockJavaBase = new EmptyJavaBase(input); + await expect(mockJavaBase.setupJava()).rejects.toThrow( + `Could not find satisfied version for SemVer '${input.version}'` + ); + expect(spyTcFindAllVersions).toHaveBeenCalled(); + expect(spyCoreAddPath).not.toHaveBeenCalled(); + expect(spyCoreExportVariable).not.toHaveBeenCalled(); + expect(spyCoreSetOutput).not.toHaveBeenCalled(); + }); }); describe('normalizeVersion', () => { @@ -570,6 +567,97 @@ describe('normalizeVersion', () => { }); }); +describe('createVersionNotFoundError', () => { + it('should include all required fields in error message without available versions', () => { + const mockJavaBase = new EmptyJavaBase({ + version: '17.0.5', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }); + + const error = (mockJavaBase as any).createVersionNotFoundError('17.0.5'); + + expect(error.message).toContain( + "Could not find satisfied version for SemVer '17.0.5'" + ); + expect(error.message).toContain('Distribution: Empty'); + expect(error.message).toContain('Package type: jdk'); + expect(error.message).toContain('Architecture: x64'); + }); + + it('should include available versions when provided', () => { + const mockJavaBase = new EmptyJavaBase({ + version: '17.0.5', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }); + + const availableVersions = ['11.0.1', '11.0.2', '17.0.1', '17.0.2']; + const error = (mockJavaBase as any).createVersionNotFoundError( + '17.0.5', + availableVersions + ); + + expect(error.message).toContain( + "Could not find satisfied version for SemVer '17.0.5'" + ); + expect(error.message).toContain('Distribution: Empty'); + expect(error.message).toContain('Package type: jdk'); + expect(error.message).toContain('Architecture: x64'); + expect(error.message).toContain( + 'Available versions: 11.0.1, 11.0.2, 17.0.1, 17.0.2' + ); + }); + + it('should truncate available versions when there are many', () => { + const mockJavaBase = new EmptyJavaBase({ + version: '17.0.5', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }); + + // Create 60 versions to test truncation + const availableVersions = Array.from({length: 60}, (_, i) => `11.0.${i}`); + const error = (mockJavaBase as any).createVersionNotFoundError( + '17.0.5', + availableVersions + ); + + expect(error.message).toContain('Available versions:'); + expect(error.message).toContain('...'); + expect(error.message).toContain('(showing first 50 of 60 versions'); + }); + + it('should include additional context when provided', () => { + const mockJavaBase = new EmptyJavaBase({ + version: '17.0.5', + architecture: 'x64', + packageType: 'jdk', + checkLatest: false + }); + + const availableVersions = ['11.0.1', '11.0.2']; + const additionalContext = 'Platform: linux'; + const error = (mockJavaBase as any).createVersionNotFoundError( + '17.0.5', + availableVersions, + additionalContext + ); + + expect(error.message).toContain( + "Could not find satisfied version for SemVer '17.0.5'" + ); + expect(error.message).toContain('Distribution: Empty'); + expect(error.message).toContain('Package type: jdk'); + expect(error.message).toContain('Architecture: x64'); + expect(error.message).toContain('Platform: linux'); + expect(error.message).toContain('Available versions: 11.0.1, 11.0.2'); + }); +}); + describe('getToolcacheVersionName', () => { const DummyJavaBase = JavaBase as any; diff --git a/__tests__/distributors/dragonwell-installer.test.ts b/__tests__/distributors/dragonwell-installer.test.ts index 627a96ab3..e33c74791 100644 --- a/__tests__/distributors/dragonwell-installer.test.ts +++ b/__tests__/distributors/dragonwell-installer.test.ts @@ -232,7 +232,7 @@ describe('getAvailableVersions', () => { await expect( distribution['findPackageForDownload'](jdkVersion) ).rejects.toThrow( - `Couldn't find any satisfied version for the specified java-version: "${jdkVersion}" and architecture: "${arch}".` + `Could not find satisfied version for SemVer '${jdkVersion}'` ); } ); diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index d2dda9f6d..95f553e35 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -348,11 +348,17 @@ describe('GraalVMDistribution', () => { } as http.HttpClientResponse; mockHttpClient.head.mockResolvedValue(mockResponse); + // Verify the error is thrown with the expected message await expect( (distribution as any).findPackageForDownload('17.0.99') ).rejects.toThrow( - 'Could not find GraalVM for SemVer 17.0.99. Please check if this version is available at https://download.oracle.com/graalvm' + "Could not find satisfied version for SemVer '17.0.99'" ); + + // Verify the hint about checking the base URL is included + await expect( + (distribution as any).findPackageForDownload('17.0.99') + ).rejects.toThrow('https://download.oracle.com/graalvm'); }); it('should throw error for unauthorized access (401)', async () => { @@ -496,12 +502,11 @@ describe('GraalVMDistribution', () => { await expect( (distribution as any).findPackageForDownload('23') - ).rejects.toThrow("Unable to find latest version for '23-ea'"); - - // Verify error logging - expect(core.error).toHaveBeenCalledWith( - 'Available versions: 23-ea-20240716' + ).rejects.toThrow( + "Could not find satisfied version for SemVer '23-ea'" ); + + // Verify error logging - removed as we now use the helper method which doesn't call core.error }); it('should throw error when no matching file for architecture in EA build', async () => { @@ -708,11 +713,9 @@ describe('GraalVMDistribution', () => { await expect( (distribution as any).findEABuildDownloadUrl('23-ea') - ).rejects.toThrow("Unable to find latest version for '23-ea'"); + ).rejects.toThrow("Could not find satisfied version for SemVer '23-ea'"); - expect(core.error).toHaveBeenCalledWith( - 'Available versions: 23-ea-20240716, 23-ea-20240709' - ); + // Verify error logging - removed as we now use the helper method which doesn't call core.error }); it('should throw error when no matching file for architecture', async () => { diff --git a/__tests__/distributors/liberica-installer.test.ts b/__tests__/distributors/liberica-installer.test.ts index 5e664d5f3..1787de7c3 100644 --- a/__tests__/distributors/liberica-installer.test.ts +++ b/__tests__/distributors/liberica-installer.test.ts @@ -209,7 +209,7 @@ describe('findPackageForDownload', () => { it('should throw an error', async () => { await expect(distribution['findPackageForDownload']('17')).rejects.toThrow( - /Could not find satisfied version for semver */ + /Could not find satisfied version for SemVer/ ); }); }); diff --git a/__tests__/distributors/liberica-linux-installer.test.ts b/__tests__/distributors/liberica-linux-installer.test.ts index 58c4e4781..28b640555 100644 --- a/__tests__/distributors/liberica-linux-installer.test.ts +++ b/__tests__/distributors/liberica-linux-installer.test.ts @@ -209,7 +209,7 @@ describe('findPackageForDownload', () => { it('should throw an error', async () => { await expect(distribution['findPackageForDownload']('18')).rejects.toThrow( - /Could not find satisfied version for semver */ + /Could not find satisfied version for SemVer/ ); }); }); diff --git a/__tests__/distributors/liberica-windows-installer.test.ts b/__tests__/distributors/liberica-windows-installer.test.ts index 22d287410..de59b4d2e 100644 --- a/__tests__/distributors/liberica-windows-installer.test.ts +++ b/__tests__/distributors/liberica-windows-installer.test.ts @@ -209,7 +209,7 @@ describe('findPackageForDownload', () => { it('should throw an error', async () => { await expect(distribution['findPackageForDownload']('18')).rejects.toThrow( - /Could not find satisfied version for semver */ + /Could not find satisfied version for SemVer/ ); }); }); diff --git a/__tests__/distributors/sapmachine-installer.test.ts b/__tests__/distributors/sapmachine-installer.test.ts index 5073cd9fe..9367cb7f9 100644 --- a/__tests__/distributors/sapmachine-installer.test.ts +++ b/__tests__/distributors/sapmachine-installer.test.ts @@ -266,7 +266,7 @@ describe('getAvailableVersions', () => { await expect( distribution['findPackageForDownload'](normalizedVersion) ).rejects.toThrow( - `Couldn't find any satisfied version for the specified java-version: "${normalizedVersion}" and architecture: "${arch}".` + `Could not find satisfied version for SemVer '${normalizedVersion}'` ); } ); diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts index 100429b30..d2fbfdc95 100644 --- a/__tests__/distributors/zulu-installer.test.ts +++ b/__tests__/distributors/zulu-installer.test.ts @@ -225,6 +225,6 @@ describe('findPackageForDownload', () => { distribution['getAvailableVersions'] = async () => manifestData; await expect( distribution['findPackageForDownload'](distribution['version']) - ).rejects.toThrow(/Could not find satisfied version for semver */); + ).rejects.toThrow(/Could not find satisfied version for SemVer/); }); }); diff --git a/__tests__/distributors/zulu-linux-installer.test.ts b/__tests__/distributors/zulu-linux-installer.test.ts index a25344cbd..fd81e4e8a 100644 --- a/__tests__/distributors/zulu-linux-installer.test.ts +++ b/__tests__/distributors/zulu-linux-installer.test.ts @@ -228,6 +228,6 @@ describe('findPackageForDownload', () => { distribution['getAvailableVersions'] = async () => manifestData; await expect( distribution['findPackageForDownload'](distribution['version']) - ).rejects.toThrow(/Could not find satisfied version for semver */); + ).rejects.toThrow(/Could not find satisfied version for SemVer/); }); }); diff --git a/__tests__/distributors/zulu-windows-installer.test.ts b/__tests__/distributors/zulu-windows-installer.test.ts index a3511ac90..2ca5830b9 100644 --- a/__tests__/distributors/zulu-windows-installer.test.ts +++ b/__tests__/distributors/zulu-windows-installer.test.ts @@ -226,6 +226,6 @@ describe('findPackageForDownload', () => { distribution['getAvailableVersions'] = async () => manifestData; await expect( distribution['findPackageForDownload'](distribution['version']) - ).rejects.toThrow(/Could not find satisfied version for semver */); + ).rejects.toThrow(/Could not find satisfied version for SemVer/); }); }); diff --git a/dist/setup/index.js b/dist/setup/index.js index 59aa1ec3b..8e066e190 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -84747,13 +84747,8 @@ class AdoptDistribution extends base_installer_1.JavaBase { }); const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`); + const availableVersionStrings = availableVersionsWithBinaries.map(item => item.version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; }); @@ -85102,6 +85097,28 @@ class JavaBase { stable }; } + createVersionNotFoundError(versionOrRange, availableVersions, additionalContext) { + const parts = [ + `Could not find satisfied version for SemVer '${versionOrRange}'.`, + `Distribution: ${this.distribution}`, + `Package type: ${this.packageType}`, + `Architecture: ${this.architecture}` + ]; + // Add additional context if provided (e.g., platform/OS info) + if (additionalContext) { + parts.push(additionalContext); + } + if (availableVersions && availableVersions.length > 0) { + const maxVersionsToShow = core.isDebug() ? availableVersions.length : 50; + const versionsToShow = availableVersions.slice(0, maxVersionsToShow); + const truncated = availableVersions.length > maxVersionsToShow; + parts.push(`Available versions: ${versionsToShow.join(', ')}${truncated ? '...' : ''}`); + if (truncated) { + parts.push(`(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)`); + } + } + return new Error(parts.join('\n')); + } setJavaDefault(version, toolPath) { const majorVersion = version.split('.')[0]; core.exportVariable('JAVA_HOME', toolPath); @@ -85223,13 +85240,8 @@ class CorrettoDistribution extends base_installer_1.JavaBase { }); const resolvedVersion = matchingVersions.length > 0 ? matchingVersions[0] : null; if (!resolvedVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`); + const availableVersionStrings = availableVersions.map(item => item.version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedVersion; }); @@ -85463,7 +85475,8 @@ class DragonwellDistribution extends base_installer_1.JavaBase { }; }); if (!matchedVersions.length) { - throw new Error(`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".`); + const availableVersionStrings = availableVersions.map(item => item.jdk_version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } const resolvedVersion = matchedVersions[0]; return resolvedVersion; @@ -85732,7 +85745,10 @@ class GraalVMDistribution extends base_installer_1.JavaBase { handleHttpResponse(response, range) { const statusCode = response.message.statusCode; if (statusCode === http_client_1.HttpCodes.NotFound) { - throw new Error(`Could not find GraalVM for SemVer ${range}. Please check if this version is available at ${GRAALVM_DL_BASE}`); + // Create the standard error with additional hint about checking the download URL + const error = this.createVersionNotFoundError(range); + error.message += `\nPlease check if this version is available at ${GRAALVM_DL_BASE}`; + throw error; } if (statusCode === http_client_1.HttpCodes.Unauthorized || statusCode === http_client_1.HttpCodes.Forbidden) { @@ -85749,8 +85765,8 @@ class GraalVMDistribution extends base_installer_1.JavaBase { core.debug(`Found ${versions.length} EA versions`); const latestVersion = versions.find(v => v.latest); if (!latestVersion) { - core.error(`Available versions: ${versions.map(v => v.version).join(', ')}`); - throw new Error(`Unable to find latest version for '${javaEaVersion}'`); + const availableVersions = versions.map(v => v.version); + throw this.createVersionNotFoundError(javaEaVersion, availableVersions); } core.debug(`Latest version found: ${latestVersion.version}`); const arch = this.distributionArchitecture(); @@ -85886,13 +85902,8 @@ class JetBrainsDistribution extends base_installer_1.JavaBase { }); const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = versionsRaw - .map(item => `${item.tag_name} (${item.semver}+${item.build})`) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for SemVer '${range}'. ${availableOptionsMessage}`); + const availableVersionStrings = versionsRaw.map(item => `${item.tag_name} (${item.semver}+${item.build})`); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return resolvedFullVersion; }); @@ -86129,13 +86140,8 @@ class LibericaDistributions extends base_installer_1.JavaBase { .filter(item => (0, util_1.isVersionSatisfies)(range, item.version)) .sort((a, b) => -semver_1.default.compareBuild(a.version, b.version))[0]; if (!satisfiedVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for semver ${range}. ${availableOptionsMessage}`); + const availableVersionStrings = availableVersions.map(item => item.version); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return satisfiedVersion; }); @@ -86421,9 +86427,8 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { } const foundRelease = yield tc.findFromManifest(range, true, manifest, arch); if (!foundRelease) { - throw new Error(`Could not find satisfied version for SemVer ${range}.\nAvailable versions: ${manifest - .map(item => item.version) - .join(', ')}`); + const availableVersionStrings = manifest.map(item => item.version); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return { url: foundRelease.files[0].download_url, @@ -86586,7 +86591,7 @@ class OracleDistribution extends base_installer_1.JavaBase { throw new Error(`Http request for Oracle JDK failed with status code: ${response.message.statusCode}`); } } - throw new Error(`Could not find Oracle JDK for SemVer ${range}`); + throw this.createVersionNotFoundError(range); }); } getPlatform(platform = process.platform) { @@ -86678,7 +86683,8 @@ class SapMachineDistribution extends base_installer_1.JavaBase { }; }); if (!matchedVersions.length) { - throw new Error(`Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".`); + const availableVersionStrings = availableVersions.map(item => item.version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } const resolvedVersion = matchedVersions[0]; return resolvedVersion; @@ -86917,13 +86923,11 @@ class SemeruDistribution extends base_installer_1.JavaBase { }); const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for SemVer version '${version}' for your current OS version for ${this.architecture} architecture ${availableOptionsMessage}`); + const availableVersionStrings = availableVersionsWithBinaries.map(item => item.version); + // Include platform context to help users understand OS-specific version availability + // IBM Semeru builds are OS-specific, so platform info aids in troubleshooting + const platformContext = `Platform: ${process.platform}`; + throw this.createVersionNotFoundError(version, availableVersionStrings, platformContext); } return resolvedFullVersion; }); @@ -87096,13 +87100,8 @@ class TemurinDistribution extends base_installer_1.JavaBase { }); const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}`); + const availableVersionStrings = availableVersionsWithBinaries.map(item => item.version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; }); @@ -87274,13 +87273,8 @@ class ZuluDistribution extends base_installer_1.JavaBase { }); const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error(`Could not find satisfied version for semver ${version}. ${availableOptionsMessage}`); + const availableVersionStrings = availableVersions.map(item => item.version); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; }); diff --git a/package-lock.json b/package-lock.json index 9a8bb83f4..d21d0737f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -496,7 +496,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", "dev": true, - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", @@ -1788,7 +1787,6 @@ "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", @@ -2037,7 +2035,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2317,7 +2314,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001541", "electron-to-chromium": "^1.4.535", @@ -2687,7 +2683,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -3634,7 +3629,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -5299,7 +5293,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/src/distributions/adopt/installer.ts b/src/distributions/adopt/installer.ts index 850a4a0df..34c1716cd 100644 --- a/src/distributions/adopt/installer.ts +++ b/src/distributions/adopt/installer.ts @@ -54,15 +54,10 @@ export class AdoptDistribution extends JavaBase { const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}` + const availableVersionStrings = availableVersionsWithBinaries.map( + item => item.version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 0fc4f0343..33f1a6ea8 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -259,6 +259,42 @@ export abstract class JavaBase { }; } + protected createVersionNotFoundError( + versionOrRange: string, + availableVersions?: string[], + additionalContext?: string + ): Error { + const parts = [ + `Could not find satisfied version for SemVer '${versionOrRange}'.`, + `Distribution: ${this.distribution}`, + `Package type: ${this.packageType}`, + `Architecture: ${this.architecture}` + ]; + + // Add additional context if provided (e.g., platform/OS info) + if (additionalContext) { + parts.push(additionalContext); + } + + if (availableVersions && availableVersions.length > 0) { + const maxVersionsToShow = core.isDebug() ? availableVersions.length : 50; + const versionsToShow = availableVersions.slice(0, maxVersionsToShow); + const truncated = availableVersions.length > maxVersionsToShow; + + parts.push( + `Available versions: ${versionsToShow.join(', ')}${truncated ? '...' : ''}` + ); + + if (truncated) { + parts.push( + `(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)` + ); + } + } + + return new Error(parts.join('\n')); + } + protected setJavaDefault(version: string, toolPath: string) { const majorVersion = version.split('.')[0]; core.exportVariable('JAVA_HOME', toolPath); diff --git a/src/distributions/corretto/installer.ts b/src/distributions/corretto/installer.ts index c2cc5f7cc..52af2dd96 100644 --- a/src/distributions/corretto/installer.ts +++ b/src/distributions/corretto/installer.ts @@ -75,15 +75,10 @@ export class CorrettoDistribution extends JavaBase { const resolvedVersion = matchingVersions.length > 0 ? matchingVersions[0] : null; if (!resolvedVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}` + const availableVersionStrings = availableVersions.map( + item => item.version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedVersion; } diff --git a/src/distributions/dragonwell/installer.ts b/src/distributions/dragonwell/installer.ts index 480cdbdcb..c5741bf21 100644 --- a/src/distributions/dragonwell/installer.ts +++ b/src/distributions/dragonwell/installer.ts @@ -51,9 +51,10 @@ export class DragonwellDistribution extends JavaBase { }); if (!matchedVersions.length) { - throw new Error( - `Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".` + const availableVersionStrings = availableVersions.map( + item => item.jdk_version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } const resolvedVersion = matchedVersions[0]; diff --git a/src/distributions/graalvm/installer.ts b/src/distributions/graalvm/installer.ts index 6df960c73..c15304df0 100644 --- a/src/distributions/graalvm/installer.ts +++ b/src/distributions/graalvm/installer.ts @@ -149,9 +149,10 @@ export class GraalVMDistribution extends JavaBase { const statusCode = response.message.statusCode; if (statusCode === HttpCodes.NotFound) { - throw new Error( - `Could not find GraalVM for SemVer ${range}. Please check if this version is available at ${GRAALVM_DL_BASE}` - ); + // Create the standard error with additional hint about checking the download URL + const error = this.createVersionNotFoundError(range); + error.message += `\nPlease check if this version is available at ${GRAALVM_DL_BASE}`; + throw error; } if ( @@ -180,10 +181,8 @@ export class GraalVMDistribution extends JavaBase { const latestVersion = versions.find(v => v.latest); if (!latestVersion) { - core.error( - `Available versions: ${versions.map(v => v.version).join(', ')}` - ); - throw new Error(`Unable to find latest version for '${javaEaVersion}'`); + const availableVersions = versions.map(v => v.version); + throw this.createVersionNotFoundError(javaEaVersion, availableVersions); } core.debug(`Latest version found: ${latestVersion.version}`); diff --git a/src/distributions/jetbrains/installer.ts b/src/distributions/jetbrains/installer.ts index b9e9b30bb..e3458e1ef 100644 --- a/src/distributions/jetbrains/installer.ts +++ b/src/distributions/jetbrains/installer.ts @@ -44,15 +44,10 @@ export class JetBrainsDistribution extends JavaBase { const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = versionsRaw - .map(item => `${item.tag_name} (${item.semver}+${item.build})`) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for SemVer '${range}'. ${availableOptionsMessage}` + const availableVersionStrings = versionsRaw.map( + item => `${item.tag_name} (${item.semver}+${item.build})` ); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return resolvedFullVersion; diff --git a/src/distributions/liberica/installer.ts b/src/distributions/liberica/installer.ts index 444c46ce0..d6d683a0f 100644 --- a/src/distributions/liberica/installer.ts +++ b/src/distributions/liberica/installer.ts @@ -69,15 +69,10 @@ export class LibericaDistributions extends JavaBase { .sort((a, b) => -semver.compareBuild(a.version, b.version))[0]; if (!satisfiedVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for semver ${range}. ${availableOptionsMessage}` + const availableVersionStrings = availableVersions.map( + item => item.version ); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return satisfiedVersion; diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts index 0d80c3f98..a48a3c2a3 100644 --- a/src/distributions/microsoft/installer.ts +++ b/src/distributions/microsoft/installer.ts @@ -76,11 +76,8 @@ export class MicrosoftDistributions extends JavaBase { const foundRelease = await tc.findFromManifest(range, true, manifest, arch); if (!foundRelease) { - throw new Error( - `Could not find satisfied version for SemVer ${range}.\nAvailable versions: ${manifest - .map(item => item.version) - .join(', ')}` - ); + const availableVersionStrings = manifest.map(item => item.version); + throw this.createVersionNotFoundError(range, availableVersionStrings); } return { diff --git a/src/distributions/oracle/installer.ts b/src/distributions/oracle/installer.ts index 5a492ad14..30356e07d 100644 --- a/src/distributions/oracle/installer.ts +++ b/src/distributions/oracle/installer.ts @@ -112,7 +112,7 @@ export class OracleDistribution extends JavaBase { } } - throw new Error(`Could not find Oracle JDK for SemVer ${range}`); + throw this.createVersionNotFoundError(range); } public getPlatform(platform: NodeJS.Platform = process.platform): OsVersions { diff --git a/src/distributions/sapmachine/installer.ts b/src/distributions/sapmachine/installer.ts index ab67dec34..0af0b0b44 100644 --- a/src/distributions/sapmachine/installer.ts +++ b/src/distributions/sapmachine/installer.ts @@ -49,9 +49,10 @@ export class SapMachineDistribution extends JavaBase { }); if (!matchedVersions.length) { - throw new Error( - `Couldn't find any satisfied version for the specified java-version: "${version}" and architecture: "${this.architecture}".` + const availableVersionStrings = availableVersions.map( + item => item.version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } const resolvedVersion = matchedVersions[0]; diff --git a/src/distributions/semeru/installer.ts b/src/distributions/semeru/installer.ts index e66708ecb..edb294803 100644 --- a/src/distributions/semeru/installer.ts +++ b/src/distributions/semeru/installer.ts @@ -79,14 +79,16 @@ export class SemeruDistribution extends JavaBase { const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for SemVer version '${version}' for your current OS version for ${this.architecture} architecture ${availableOptionsMessage}` + const availableVersionStrings = availableVersionsWithBinaries.map( + item => item.version + ); + // Include platform context to help users understand OS-specific version availability + // IBM Semeru builds are OS-specific, so platform info aids in troubleshooting + const platformContext = `Platform: ${process.platform}`; + throw this.createVersionNotFoundError( + version, + availableVersionStrings, + platformContext ); } diff --git a/src/distributions/temurin/installer.ts b/src/distributions/temurin/installer.ts index 1a69652ae..8d03de745 100644 --- a/src/distributions/temurin/installer.ts +++ b/src/distributions/temurin/installer.ts @@ -57,15 +57,10 @@ export class TemurinDistribution extends JavaBase { const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersionsWithBinaries - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for SemVer '${version}'. ${availableOptionsMessage}` + const availableVersionStrings = availableVersionsWithBinaries.map( + item => item.version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; diff --git a/src/distributions/zulu/installer.ts b/src/distributions/zulu/installer.ts index 124789b8b..83f879461 100644 --- a/src/distributions/zulu/installer.ts +++ b/src/distributions/zulu/installer.ts @@ -57,15 +57,10 @@ export class ZuluDistribution extends JavaBase { const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersions - .map(item => item.version) - .join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; - throw new Error( - `Could not find satisfied version for semver ${version}. ${availableOptionsMessage}` + const availableVersionStrings = availableVersions.map( + item => item.version ); + throw this.createVersionNotFoundError(version, availableVersionStrings); } return resolvedFullVersion; From 97169f0244ded495c27a47925d741f6606099be1 Mon Sep 17 00:00:00 2001 From: chiranjib-swain Date: Mon, 23 Feb 2026 09:55:17 +0530 Subject: [PATCH 2/3] Mock core.error in tests to suppress error logs --- __tests__/cache.test.ts | 9 +++++++++ __tests__/cleanup-java.test.ts | 13 +++++++++++++ __tests__/distributors/adopt-installer.test.ts | 6 ++++++ __tests__/distributors/base-installer.test.ts | 5 +++++ __tests__/distributors/corretto-installer.test.ts | 7 ++++++- __tests__/distributors/dragonwell-installer.test.ts | 6 ++++++ __tests__/distributors/graalvm-installer.test.ts | 5 +++++ __tests__/distributors/jetbrains-installer.test.ts | 6 ++++++ __tests__/distributors/liberica-installer.test.ts | 6 ++++++ .../distributors/liberica-linux-installer.test.ts | 6 ++++++ .../distributors/liberica-windows-installer.test.ts | 5 +++++ __tests__/distributors/local-installer.test.ts | 5 +++++ __tests__/distributors/microsoft-installer.test.ts | 5 +++++ __tests__/distributors/oracle-installer.test.ts | 5 +++++ __tests__/distributors/sapmachine-installer.test.ts | 6 ++++++ __tests__/distributors/semeru-installer.test.ts | 5 +++++ __tests__/distributors/temurin-installer.test.ts | 5 +++++ __tests__/distributors/zulu-installer.test.ts | 6 ++++++ __tests__/distributors/zulu-linux-installer.test.ts | 6 ++++++ .../distributors/zulu-windows-installer.test.ts | 6 ++++++ 20 files changed, 122 insertions(+), 1 deletion(-) diff --git a/__tests__/cache.test.ts b/__tests__/cache.test.ts index 9762fb983..df7a59bd4 100644 --- a/__tests__/cache.test.ts +++ b/__tests__/cache.test.ts @@ -17,6 +17,7 @@ describe('dependency cache', () => { let spyWarning: jest.SpyInstance>; let spyDebug: jest.SpyInstance>; let spySaveState: jest.SpyInstance>; + let spyCoreError: jest.SpyInstance; beforeEach(() => { workspace = mkdtempSync(join(tmpdir(), 'setup-java-cache-')); @@ -51,6 +52,10 @@ describe('dependency cache', () => { spySaveState = jest.spyOn(core, 'saveState'); spySaveState.mockImplementation(() => null); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { @@ -58,6 +63,10 @@ describe('dependency cache', () => { process.env['GITHUB_WORKSPACE'] = ORIGINAL_GITHUB_WORKSPACE; process.env['RUNNER_OS'] = ORIGINAL_RUNNER_OS; resetState(); + + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); }); describe('restore', () => { diff --git a/__tests__/cleanup-java.test.ts b/__tests__/cleanup-java.test.ts index 375a2ad15..4cd2709d8 100644 --- a/__tests__/cleanup-java.test.ts +++ b/__tests__/cleanup-java.test.ts @@ -11,19 +11,32 @@ describe('cleanup', () => { Parameters >; let spyJobStatusSuccess: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyWarning = jest.spyOn(core, 'warning'); spyWarning.mockImplementation(() => null); + spyInfo = jest.spyOn(core, 'info'); spyInfo.mockImplementation(() => null); + spyCacheSave = jest.spyOn(cache, 'saveCache'); + spyJobStatusSuccess = jest.spyOn(util, 'isJobStatusSuccess'); spyJobStatusSuccess.mockReturnValue(true); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); + createStateForSuccessfulRestore(); }); + afterEach(() => { resetState(); + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); }); it('does not fail nor warn even when the save process throws a ReserveCacheError', async () => { diff --git a/__tests__/distributors/adopt-installer.test.ts b/__tests__/distributors/adopt-installer.test.ts index 0b35c3d3e..d24940ff9 100644 --- a/__tests__/distributors/adopt-installer.test.ts +++ b/__tests__/distributors/adopt-installer.test.ts @@ -9,9 +9,11 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models'; import os from 'os'; import manifestData from '../data/adopt.json'; +import * as core from '@actions/core'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -20,6 +22,10 @@ describe('getAvailableVersions', () => { headers: {}, result: [] }); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts index befa2d254..3905c7113 100644 --- a/__tests__/distributors/base-installer.test.ts +++ b/__tests__/distributors/base-installer.test.ts @@ -248,6 +248,7 @@ describe('setupJava', () => { let spyCoreExportVariable: jest.SpyInstance; let spyCoreAddPath: jest.SpyInstance; let spyCoreSetOutput: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyGetToolcachePath = jest.spyOn(util, 'getToolcachePath'); @@ -287,6 +288,10 @@ describe('setupJava', () => { spyCoreSetOutput = jest.spyOn(core, 'setOutput'); spyCoreSetOutput.mockImplementation(() => undefined); + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => undefined); + jest.spyOn(os, 'arch').mockReturnValue('x86' as ReturnType); }); diff --git a/__tests__/distributors/corretto-installer.test.ts b/__tests__/distributors/corretto-installer.test.ts index 1da5e393e..4234f4e47 100644 --- a/__tests__/distributors/corretto-installer.test.ts +++ b/__tests__/distributors/corretto-installer.test.ts @@ -4,13 +4,14 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models'; import {CorrettoDistribution} from '../../src/distributions/corretto/installer'; import * as util from '../../src/util'; import os from 'os'; -import {isGeneratorFunction} from 'util/types'; +import * as core from '@actions/core'; import manifestData from '../data/corretto.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -23,6 +24,10 @@ describe('getAvailableVersions', () => { util, 'getDownloadArchiveExtension' ); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/dragonwell-installer.test.ts b/__tests__/distributors/dragonwell-installer.test.ts index e33c74791..de6564ed3 100644 --- a/__tests__/distributors/dragonwell-installer.test.ts +++ b/__tests__/distributors/dragonwell-installer.test.ts @@ -1,12 +1,14 @@ import {HttpClient} from '@actions/http-client'; import {DragonwellDistribution} from '../../src/distributions/dragonwell/installer'; import * as utils from '../../src/util'; +import * as core from '@actions/core'; import manifestData from '../data/dragonwell.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -21,6 +23,10 @@ describe('getAvailableVersions', () => { 'getDownloadArchiveExtension' ); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index 95f553e35..bd12d3b4b 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -42,6 +42,7 @@ beforeAll(() => { describe('GraalVMDistribution', () => { let distribution: GraalVMDistribution; let mockHttpClient: jest.Mocked; + let spyCoreError: jest.SpyInstance; const defaultOptions: JavaInstallerOptions = { version: '17', @@ -59,6 +60,10 @@ describe('GraalVMDistribution', () => { (distribution as any).http = mockHttpClient; (util.getDownloadArchiveExtension as jest.Mock).mockReturnValue('tar.gz'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterAll(() => { diff --git a/__tests__/distributors/jetbrains-installer.test.ts b/__tests__/distributors/jetbrains-installer.test.ts index 44d8ef896..e75a76db0 100644 --- a/__tests__/distributors/jetbrains-installer.test.ts +++ b/__tests__/distributors/jetbrains-installer.test.ts @@ -4,9 +4,11 @@ import {JetBrainsDistribution} from '../../src/distributions/jetbrains/installer import manifestData from '../data/jetbrains.json'; import os from 'os'; +import * as core from '@actions/core'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -15,6 +17,10 @@ describe('getAvailableVersions', () => { headers: {}, result: [] }); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/liberica-installer.test.ts b/__tests__/distributors/liberica-installer.test.ts index 1787de7c3..dbf7f43da 100644 --- a/__tests__/distributors/liberica-installer.test.ts +++ b/__tests__/distributors/liberica-installer.test.ts @@ -5,11 +5,13 @@ import { } from '../../src/distributions/liberica/models'; import {HttpClient} from '@actions/http-client'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/liberica.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -18,6 +20,10 @@ describe('getAvailableVersions', () => { headers: {}, result: manifestData as LibericaVersion[] }); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/liberica-linux-installer.test.ts b/__tests__/distributors/liberica-linux-installer.test.ts index 28b640555..74f014b37 100644 --- a/__tests__/distributors/liberica-linux-installer.test.ts +++ b/__tests__/distributors/liberica-linux-installer.test.ts @@ -5,11 +5,13 @@ import { } from '../../src/distributions/liberica/models'; import {HttpClient} from '@actions/http-client'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/liberica-linux.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -18,6 +20,10 @@ describe('getAvailableVersions', () => { headers: {}, result: manifestData as LibericaVersion[] }); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/liberica-windows-installer.test.ts b/__tests__/distributors/liberica-windows-installer.test.ts index de59b4d2e..0d6c12f44 100644 --- a/__tests__/distributors/liberica-windows-installer.test.ts +++ b/__tests__/distributors/liberica-windows-installer.test.ts @@ -5,11 +5,13 @@ import { } from '../../src/distributions/liberica/models'; import {HttpClient} from '@actions/http-client'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/liberica-windows.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -18,6 +20,9 @@ describe('getAvailableVersions', () => { headers: {}, result: manifestData as LibericaVersion[] }); + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/local-installer.test.ts b/__tests__/distributors/local-installer.test.ts index 8e9d5d437..201d1d254 100644 --- a/__tests__/distributors/local-installer.test.ts +++ b/__tests__/distributors/local-installer.test.ts @@ -27,6 +27,7 @@ describe('setupJava', () => { let spyFsReadDir: jest.SpyInstance; let spyUtilsExtractJdkFile: jest.SpyInstance; let spyPathResolve: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; const expectedJdkFile = 'JavaLocalJdkFile'; beforeEach(() => { @@ -93,6 +94,10 @@ describe('setupJava', () => { // Spy on path methods spyPathResolve = jest.spyOn(path, 'resolve'); spyPathResolve.mockImplementation((path: string) => path); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts index 16c436370..bac9d4259 100644 --- a/__tests__/distributors/microsoft-installer.test.ts +++ b/__tests__/distributors/microsoft-installer.test.ts @@ -8,6 +8,7 @@ describe('findPackageForDownload', () => { let distribution: MicrosoftDistributions; let spyGetManifestFromRepo: jest.SpyInstance; let spyDebug: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { distribution = new MicrosoftDistributions({ @@ -26,6 +27,10 @@ describe('findPackageForDownload', () => { spyDebug = jest.spyOn(core, 'debug'); spyDebug.mockImplementation(() => {}); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); it.each([ diff --git a/__tests__/distributors/oracle-installer.test.ts b/__tests__/distributors/oracle-installer.test.ts index 226eca905..6f64058c3 100644 --- a/__tests__/distributors/oracle-installer.test.ts +++ b/__tests__/distributors/oracle-installer.test.ts @@ -8,6 +8,7 @@ describe('findPackageForDownload', () => { let distribution: OracleDistribution; let spyDebug: jest.SpyInstance; let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { distribution = new OracleDistribution({ @@ -19,6 +20,10 @@ describe('findPackageForDownload', () => { spyDebug = jest.spyOn(core, 'debug'); spyDebug.mockImplementation(() => {}); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); it.each([ diff --git a/__tests__/distributors/sapmachine-installer.test.ts b/__tests__/distributors/sapmachine-installer.test.ts index 9367cb7f9..e2f197464 100644 --- a/__tests__/distributors/sapmachine-installer.test.ts +++ b/__tests__/distributors/sapmachine-installer.test.ts @@ -1,12 +1,14 @@ import {HttpClient} from '@actions/http-client'; import {SapMachineDistribution} from '../../src/distributions/sapmachine/installer'; import * as utils from '../../src/util'; +import * as core from '@actions/core'; import manifestData from '../data/sapmachine.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -21,6 +23,10 @@ describe('getAvailableVersions', () => { 'getDownloadArchiveExtension' ); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/semeru-installer.test.ts b/__tests__/distributors/semeru-installer.test.ts index 690478f79..61e618c25 100644 --- a/__tests__/distributors/semeru-installer.test.ts +++ b/__tests__/distributors/semeru-installer.test.ts @@ -4,9 +4,11 @@ import {JavaInstallerOptions} from '../../src/distributions/base-models'; import {SemeruDistribution} from '../../src/distributions/semeru/installer'; import manifestData from '../data/semeru.json'; +import * as core from '@actions/core'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -15,6 +17,9 @@ describe('getAvailableVersions', () => { headers: {}, result: [] }); + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/temurin-installer.test.ts b/__tests__/distributors/temurin-installer.test.ts index f540901eb..5810c8818 100644 --- a/__tests__/distributors/temurin-installer.test.ts +++ b/__tests__/distributors/temurin-installer.test.ts @@ -7,9 +7,11 @@ import { import {JavaInstallerOptions} from '../../src/distributions/base-models'; import manifestData from '../data/temurin.json'; +import * as core from '@actions/core'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -18,6 +20,9 @@ describe('getAvailableVersions', () => { headers: {}, result: [] }); + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts index d2fbfdc95..1372d0e48 100644 --- a/__tests__/distributors/zulu-installer.test.ts +++ b/__tests__/distributors/zulu-installer.test.ts @@ -3,12 +3,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer'; import {IZuluVersions} from '../../src/distributions/zulu/models'; import * as utils from '../../src/util'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/zulu-releases-default.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -23,6 +25,10 @@ describe('getAvailableVersions', () => { 'getDownloadArchiveExtension' ); spyUtilGetDownloadArchiveExtension.mockReturnValue('tar.gz'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/zulu-linux-installer.test.ts b/__tests__/distributors/zulu-linux-installer.test.ts index fd81e4e8a..a37da36ed 100644 --- a/__tests__/distributors/zulu-linux-installer.test.ts +++ b/__tests__/distributors/zulu-linux-installer.test.ts @@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer'; import {IZuluVersions} from '../../src/distributions/zulu/models'; import * as utils from '../../src/util'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/zulu-linux.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -24,6 +26,10 @@ describe('getAvailableVersions', () => { 'getDownloadArchiveExtension' ); spyUtilGetDownloadArchiveExtension.mockReturnValue('zip'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { diff --git a/__tests__/distributors/zulu-windows-installer.test.ts b/__tests__/distributors/zulu-windows-installer.test.ts index 2ca5830b9..c70c1a780 100644 --- a/__tests__/distributors/zulu-windows-installer.test.ts +++ b/__tests__/distributors/zulu-windows-installer.test.ts @@ -4,12 +4,14 @@ import {ZuluDistribution} from '../../src/distributions/zulu/installer'; import {IZuluVersions} from '../../src/distributions/zulu/models'; import * as utils from '../../src/util'; import os from 'os'; +import * as core from '@actions/core'; import manifestData from '../data/zulu-windows.json'; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; let spyUtilGetDownloadArchiveExtension: jest.SpyInstance; + let spyCoreError: jest.SpyInstance; beforeEach(() => { spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); @@ -24,6 +26,10 @@ describe('getAvailableVersions', () => { 'getDownloadArchiveExtension' ); spyUtilGetDownloadArchiveExtension.mockReturnValue('zip'); + + // Mock core.error to suppress error logs + spyCoreError = jest.spyOn(core, 'error'); + spyCoreError.mockImplementation(() => {}); }); afterEach(() => { From 102c2095e0da607bf6cbcbde034a9dee2583f107 Mon Sep 17 00:00:00 2001 From: chiranjib-swain Date: Thu, 19 Mar 2026 10:15:48 +0530 Subject: [PATCH 3/3] fix(graalvm): improve error messages for EA version not found scenarios --- __tests__/distributors/graalvm-installer.test.ts | 6 ++++-- dist/setup/index.js | 8 ++++++-- src/distributions/base-installer.ts | 2 +- src/distributions/graalvm/installer.ts | 6 +++++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/__tests__/distributors/graalvm-installer.test.ts b/__tests__/distributors/graalvm-installer.test.ts index bd12d3b4b..1ba002e69 100644 --- a/__tests__/distributors/graalvm-installer.test.ts +++ b/__tests__/distributors/graalvm-installer.test.ts @@ -508,7 +508,7 @@ describe('GraalVMDistribution', () => { await expect( (distribution as any).findPackageForDownload('23') ).rejects.toThrow( - "Could not find satisfied version for SemVer '23-ea'" + "No EA build is marked as 'latest' for version range '23-ea'. Available EA versions: 23-ea-20240716." ); // Verify error logging - removed as we now use the helper method which doesn't call core.error @@ -718,7 +718,9 @@ describe('GraalVMDistribution', () => { await expect( (distribution as any).findEABuildDownloadUrl('23-ea') - ).rejects.toThrow("Could not find satisfied version for SemVer '23-ea'"); + ).rejects.toThrow( + "No EA build is marked as 'latest' for version range '23-ea'. Available EA versions: 23-ea-20240716, 23-ea-20240709." + ); // Verify error logging - removed as we now use the helper method which doesn't call core.error }); diff --git a/dist/setup/index.js b/dist/setup/index.js index 0b3478220..d87d859ad 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -112584,7 +112584,7 @@ class JavaBase { const maxVersionsToShow = core.isDebug() ? availableVersions.length : 50; const versionsToShow = availableVersions.slice(0, maxVersionsToShow); const truncated = availableVersions.length > maxVersionsToShow; - parts.push(`Available versions: ${versionsToShow.join(', ')}${truncated ? '...' : ''}`); + parts.push(`Available versions: ${versionsToShow.join(', ')}${truncated ? ', ...' : ''}`); if (truncated) { parts.push(`(showing first ${maxVersionsToShow} of ${availableVersions.length} versions, enable debug mode to see all)`); } @@ -113238,7 +113238,11 @@ class GraalVMDistribution extends base_installer_1.JavaBase { const latestVersion = versions.find(v => v.latest); if (!latestVersion) { const availableVersions = versions.map(v => v.version); - throw this.createVersionNotFoundError(javaEaVersion, availableVersions); + let message = `No EA build is marked as 'latest' for version range '${javaEaVersion}'.`; + if (availableVersions.length > 0) { + message += ` Available EA versions: ${availableVersions.join(', ')}.`; + } + throw new Error(message); } core.debug(`Latest version found: ${latestVersion.version}`); const arch = this.distributionArchitecture(); diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 33f1a6ea8..c3eb263a7 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -282,7 +282,7 @@ export abstract class JavaBase { const truncated = availableVersions.length > maxVersionsToShow; parts.push( - `Available versions: ${versionsToShow.join(', ')}${truncated ? '...' : ''}` + `Available versions: ${versionsToShow.join(', ')}${truncated ? ', ...' : ''}` ); if (truncated) { diff --git a/src/distributions/graalvm/installer.ts b/src/distributions/graalvm/installer.ts index c15304df0..a92f901f0 100644 --- a/src/distributions/graalvm/installer.ts +++ b/src/distributions/graalvm/installer.ts @@ -182,7 +182,11 @@ export class GraalVMDistribution extends JavaBase { const latestVersion = versions.find(v => v.latest); if (!latestVersion) { const availableVersions = versions.map(v => v.version); - throw this.createVersionNotFoundError(javaEaVersion, availableVersions); + let message = `No EA build is marked as 'latest' for version range '${javaEaVersion}'.`; + if (availableVersions.length > 0) { + message += ` Available EA versions: ${availableVersions.join(', ')}.`; + } + throw new Error(message); } core.debug(`Latest version found: ${latestVersion.version}`);