Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add versions-manifest.json for Microsoft Build of OpenJDK #383

Merged
Merged
51 changes: 19 additions & 32 deletions __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({
Expand All @@ -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}}'
],
[
Expand All @@ -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}}'
],
[
Expand Down Expand Up @@ -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: .+/
);
}
);
});
3 changes: 3 additions & 0 deletions action.yml
Expand Up @@ -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'
Expand Down
88 changes: 34 additions & 54 deletions dist/setup/index.js
Expand Up @@ -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));
Expand Down Expand Up @@ -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;

Expand Down
112 changes: 45 additions & 67 deletions 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) {
Expand Down Expand Up @@ -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 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 => isVersionSatisfies(range, item.version))
.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}`
: '';
const manifest = await this.getAvailableVersions();

if (!manifest) {
throw new Error('Could not load manifest for Microsoft Build of OpenJDK');
}

const foundRelease = await tc.findFromManifest(range, true, manifest, this.architecture);

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<MicrosoftVersion[]> {
private async getAvailableVersions(): Promise<tc.IToolRelease[] | null> {
// 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<tc.IToolRelease[]> | null = null;

try {
response = await this.http.getJson<tc.IToolRelease[]>(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;
}
}
10 changes: 0 additions & 10 deletions 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<number>;
}
1 change: 1 addition & 0 deletions tsconfig.json
Expand Up @@ -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. */
Expand Down