diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts index 4fdc32144..b45b5109e 100644 --- a/__tests__/auth.test.ts +++ b/__tests__/auth.test.ts @@ -1,13 +1,7 @@ import io = require('@actions/io'); import fs = require('fs'); import path = require('path'); - -// make the os.homedir() call be local to the tests -jest.doMock('os', () => { - return { - homedir: jest.fn(() => __dirname) - }; -}); +import os from 'os'; import * as auth from '../src/auth'; @@ -15,8 +9,12 @@ const m2Dir = path.join(__dirname, auth.M2_DIR); const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE); describe('auth tests', () => { + let spyOSHomedir: jest.SpyInstance; + beforeEach(async () => { await io.rmRF(m2Dir); + spyOSHomedir = jest.spyOn(os, 'homedir'); + spyOSHomedir.mockReturnValue(__dirname); }, 300000); afterAll(async () => { @@ -25,6 +23,9 @@ describe('auth tests', () => { } catch { console.log('Failed to remove test directories'); } + jest.resetAllMocks(); + jest.clearAllMocks(); + jest.restoreAllMocks(); }, 100000); it('creates settings.xml in alternate locations', async () => { diff --git a/__tests__/data/zulu/zulu-releases-default.json b/__tests__/data/zulu-releases-default.json similarity index 97% rename from __tests__/data/zulu/zulu-releases-default.json rename to __tests__/data/zulu-releases-default.json index b1572aeb3..f23a87d43 100644 --- a/__tests__/data/zulu/zulu-releases-default.json +++ b/__tests__/data/zulu-releases-default.json @@ -48,13 +48,6 @@ "zulu_version": [8, 48, 0, 47], "jdk_version": [8, 0, 262, 17] }, - { - "id": 11535, - "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", - "name": "zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", - "zulu_version": [8, 48, 0, 49], - "jdk_version": [8, 0, 262, 18] - }, { "id": 11622, "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.51-ca-jdk8.0.262-macosx_x64.tar.gz", @@ -62,6 +55,13 @@ "zulu_version": [8, 48, 0, 51], "jdk_version": [8, 0, 262, 19] }, + { + "id": 11535, + "url": "https://cdn.azul.com/zulu/bin/zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", + "name": "zulu8.48.0.49-ca-jdk8.0.262-macosx_x64.tar.gz", + "zulu_version": [8, 48, 0, 49], + "jdk_version": [8, 0, 262, 18] + }, { "id": 12424, "url": "https://cdn.azul.com/zulu/bin/zulu8.52.0.23-ca-jdk8.0.282-macosx_x64.tar.gz", @@ -132,6 +132,13 @@ "zulu_version": [11, 35, 15, 0], "jdk_version": [11, 0, 5, 10] }, + { + "id": 10933, + "url": "https://cdn.azul.com/zulu/bin/zulu11.35.11-ca-jdk11.0.5-macosx_x64.tar.gz", + "name": "zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz", + "zulu_version": [11, 35, 11, 0], + "jdk_version": [11, 0, 5, 10] + }, { "id": 12397, "url": "https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_x64.tar.gz", diff --git a/__tests__/distributors/adoptium-installer.test.ts b/__tests__/distributors/adoptium-installer.test.ts index 3297b3d2c..f37c6a911 100644 --- a/__tests__/distributors/adoptium-installer.test.ts +++ b/__tests__/distributors/adoptium-installer.test.ts @@ -97,7 +97,6 @@ describe('findPackageForDownload', () => { ['15.0', '15.0.2+7'], ['15.0.2', '15.0.2+7'], ['15.0.1', '15.0.1+9.1'], - //['15.0.1.9', '15.0.1+9.1'], // is not supported yet ['11.x', '11.0.10+9'], ['x', '15.0.2+7'], ['12', '12.0.2+10.3'] // make sure that '12.0.2+10.1', '12.0.2+10.3', '12.0.2+10.2' are sorted correctly diff --git a/__tests__/distributors/zulu-installer.test.ts b/__tests__/distributors/zulu-installer.test.ts index 353e6b4d8..dbb394c5b 100644 --- a/__tests__/distributors/zulu-installer.test.ts +++ b/__tests__/distributors/zulu-installer.test.ts @@ -1,9 +1,10 @@ import { HttpClient } from '@actions/http-client'; +import * as semver from 'semver'; import { ZuluDistributor } from '../../src/distributors/zulu/installer'; import { IZuluVersions } from '../../src/distributors/zulu/models'; import * as utils from '../../src/util'; -let manifestData = require('../data/zulu/zulu-releases-default.json'); +const manifestData = require('../data/zulu-releases-default.json') as []; describe('getAvailableVersions', () => { let spyHttpClient: jest.SpyInstance; @@ -64,31 +65,8 @@ describe('getAvailableVersions', () => { it('load available versions', async () => { zuluDistributor = new ZuluDistributor({ version: '11', arch: 'x86', packageType: 'jdk' }); - await expect(zuluDistributor['getAvailableVersions']()).resolves.not.toBeNull(); - }); - - it('Error is thrown for empty response', async () => { - spyHttpClient.mockReturnValue({ - statusCode: 200, - headers: {}, - result: [] as IZuluVersions[] - }); - zuluDistributor = new ZuluDistributor({ version: '11', arch: 'x86', packageType: 'jdk' }); - await expect(zuluDistributor['getAvailableVersions']()).rejects.toThrowError( - /No versions were found using url */ - ); - }); - - it('Error is thrown for undefined', async () => { - spyHttpClient.mockReturnValue({ - statusCode: 200, - headers: {}, - result: undefined - }); - zuluDistributor = new ZuluDistributor({ version: '11', arch: 'x86', packageType: 'jdk' }); - await expect(zuluDistributor['getAvailableVersions']()).rejects.toThrowError( - /No versions were found using url */ - ); + const availableVersions = await zuluDistributor['getAvailableVersions'](); + expect(availableVersions).toHaveLength(manifestData.length); }); }); @@ -109,41 +87,53 @@ describe('getArchitectureOptions', () => { }); describe('findPackageForDownload', () => { - let spyHttpClient: jest.SpyInstance; - let zuluDistributor: ZuluDistributor; - - beforeEach(() => { - spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); - spyHttpClient.mockReturnValue({ - statusCode: 200, - headers: {}, - result: manifestData - }); - }); - - afterEach(() => { - jest.resetAllMocks(); - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - it.each([ ['8', '8.0.282+8'], - ['11', '11.0.10+9'], + ['11.x', '11.0.10+9'], ['8.0', '8.0.282+8'], - ['11.0', '11.0.10+9'], - ['15', '15.0.2+7'] + ['11.0.x', '11.0.10+9'], + ['15', '15.0.2+7'], + ['9.0.0', '9.0.0+0'], + ['9.0', '9.0.1+0'], + ['8.0.262', '8.0.262+19'] // validate correct choise between [8.0.262.17, 8.0.262.19, 8.0.262.18] ])('version is %s -> %s', async (input, expected) => { - let zuluDistributor = new ZuluDistributor({ version: input, arch: 'x86', packageType: 'jdk' }); + const zuluDistributor = new ZuluDistributor({ + version: input, + arch: 'x86', + packageType: 'jdk' + }); + zuluDistributor['getAvailableVersions'] = async () => manifestData; const result = await zuluDistributor['findPackageForDownload'](zuluDistributor['version']); - expect(result.version).toBe(expected); }); - it('Should throw an error', async () => { - zuluDistributor = new ZuluDistributor({ version: '18', arch: 'x86', packageType: 'jdk' }); + it('select correct bundle if there are multiple items with the same jdk version but different zulu versions', async () => { + const zuluDistributor = new ZuluDistributor({ version: '', arch: 'x86', packageType: 'jdk' }); + zuluDistributor['getAvailableVersions'] = async () => manifestData; + const result = await zuluDistributor['findPackageForDownload'](new semver.Range('11.0.5')); + expect(result.url).toBe( + 'https://cdn.azul.com/zulu/bin/zulu11.35.15-ca-jdk11.0.5-macosx_x64.tar.gz' + ); + }); + + it('should throw an error', async () => { + const zuluDistributor = new ZuluDistributor({ version: '18', arch: 'x86', packageType: 'jdk' }); await expect( zuluDistributor['findPackageForDownload'](zuluDistributor['version']) ).rejects.toThrowError(/Could not find satisfied version for semver */); }); }); + +describe('convertVersionToSemver', () => { + it.each([ + [[12], '12'], + [[12, 0], '12.0'], + [[12, 0, 2], '12.0.2'], + [[12, 0, 2, 1], '12.0.2+1'], + [[12, 0, 2, 1, 3], '12.0.2+1'] + ])('%s -> %s', (input: number[], expected: string) => { + const distributor = new ZuluDistributor({ version: '18', arch: 'x86', packageType: 'jdk' }); + const actual = distributor['convertVersionToSemver'](input); + expect(actual).toBe(expected); + }); +}); diff --git a/dist/setup/index.js b/dist/setup/index.js index 418264899..749f9b94e 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -10273,32 +10273,31 @@ class AdoptiumDistributor extends base_installer_1.JavaBase { constructor(installerOptions) { super('Adoptium', installerOptions); } - // TO-DO: Validate that all versions are available through API findPackageForDownload(version) { return __awaiter(this, void 0, void 0, function* () { - const availableVersions = yield this.getAvailableVersions(); - const availableVersionsWithBinaries = availableVersions.filter(item => item.binaries.length > 0); - const satisfiedVersions = semver_1.default.rsort(availableVersionsWithBinaries - .map(item => item.version_data.semver) - .filter(item => semver_1.default.satisfies(item, version))); - const maxSatisfiedVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; - const resolvedFullVersion = availableVersions.find(item => item.version_data.semver === maxSatisfiedVersion); + const availableVersionsRaw = yield this.getAvailableVersions(); + const availableVersionsWithBinaries = availableVersionsRaw + .filter(item => item.binaries.length > 0) + .map(item => { + return { + version: item.version_data.semver, + url: item.binaries[0].package.link + }; + }); + const satisfiedVersions = availableVersionsWithBinaries + .filter(item => semver_1.default.satisfies(item.version, version)) + .sort((a, b) => { + return -semver_1.default.compareBuild(a.version, b.version); + }); + const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersions.map(item => item.version_data.semver).join(', '); + 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.raw}'. ${availableOptionsMessage}`); } - if (resolvedFullVersion.binaries.length < 0) { - throw new Error(`No binaries were found for SemVer '${version.raw}'`); - } - // take the first element in 'binaries' array - // because it is already filtered by arch and platform options and can't contain > 1 elements - return { - version: resolvedFullVersion.version_data.semver, - url: resolvedFullVersion.binaries[0].package.link - }; + return resolvedFullVersion; }); } downloadTool(javaRelease) { @@ -33252,7 +33251,6 @@ const path = __importStar(__webpack_require__(622)); const distributor_factory_1 = __webpack_require__(264); // To-Do need check resolving with 4 numbers // To-Do add check that Java resolves from to toolcache to e2e -// To-Do check sorting for zulu for maxSatisfying function run() { return __awaiter(this, void 0, void 0, function* () { try { @@ -37407,7 +37405,6 @@ const fs_1 = __importDefault(__webpack_require__(747)); const semver_1 = __importDefault(__webpack_require__(280)); const base_installer_1 = __webpack_require__(534); const util_1 = __webpack_require__(322); -// TO-DO: issue with 4 digits versions: 15.0.0.36 / 15.0.0+36 class ZuluDistributor extends base_installer_1.JavaBase { constructor(installerOptions) { super('Zulu', installerOptions); @@ -37415,19 +37412,28 @@ class ZuluDistributor extends base_installer_1.JavaBase { findPackageForDownload(version) { return __awaiter(this, void 0, void 0, function* () { const availableVersionsRaw = yield this.getAvailableVersions(); - if (availableVersionsRaw.length === 0) { - throw new Error(`No versions were found'`); - } const availableVersions = availableVersionsRaw.map(item => { - const version = item.jdk_version.slice(0, 3).join('.') + '+' + item.jdk_version[3]; return { - version, + version: this.convertVersionToSemver(item.jdk_version), + url: item.url, + zuluVersion: this.convertVersionToSemver(item.zulu_version) + }; + }); + const satisfiedVersions = availableVersions + .filter(item => semver_1.default.satisfies(item.version, version)) + .sort((a, b) => { + // Azul provides two versions: jdk_version and azul_version + // we should sort by both fields by descending + return (-semver_1.default.compareBuild(a.version, b.version) || + -semver_1.default.compareBuild(a.zuluVersion, b.zuluVersion)); + }) + .map(item => { + return { + version: item.version, url: item.url }; }); - const satisfiedVersions = semver_1.default.rsort(availableVersions.map(item => item.version).filter(item => semver_1.default.satisfies(item, version))); - const maxSatisfiedVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; - const resolvedFullVersion = availableVersions.find(item => item.version === maxSatisfiedVersion); + const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { const availableOptions = availableVersions.map(item => item.version).join(', '); const availableOptionsMessage = availableOptions @@ -37453,7 +37459,7 @@ class ZuluDistributor extends base_installer_1.JavaBase { }); } getAvailableVersions() { - var _a; + var _a, _b; return __awaiter(this, void 0, void 0, function* () { const { arch, hw_bitness, abi } = this.getArchitectureOptions(); const [bundleType, features] = this.packageType.split('+'); @@ -37479,11 +37485,7 @@ class ZuluDistributor extends base_installer_1.JavaBase { if (core.isDebug()) { core.debug(`Gathering available versions from '${availableVersionsUrl}'`); } - const availableVersions = (yield this.http.getJson(availableVersionsUrl)) - .result; - if (!availableVersions || availableVersions.length === 0) { - throw new Error(`No versions were found using url '${availableVersionsUrl}'`); - } + const availableVersions = (_b = (yield this.http.getJson(availableVersionsUrl)).result) !== null && _b !== void 0 ? _b : []; if (core.isDebug()) { core.startGroup('Print information about available versions'); console.timeEnd('azul-retrieve-available-versions'); @@ -37521,6 +37523,15 @@ class ZuluDistributor extends base_installer_1.JavaBase { return process.platform; } } + // Azul API returns jdk_version as array of digits like [11, 0, 2, 1] + convertVersionToSemver(version_array) { + const mainVersion = version_array.slice(0, 3).join('.'); + if (version_array.length > 3) { + // intentionally ignore more than 4 numbers because it is invalid semver + return `${mainVersion}+${version_array[3]}`; + } + return mainVersion; + } } exports.ZuluDistributor = ZuluDistributor; diff --git a/src/distributors/adoptium/installer.ts b/src/distributors/adoptium/installer.ts index 859334026..5d07dfc52 100644 --- a/src/distributors/adoptium/installer.ts +++ b/src/distributors/adoptium/installer.ts @@ -16,26 +16,26 @@ export class AdoptiumDistributor extends JavaBase { super('Adoptium', installerOptions); } - // TO-DO: Validate that all versions are available through API - protected async findPackageForDownload(version: semver.Range): Promise { - const availableVersions = await this.getAvailableVersions(); + const availableVersionsRaw = await this.getAvailableVersions(); + const availableVersionsWithBinaries = availableVersionsRaw + .filter(item => item.binaries.length > 0) + .map(item => { + return { + version: item.version_data.semver, + url: item.binaries[0].package.link + } as JavaDownloadRelease; + }); - const availableVersionsWithBinaries = availableVersions.filter( - item => item.binaries.length > 0 - ); - const satisfiedVersions = semver.rsort( - availableVersionsWithBinaries - .map(item => item.version_data.semver) - .filter(item => semver.satisfies(item, version)) - ); - const maxSatisfiedVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; - const resolvedFullVersion = availableVersions.find( - item => item.version_data.semver === maxSatisfiedVersion - ); + const satisfiedVersions = availableVersionsWithBinaries + .filter(item => semver.satisfies(item.version, version)) + .sort((a, b) => { + return -semver.compareBuild(a.version, b.version); + }); + const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { - const availableOptions = availableVersions.map(item => item.version_data.semver).join(', '); + const availableOptions = availableVersionsWithBinaries.map(item => item.version).join(', '); const availableOptionsMessage = availableOptions ? `\nAvailable versions: ${availableOptions}` : ''; @@ -44,16 +44,7 @@ export class AdoptiumDistributor extends JavaBase { ); } - if (resolvedFullVersion.binaries.length < 0) { - throw new Error(`No binaries were found for SemVer '${version.raw}'`); - } - - // take the first element in 'binaries' array - // because it is already filtered by arch and platform options and can't contain > 1 elements - return { - version: resolvedFullVersion.version_data.semver, - url: resolvedFullVersion.binaries[0].package.link - }; + return resolvedFullVersion; } protected async downloadTool(javaRelease: JavaDownloadRelease): Promise { diff --git a/src/distributors/zulu/installer.ts b/src/distributors/zulu/installer.ts index 503cd7e20..0eb9259ed 100644 --- a/src/distributors/zulu/installer.ts +++ b/src/distributors/zulu/installer.ts @@ -9,8 +9,7 @@ import { JavaBase } from '../base-installer'; import { IZuluVersions } from './models'; import { extractJdkFile, getDownloadArchiveExtension } from '../../util'; import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models'; - -// TO-DO: issue with 4 digits versions: 15.0.0.36 / 15.0.0+36 +import { TIMEOUT } from 'dns'; export class ZuluDistributor extends JavaBase { constructor(installerOptions: JavaInstallerOptions) { @@ -19,24 +18,32 @@ export class ZuluDistributor extends JavaBase { protected async findPackageForDownload(version: semver.Range): Promise { const availableVersionsRaw = await this.getAvailableVersions(); - if (availableVersionsRaw.length === 0) { - throw new Error(`No versions were found'`); - } const availableVersions = availableVersionsRaw.map(item => { - const version = item.jdk_version.slice(0, 3).join('.') + '+' + item.jdk_version[3]; return { - version, - url: item.url - } as JavaDownloadRelease; + version: this.convertVersionToSemver(item.jdk_version), + url: item.url, + zuluVersion: this.convertVersionToSemver(item.zulu_version) + }; }); - const satisfiedVersions = semver.rsort( - availableVersions.map(item => item.version).filter(item => semver.satisfies(item, version)) - ); - const maxSatisfiedVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; - const resolvedFullVersion = availableVersions.find( - item => item.version === maxSatisfiedVersion - ); + const satisfiedVersions = availableVersions + .filter(item => semver.satisfies(item.version, version)) + .sort((a, b) => { + // Azul provides two versions: jdk_version and azul_version + // we should sort by both fields by descending + return ( + -semver.compareBuild(a.version, b.version) || + -semver.compareBuild(a.zuluVersion, b.zuluVersion) + ); + }) + .map(item => { + return { + version: item.version, + url: item.url + } as JavaDownloadRelease; + }); + + const resolvedFullVersion = satisfiedVersions.length > 0 ? satisfiedVersions[0] : null; if (!resolvedFullVersion) { const availableOptions = availableVersions.map(item => item.version).join(', '); const availableOptionsMessage = availableOptions @@ -46,6 +53,7 @@ export class ZuluDistributor extends JavaBase { `Could not find satisfied version for semver ${version.raw}. ${availableOptionsMessage}` ); } + return resolvedFullVersion; } @@ -102,11 +110,8 @@ export class ZuluDistributor extends JavaBase { core.debug(`Gathering available versions from '${availableVersionsUrl}'`); } - const availableVersions = (await this.http.getJson>(availableVersionsUrl)) - .result; - if (!availableVersions || availableVersions.length === 0) { - throw new Error(`No versions were found using url '${availableVersionsUrl}'`); - } + const availableVersions = + (await this.http.getJson>(availableVersionsUrl)).result ?? []; if (core.isDebug()) { core.startGroup('Print information about available versions'); @@ -149,4 +154,15 @@ export class ZuluDistributor extends JavaBase { return process.platform; } } + + // Azul API returns jdk_version as array of digits like [11, 0, 2, 1] + private convertVersionToSemver(version_array: number[]) { + const mainVersion = version_array.slice(0, 3).join('.'); + if (version_array.length > 3) { + // intentionally ignore more than 4 numbers because it is invalid semver + return `${mainVersion}+${version_array[3]}`; + } + + return mainVersion; + } } diff --git a/src/setup-java.ts b/src/setup-java.ts index f26170adc..c970932eb 100644 --- a/src/setup-java.ts +++ b/src/setup-java.ts @@ -8,7 +8,6 @@ import { JavaInstallerOptions } from './distributors/base-models'; // To-Do need check resolving with 4 numbers // To-Do add check that Java resolves from to toolcache to e2e -// To-Do check sorting for zulu for maxSatisfying async function run() { try { const version = core.getInput(constants.INPUT_JAVA_VERSION);