import fs from 'fs'; import * as core from '@actions/core'; import { getBooleanInput, getVersionFromFileContent, isJdkCacheEnabled } from './util.js'; import * as constants from './constants.js'; import * as path from 'path'; import {fileURLToPath} from 'url'; import {getJavaDistribution} from './distributions/distribution-factory.js'; import {JavaInstallerOptions} from './distributions/base-models.js'; import {configureProblemMatcher} from './problem-matcher.js'; import {validateToolchainIds} from './toolchain-ids.js'; export async function run() { const versions = core.getMultilineInput(constants.INPUT_JAVA_VERSION); let distributionName = core.getInput(constants.INPUT_DISTRIBUTION); const versionFile = core.getInput(constants.INPUT_JAVA_VERSION_FILE); const architecture = core.getInput(constants.INPUT_ARCHITECTURE); const packageType = core.getInput(constants.INPUT_JAVA_PACKAGE); const jdkFile = getJdkFileInput(); const cache = core.getInput(constants.INPUT_CACHE); const cacheJdk = isJdkCacheEnabled(cache); const cacheDependencyPath = core.getInput( constants.INPUT_CACHE_DEPENDENCY_PATH ); const cachePath = core.getMultilineInput(constants.INPUT_CACHE_PATH); const checkLatest = getBooleanInput(constants.INPUT_CHECK_LATEST, false); const forceDownload = getBooleanInput(constants.INPUT_FORCE_DOWNLOAD, false); const setDefault = getBooleanInput(constants.INPUT_SET_DEFAULT, true); const verifySignature = getBooleanInput( constants.INPUT_VERIFY_SIGNATURE, false ); const verifySignaturePublicKey = core.getInput(constants.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY) || undefined; const toolchainIds = core.getMultilineInput(constants.INPUT_MVN_TOOLCHAIN_ID); let actionError: Error | undefined; let cacheRestore: Promise> | undefined; const toolchainConfigurations: ToolchainConfiguration[] = []; try { core.startGroup('Installed distributions'); if (!versions.length && !versionFile) { throw new Error('java-version or java-version-file input expected'); } validateToolchainIds(versions, versionFile, toolchainIds); if (!versions.length) { core.debug( 'java-version input is empty, looking for java-version-file input' ); const content = fs.readFileSync(versionFile).toString().trim(); const versionInfo = getVersionFromFileContent( content, distributionName, versionFile ); core.debug(`Parsed version from file '${versionInfo?.version}'`); if (!versionInfo) { throw new Error( `No supported version was found in file ${versionFile}` ); } // Use distribution from file if available, otherwise use the input if (versionInfo.distribution) { core.info( `Using distribution '${versionInfo.distribution}' from ${versionFile}` ); distributionName = versionInfo.distribution; } else if (!distributionName) { throw new Error( 'distribution input is required when not specified in the version file' ); } const installerInputsOptions: installerInputsOptions = { architecture, packageType, checkLatest, forceDownload, cacheJdk, setDefault, verifySignature, verifySignaturePublicKey, distributionName, jdkFile, toolchainIds }; await validateCacheInput(cache); cacheRestore = cache ? settle(startCacheRestore(cache, cacheDependencyPath, cachePath)) : undefined; toolchainConfigurations.push( await installVersion(versionInfo.version, installerInputsOptions) ); } else { // When using java-version input, distribution is still required if (!distributionName) { throw new Error('distribution input is required'); } const installerInputsOptions: installerInputsOptions = { architecture, packageType, checkLatest, forceDownload, cacheJdk, setDefault, verifySignature, verifySignaturePublicKey, distributionName, jdkFile, toolchainIds }; await validateCacheInput(cache); cacheRestore = cache ? settle(startCacheRestore(cache, cacheDependencyPath, cachePath)) : undefined; for (const [index, version] of versions.entries()) { toolchainConfigurations.push( await installVersion(version, installerInputsOptions, index) ); } } core.endGroup(); const matchersPath = path.join( path.dirname(fileURLToPath(import.meta.url)), '..', '..', '.github' ); configureProblemMatcher(path.join(matchersPath, 'java.json')); await configureMaven(toolchainConfigurations); } catch (error) { actionError = error as Error; } if (cacheRestore) { const cacheResult = await cacheRestore; if (cacheResult.status === 'rejected' && !actionError) { actionError = cacheResult.reason as Error; } } if (actionError) { core.setFailed(actionError.message); } } async function validateCacheInput(cache: string): Promise { if (!cache) { return; } const {validatePackageManager} = await import('./cache.js'); validatePackageManager(cache); } function settle(promise: Promise): Promise> { return promise.then, PromiseRejectedResult>( value => ({status: 'fulfilled', value}), reason => ({status: 'rejected', reason}) ); } if (process.argv[1] === fileURLToPath(import.meta.url)) { run(); } else { // https://nodejs.org/api/modules.html#modules_accessing_the_main_module core.info('the script is loaded as a module, so skipping the execution'); } function getJdkFileInput(): string { const jdkFile = core.getInput(constants.INPUT_JDK_FILE); const deprecatedJdkFile = core.getInput(constants.INPUT_JDK_FILE_DEPRECATED); if (deprecatedJdkFile) { core.warning( `The '${constants.INPUT_JDK_FILE_DEPRECATED}' input is deprecated and may be removed in a future release. Please use '${constants.INPUT_JDK_FILE}' instead.` ); } return jdkFile || deprecatedJdkFile; } async function installVersion( version: string, options: installerInputsOptions, toolchainId = 0 ): Promise { const { distributionName, jdkFile, architecture, packageType, checkLatest, forceDownload, cacheJdk, setDefault, verifySignature, verifySignaturePublicKey, toolchainIds } = options; const installerOptions: JavaInstallerOptions = { architecture, packageType, checkLatest, forceDownload, cacheJdk, setDefault, verifySignature, verifySignaturePublicKey, version }; const distribution = await getJavaDistribution( distributionName, installerOptions, jdkFile ); if (!distribution) { throw new Error( `No supported distribution was found for input ${distributionName}` ); } const result = await distribution.setupJava(); // When the `latest` alias is used, the literal input isn't a real version, so // pass the resolved version to the toolchains configuration instead. const isLatest = version.trim().toLowerCase() === 'latest'; const toolchainVersion = isLatest ? result.version : version; core.info(''); core.info('Java configuration:'); core.info(` Distribution: ${distributionName}`); core.info(` Version: ${result.version}`); core.info(` Path: ${result.path}`); core.info(''); return { version: toolchainVersion, distributionName, path: result.path, toolchainId: toolchainIds[toolchainId] }; } interface installerInputsOptions { architecture: string; packageType: string; checkLatest: boolean; forceDownload: boolean; cacheJdk: boolean; setDefault: boolean; verifySignature: boolean; verifySignaturePublicKey: string | undefined; distributionName: string; jdkFile: string; toolchainIds: Array; } interface ToolchainConfiguration { version: string; distributionName: string; path: string; toolchainId?: string; } async function configureMaven( toolchainConfigurations: ToolchainConfiguration[] ): Promise { const authentication = import('./auth.js').then(auth => auth.configureAuthentication() ); const toolchains = configureInstalledToolchains(toolchainConfigurations); const results = await Promise.allSettled([authentication, toolchains]); const failure = results.find( (result): result is PromiseRejectedResult => result.status === 'rejected' ); if (failure) { throw failure.reason; } const {configureMavenArgs} = await import('./maven-args.js'); configureMavenArgs(); } async function configureInstalledToolchains( toolchainConfigurations: ToolchainConfiguration[] ): Promise { const toolchains = await import('./toolchains.js'); for (const configuration of toolchainConfigurations) { await toolchains.configureToolchains( configuration.version, configuration.distributionName, configuration.path, configuration.toolchainId ); } } async function startCacheRestore( cache: string, cacheDependencyPath: string, cachePath: string[] ): Promise { const {isCacheFeatureAvailable} = await import('./cache-feature.js'); if (!isCacheFeatureAvailable()) { return; } const {restore} = await import('./cache.js'); await restore(cache, cacheDependencyPath, cachePath); }