From a18c333f3f14249953dab3e186e5e21bf3390f1d Mon Sep 17 00:00:00 2001 From: Dmitry Shibanov Date: Fri, 23 Sep 2022 14:47:30 +0200 Subject: [PATCH] Add versions-manifest.json for Microsoft Build of OpenJDK (#383) --- .../distributors/microsoft-installer.test.ts | 51 ++++----- action.yml | 3 + dist/setup/index.js | 88 ++++++--------- src/distributions/microsoft/installer.ts | 106 +++++++----------- src/distributions/microsoft/models.ts | 10 -- tsconfig.json | 1 + 6 files changed, 99 insertions(+), 160 deletions(-) diff --git a/__tests__/distributors/microsoft-installer.test.ts b/__tests__/distributors/microsoft-installer.test.ts index 9be0f50..c3e560b 100644 --- a/__tests__/distributors/microsoft-installer.test.ts +++ b/__tests__/distributors/microsoft-installer.test.ts @@ -1,7 +1,13 @@ import { MicrosoftDistributions } from '../../src/distributions/microsoft/installer'; +import * as tc from '@actions/tool-cache'; +import data from '../../src/distributions/microsoft/microsoft-openjdk-versions.json'; +import * as httpm from '@actions/http-client'; +import * as core from '@actions/core'; describe('findPackageForDownload', () => { let distribution: MicrosoftDistributions; + let spyGetManifestFromRepo: jest.SpyInstance; + let spyDebug: jest.SpyInstance; beforeEach(() => { distribution = new MicrosoftDistributions({ @@ -10,12 +16,22 @@ describe('findPackageForDownload', () => { packageType: 'jdk', checkLatest: false }); + + spyGetManifestFromRepo = jest.spyOn(httpm.HttpClient.prototype, 'getJson'); + spyGetManifestFromRepo.mockReturnValue({ + result: data, + statusCode: 200, + headers: {} + }); + + spyDebug = jest.spyOn(core, 'debug'); + spyDebug.mockImplementation(() => {}); }); it.each([ [ '17.0.1', - '17.0.1', + '17.0.1+12.1', 'https://aka.ms/download-jdk/microsoft-jdk-17.0.1.12.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], [ @@ -25,12 +41,12 @@ describe('findPackageForDownload', () => { ], [ '16.0.x', - '16.0.2', + '16.0.2+7.1', 'https://aka.ms/download-jdk/microsoft-jdk-16.0.2.7.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], [ '11.0.13', - '11.0.13', + '11.0.13+8.1', 'https://aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-{{OS_TYPE}}-x64.{{ARCHIVE_TYPE}}' ], [ @@ -67,32 +83,3 @@ describe('findPackageForDownload', () => { ); }); }); - -describe('getPlatformOption', () => { - const distributions = new MicrosoftDistributions({ - architecture: 'x64', - version: '11', - packageType: 'jdk', - checkLatest: false - }); - - it.each([ - ['linux', 'tar.gz', 'linux'], - ['darwin', 'tar.gz', 'macos'], - ['win32', 'zip', 'windows'] - ])('os version %s -> %s', (input, expectedArchive, expectedOs) => { - const actual = distributions['getPlatformOption'](input as NodeJS.Platform); - - expect(actual.archive).toEqual(expectedArchive); - expect(actual.os).toEqual(expectedOs); - }); - - it.each(['aix', 'android', 'freebsd', 'openbsd', 'netbsd', 'solaris', 'cygwin'])( - 'not support os version %s', - input => { - expect(() => distributions['getPlatformOption'](input as NodeJS.Platform)).toThrow( - /Platform '\w+' is not supported\. Supported platforms: .+/ - ); - } - ); -}); diff --git a/action.yml b/action.yml index 8a7214b..499eae3 100644 --- a/action.yml +++ b/action.yml @@ -59,6 +59,9 @@ inputs: job-status: description: 'Workaround to pass job status to post job step. This variable is not intended for manual setting' default: ${{ job.status }} + token: + description: Used to pull java versions from setup-java. Since there is a default value, token is typically not supplied by the user. + default: ${{ github.token }} outputs: distribution: description: 'Distribution of Java that has been installed' diff --git a/dist/setup/index.js b/dist/setup/index.js index b40fb34..e19da55 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -104405,7 +104405,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MicrosoftDistributions = void 0; const base_installer_1 = __nccwpck_require__(9741); -const semver_1 = __importDefault(__nccwpck_require__(1383)); const util_1 = __nccwpck_require__(2629); const core = __importStar(__nccwpck_require__(2186)); const tc = __importStar(__nccwpck_require__(7784)); @@ -104439,70 +104438,51 @@ class MicrosoftDistributions extends base_installer_1.JavaBase { if (this.packageType !== 'jdk') { throw new Error('Microsoft Build of OpenJDK provides only the `jdk` package type'); } - const availableVersionsRaw = yield this.getAvailableVersions(); - const opts = this.getPlatformOption(); - const availableVersions = availableVersionsRaw.map(item => ({ - url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${this.architecture}.${opts.archive}`, - version: this.convertVersionToSemver(item) - })); - const satisfiedVersion = availableVersions - .filter(item => 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 manifest = yield this.getAvailableVersions(); + if (!manifest) { + throw new Error('Could not load manifest for Microsoft Build of OpenJDK'); } - return satisfiedVersion; + const foundRelease = yield tc.findFromManifest(range, true, manifest, this.architecture); + if (!foundRelease) { + throw new Error(`Could not find satisfied version for SemVer ${range}. ${manifest + .map(item => item.version) + .join(', ')}`); + } + return { url: foundRelease.files[0].download_url, version: foundRelease.version }; }); } getAvailableVersions() { return __awaiter(this, void 0, void 0, function* () { // TODO get these dynamically! // We will need Microsoft to add an endpoint where we can query for versions. - const jdkVersions = [ - { - version: [17, 0, 3] - }, - { - version: [17, 0, 1, 12, 1] - }, - { - version: [16, 0, 2, 7, 1] - }, - { - version: [11, 0, 15] + const token = core.getInput('token'); + const owner = 'actions'; + const repository = 'setup-java'; + const branch = 'main'; + const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json'; + let releases = null; + const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; + const headers = { + authorization: token, + accept: 'application/vnd.github.VERSION.raw' + }; + let response = null; + try { + response = yield this.http.getJson(fileUrl, headers); + if (!response.result) { + return null; } - ]; - // M1 is only supported for Java 16 & 17 - if (process.platform !== 'darwin' || this.architecture !== 'aarch64') { - jdkVersions.push({ - version: [11, 0, 13, 8, 1] - }); } - return jdkVersions; + catch (err) { + core.debug(`Http request for microsoft-openjdk-versions.json failed with status code: ${response === null || response === void 0 ? void 0 : response.statusCode}`); + return null; + } + if (response.result) { + releases = response.result; + } + return releases; }); } - getPlatformOption(platform = process.platform /* for testing */) { - switch (platform) { - case 'darwin': - return { archive: 'tar.gz', os: 'macos' }; - case 'win32': - return { archive: 'zip', os: 'windows' }; - case 'linux': - return { archive: 'tar.gz', os: 'linux' }; - default: - throw new Error(`Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'`); - } - } - convertVersionToSemver(version) { - const major = version.version[0]; - const minor = version.version[1]; - const patch = version.version[2]; - return `${major}.${minor}.${patch}`; - } } exports.MicrosoftDistributions = MicrosoftDistributions; diff --git a/src/distributions/microsoft/installer.ts b/src/distributions/microsoft/installer.ts index 4ceb428..4a7264d 100644 --- a/src/distributions/microsoft/installer.ts +++ b/src/distributions/microsoft/installer.ts @@ -1,12 +1,12 @@ import { JavaBase } from '../base-installer'; import { JavaDownloadRelease, JavaInstallerOptions, JavaInstallerResults } from '../base-models'; -import semver from 'semver'; -import { extractJdkFile, getDownloadArchiveExtension, isVersionSatisfies } from '../../util'; +import { extractJdkFile, getDownloadArchiveExtension } from '../../util'; import * as core from '@actions/core'; -import { MicrosoftVersion, PlatformOptions } from './models'; import * as tc from '@actions/tool-cache'; +import { OutgoingHttpHeaders } from 'http'; import fs from 'fs'; import path from 'path'; +import { ITypedResponse } from '@actions/http-client/interfaces'; export class MicrosoftDistributions extends JavaBase { constructor(installerOptions: JavaInstallerOptions) { @@ -49,82 +49,60 @@ export class MicrosoftDistributions extends JavaBase { throw new Error('Microsoft Build of OpenJDK provides only the `jdk` package type'); } - const availableVersionsRaw = await this.getAvailableVersions(); + const manifest = await this.getAvailableVersions(); - const opts = this.getPlatformOption(); - const availableVersions = availableVersionsRaw.map(item => ({ - url: `https://aka.ms/download-jdk/microsoft-jdk-${item.version.join('.')}-${opts.os}-${ - this.architecture - }.${opts.archive}`, - version: this.convertVersionToSemver(item) - })); + if (!manifest) { + throw new Error('Could not load manifest for Microsoft Build of OpenJDK'); + } - const satisfiedVersion = availableVersions - .filter(item => isVersionSatisfies(range, item.version)) - .sort((a, b) => -semver.compareBuild(a.version, b.version))[0]; + const foundRelease = await tc.findFromManifest(range, true, manifest, this.architecture); - if (!satisfiedVersion) { - const availableOptions = availableVersions.map(item => item.version).join(', '); - const availableOptionsMessage = availableOptions - ? `\nAvailable versions: ${availableOptions}` - : ''; + if (!foundRelease) { throw new Error( - `Could not find satisfied version for SemVer ${range}. ${availableOptionsMessage}` + `Could not find satisfied version for SemVer ${range}. ${manifest + .map(item => item.version) + .join(', ')}` ); } - return satisfiedVersion; + return { url: foundRelease.files[0].download_url, version: foundRelease.version }; } - private async getAvailableVersions(): Promise { + private async getAvailableVersions(): Promise { // TODO get these dynamically! // We will need Microsoft to add an endpoint where we can query for versions. - const jdkVersions = [ - { - version: [17, 0, 3] - }, - { - version: [17, 0, 1, 12, 1] - }, - { - version: [16, 0, 2, 7, 1] - }, - { - version: [11, 0, 15] + const token = core.getInput('token'); + const owner = 'actions'; + const repository = 'setup-java'; + const branch = 'main'; + const filePath = 'src/distributions/microsoft/microsoft-openjdk-versions.json'; + + let releases: tc.IToolRelease[] | null = null; + const fileUrl = `https://api.github.com/repos/${owner}/${repository}/contents/${filePath}?ref=${branch}`; + + const headers: OutgoingHttpHeaders = { + authorization: token, + accept: 'application/vnd.github.VERSION.raw' + }; + + let response: ITypedResponse | null = null; + + try { + response = await this.http.getJson(fileUrl, headers); + if (!response.result) { + return null; } - ]; - - // M1 is only supported for Java 16 & 17 - if (process.platform !== 'darwin' || this.architecture !== 'aarch64') { - jdkVersions.push({ - version: [11, 0, 13, 8, 1] - }); + } catch (err) { + core.debug( + `Http request for microsoft-openjdk-versions.json failed with status code: ${response?.statusCode}` + ); + return null; } - return jdkVersions; - } - - private getPlatformOption( - platform: NodeJS.Platform = process.platform /* for testing */ - ): PlatformOptions { - switch (platform) { - case 'darwin': - return { archive: 'tar.gz', os: 'macos' }; - case 'win32': - return { archive: 'zip', os: 'windows' }; - case 'linux': - return { archive: 'tar.gz', os: 'linux' }; - default: - throw new Error( - `Platform '${platform}' is not supported. Supported platforms: 'darwin', 'linux', 'win32'` - ); + if (response.result) { + releases = response.result; } - } - private convertVersionToSemver(version: MicrosoftVersion): string { - const major = version.version[0]; - const minor = version.version[1]; - const patch = version.version[2]; - return `${major}.${minor}.${patch}`; + return releases; } } diff --git a/src/distributions/microsoft/models.ts b/src/distributions/microsoft/models.ts index 361c7db..c012bc7 100644 --- a/src/distributions/microsoft/models.ts +++ b/src/distributions/microsoft/models.ts @@ -1,12 +1,2 @@ type OsVersions = 'linux' | 'macos' | 'windows'; type ArchiveType = 'tar.gz' | 'zip'; - -export interface PlatformOptions { - archive: ArchiveType; - os: OsVersions; -} - -export interface MicrosoftVersion { - downloadUrl?: string; - version: Array; -} diff --git a/tsconfig.json b/tsconfig.json index 9ecff86..5621158 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ + "resolveJsonModule": true, // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */