mirror of
https://github.com/actions/setup-java.git
synced 2026-08-30 20:43:23 +01:00
Add Red Hat Build of OpenJDK support (#1241)
* Add Red Hat Build of OpenJDK support Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix Red Hat tests on Windows Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Update compiled Red Hat distribution Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -98,6 +98,10 @@ export async function getJavaDistribution(
|
||||
const {OpenJdkDistribution} = await import('./openjdk/installer.js');
|
||||
return new OpenJdkDistribution(normalizedInstallerOptions);
|
||||
}
|
||||
case JavaDistribution.RedHat: {
|
||||
const {RedHatDistribution} = await import('./redhat/installer.js');
|
||||
return new RedHatDistribution(normalizedInstallerOptions);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ export enum JavaDistribution {
|
||||
GraalVMCommunity = 'graalvm-community',
|
||||
JetBrains = 'jetbrains',
|
||||
Kona = 'kona',
|
||||
OracleOpenJdk = 'oracle-openjdk'
|
||||
OracleOpenJdk = 'oracle-openjdk',
|
||||
RedHat = 'redhat'
|
||||
}
|
||||
|
||||
export const JAVA_PACKAGE_CAPABILITIES = {
|
||||
@@ -50,7 +51,8 @@ export const JAVA_PACKAGE_CAPABILITIES = {
|
||||
'jre+ft'
|
||||
],
|
||||
[JavaDistribution.Kona]: ['jdk'],
|
||||
[JavaDistribution.OracleOpenJdk]: ['jdk']
|
||||
[JavaDistribution.OracleOpenJdk]: ['jdk'],
|
||||
[JavaDistribution.RedHat]: ['jdk', 'jre']
|
||||
} as const satisfies Record<JavaDistribution, readonly string[]>;
|
||||
|
||||
export function validateJavaPackage(
|
||||
|
||||
@@ -145,6 +145,19 @@ export const JAVA_PLATFORM_CAPABILITIES: Record<
|
||||
macos: X64_ARM64,
|
||||
windows: ['x64']
|
||||
}
|
||||
},
|
||||
[JavaDistribution.RedHat]: {
|
||||
platforms: {
|
||||
linux: [
|
||||
'x64',
|
||||
{architecture: 'aarch64', versionRange: '<12'},
|
||||
{architecture: 'ppc64le', versionRange: '<12'}
|
||||
],
|
||||
windows: [
|
||||
{architecture: 'x64', versionRange: '<22'},
|
||||
{architecture: 'x86', versionRange: '<11'}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
180
src/distributions/redhat/installer.ts
Normal file
180
src/distributions/redhat/installer.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import * as core from '@actions/core';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
import {
|
||||
cacheJdkDir,
|
||||
extractJdkFile,
|
||||
isVersionSatisfies,
|
||||
renameWinArchive
|
||||
} from '../../util.js';
|
||||
import {JavaBase} from '../base-installer.js';
|
||||
import {
|
||||
JavaDownloadRelease,
|
||||
JavaInstallerOptions,
|
||||
JavaInstallerResults
|
||||
} from '../base-models.js';
|
||||
import {
|
||||
IDiscoPackage,
|
||||
IDiscoPackageDetailsResponse,
|
||||
IDiscoPackageListResponse
|
||||
} from './models.js';
|
||||
import {isAlpineLinux} from '../platform-types.js';
|
||||
|
||||
const DISCO_API_URL = 'https://api.foojay.io/disco/v3.0';
|
||||
|
||||
export class RedHatDistribution extends JavaBase {
|
||||
constructor(installerOptions: JavaInstallerOptions) {
|
||||
super('RedHat', installerOptions);
|
||||
}
|
||||
|
||||
protected async findPackageForDownload(
|
||||
range: string
|
||||
): Promise<JavaDownloadRelease> {
|
||||
if (!this.stable) {
|
||||
throw new Error('Early access versions are not supported');
|
||||
}
|
||||
|
||||
const availablePackages = await this.getAvailablePackages();
|
||||
const normalizedPackages = availablePackages
|
||||
.map(item => ({
|
||||
item,
|
||||
version: this.normalizeDiscoVersion(item.java_version)
|
||||
}))
|
||||
.filter(
|
||||
(item): item is {item: IDiscoPackage; version: string} =>
|
||||
item.version !== null
|
||||
)
|
||||
.sort((left, right) => -semver.compareBuild(left.version, right.version));
|
||||
|
||||
const selectedPackage = normalizedPackages.find(item =>
|
||||
isVersionSatisfies(range, item.version)
|
||||
);
|
||||
if (!selectedPackage) {
|
||||
throw this.createVersionNotFoundError(
|
||||
range,
|
||||
normalizedPackages.map(item => item.version),
|
||||
`Operating system: ${this.getOperatingSystem()}`
|
||||
);
|
||||
}
|
||||
|
||||
const detailsUrl = `${DISCO_API_URL}/ids/${selectedPackage.item.id}`;
|
||||
const response =
|
||||
await this.http.getJson<IDiscoPackageDetailsResponse>(detailsUrl);
|
||||
const details = response.result?.result?.[0];
|
||||
if (!details?.direct_download_uri) {
|
||||
throw new Error(
|
||||
`Foojay Disco returned no direct Red Hat download URL for package '${selectedPackage.item.id}'.`
|
||||
);
|
||||
}
|
||||
const checksum = details.checksum?.trim();
|
||||
if (details.checksum_type?.toLowerCase() !== 'sha256' || !checksum) {
|
||||
throw new Error(
|
||||
`Foojay Disco returned no SHA-256 checksum for Red Hat package '${selectedPackage.item.id}'.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
version: selectedPackage.version,
|
||||
url: details.direct_download_uri,
|
||||
checksum: {
|
||||
algorithm: 'sha256',
|
||||
value: checksum,
|
||||
source: detailsUrl
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected async downloadTool(
|
||||
javaRelease: JavaDownloadRelease
|
||||
): Promise<JavaInstallerResults> {
|
||||
core.info(
|
||||
`Downloading Java ${javaRelease.version} (${this.distribution}) from ${javaRelease.url} ...`
|
||||
);
|
||||
let javaArchivePath = await this.downloadAndVerify(javaRelease);
|
||||
|
||||
core.info('Extracting Java archive...');
|
||||
const archiveType = this.getArchiveType();
|
||||
if (archiveType === 'zip') {
|
||||
javaArchivePath = renameWinArchive(javaArchivePath);
|
||||
}
|
||||
const extractedJavaPath = await extractJdkFile(
|
||||
javaArchivePath,
|
||||
archiveType
|
||||
);
|
||||
const archiveName = fs.readdirSync(extractedJavaPath)[0];
|
||||
if (!archiveName) {
|
||||
throw new Error(
|
||||
`The Red Hat archive for Java ${javaRelease.version} was empty.`
|
||||
);
|
||||
}
|
||||
const archivePath = path.join(extractedJavaPath, archiveName);
|
||||
const javaPath = await cacheJdkDir(
|
||||
archivePath,
|
||||
this.toolcacheFolderName,
|
||||
this.getToolcacheVersionName(javaRelease.version),
|
||||
this.architecture
|
||||
);
|
||||
|
||||
return {version: javaRelease.version, path: javaPath};
|
||||
}
|
||||
|
||||
private async getAvailablePackages(): Promise<IDiscoPackage[]> {
|
||||
const operatingSystem = this.getOperatingSystem();
|
||||
const archiveType = this.getArchiveType();
|
||||
const query = new URLSearchParams({
|
||||
distro: 'redhat',
|
||||
release_status: 'ga',
|
||||
operating_system: operatingSystem,
|
||||
architecture: this.distributionArchitecture(),
|
||||
package_type: this.packageType,
|
||||
archive_type: archiveType,
|
||||
directly_downloadable: 'true'
|
||||
});
|
||||
const url = `${DISCO_API_URL}/packages?${query.toString()}`;
|
||||
const response = await this.http.getJson<IDiscoPackageListResponse>(url);
|
||||
const packages = response.result?.result;
|
||||
if (!Array.isArray(packages)) {
|
||||
throw new Error(
|
||||
`Could not fetch Red Hat package metadata from Foojay Disco: ${url}`
|
||||
);
|
||||
}
|
||||
|
||||
return packages.filter(
|
||||
item =>
|
||||
item.distribution === 'redhat' &&
|
||||
item.release_status === 'ga' &&
|
||||
item.operating_system === operatingSystem &&
|
||||
item.architecture === this.distributionArchitecture() &&
|
||||
item.package_type === this.packageType &&
|
||||
item.archive_type === archiveType &&
|
||||
item.directly_downloadable
|
||||
);
|
||||
}
|
||||
|
||||
private getOperatingSystem(alpine = isAlpineLinux()): string {
|
||||
if (alpine) {
|
||||
throw new Error(
|
||||
"Distribution 'redhat' does not support Alpine Linux because Red Hat portable archives require glibc."
|
||||
);
|
||||
}
|
||||
return process.platform === 'win32' ? 'windows' : 'linux';
|
||||
}
|
||||
|
||||
private getArchiveType(): string {
|
||||
return process.platform === 'win32' ? 'zip' : 'tar.xz';
|
||||
}
|
||||
|
||||
private normalizeDiscoVersion(version: string): string | null {
|
||||
let normalizedVersion = version.trim();
|
||||
if (/^\d+\+\d+$/.test(normalizedVersion)) {
|
||||
normalizedVersion = normalizedVersion.replace('+', '.0.0+');
|
||||
} else if (/^\d+$/.test(normalizedVersion)) {
|
||||
normalizedVersion = `${normalizedVersion}.0.0`;
|
||||
} else if (/^\d+\.\d+$/.test(normalizedVersion)) {
|
||||
normalizedVersion = `${normalizedVersion}.0`;
|
||||
}
|
||||
|
||||
return semver.valid(normalizedVersion) ? normalizedVersion : null;
|
||||
}
|
||||
}
|
||||
28
src/distributions/redhat/models.ts
Normal file
28
src/distributions/redhat/models.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export interface IDiscoPackage {
|
||||
id: string;
|
||||
archive_type: string;
|
||||
distribution: string;
|
||||
java_version: string;
|
||||
release_status: string;
|
||||
operating_system: string;
|
||||
architecture: string;
|
||||
package_type: string;
|
||||
directly_downloadable: boolean;
|
||||
}
|
||||
|
||||
export interface IDiscoPackageListResponse {
|
||||
result: IDiscoPackage[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IDiscoPackageDetails {
|
||||
filename: string;
|
||||
direct_download_uri: string;
|
||||
checksum: string;
|
||||
checksum_type: string;
|
||||
}
|
||||
|
||||
export interface IDiscoPackageDetailsResponse {
|
||||
result: IDiscoPackageDetails[];
|
||||
message: string;
|
||||
}
|
||||
@@ -59,7 +59,9 @@ export async function extractJdkFile(toolPath: string, extension?: string) {
|
||||
if (!extension) {
|
||||
extension = toolPath.endsWith('.tar.gz')
|
||||
? 'tar.gz'
|
||||
: path.extname(toolPath);
|
||||
: toolPath.endsWith('.tar.xz')
|
||||
? 'tar.xz'
|
||||
: path.extname(toolPath);
|
||||
if (extension.startsWith('.')) {
|
||||
extension = extension.substring(1);
|
||||
}
|
||||
@@ -68,6 +70,8 @@ export async function extractJdkFile(toolPath: string, extension?: string) {
|
||||
switch (extension) {
|
||||
case 'tar.gz':
|
||||
return await extractTarGz(toolPath);
|
||||
case 'tar.xz':
|
||||
return await tc.extractTar(toolPath, undefined, 'xJ');
|
||||
case 'tar':
|
||||
return await tc.extractTar(toolPath);
|
||||
case 'zip':
|
||||
|
||||
Reference in New Issue
Block a user