Handle early dependency cache failures during Java setup (#1226)

* Handle cache restore promise rejections

Validate dependency cache providers before Java installation and settle cache restore failures immediately while preserving setup error precedence.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Make cache-rejection regression test deterministic

Reject the cache restore only after it has started and while the Java
installation is still pending, instead of relying on event-loop timing.
Verified the test fails against the pre-fix implementation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Validate cache input after required input checks

Move the package-manager validation out of the top of run() so that
missing java-version/java-version-file and toolchain id errors keep
their original precedence. Validation now happens immediately before
the cache restore is started, which still fails fast before any JDK
download.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
This commit is contained in:
Julien Dubois
2026-08-06 23:04:13 -04:00
committed by GitHub
co-authored by Copilot App Bruno Borges
parent 0b0c385478
commit d17a685945
7 changed files with 149 additions and 22 deletions
+4
View File
@@ -138,6 +138,10 @@ function findPackageManager(id: string): PackageManager {
return packageManager;
}
export function validatePackageManager(id: string): void {
findPackageManager(id);
}
function resolveCachePaths(
packageManager: PackageManager,
cachePaths: string[]
+23 -9
View File
@@ -37,7 +37,7 @@ export async function run() {
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<void> | undefined;
let cacheRestore: Promise<PromiseSettledResult<void>> | undefined;
const toolchainConfigurations: ToolchainConfiguration[] = [];
try {
@@ -94,8 +94,9 @@ export async function run() {
toolchainIds
};
await validateCacheInput(cache);
cacheRestore = cache
? startCacheRestore(cache, cacheDependencyPath, cachePath)
? settle(startCacheRestore(cache, cacheDependencyPath, cachePath))
: undefined;
toolchainConfigurations.push(
await installVersion(versionInfo.version, installerInputsOptions)
@@ -120,8 +121,9 @@ export async function run() {
toolchainIds
};
await validateCacheInput(cache);
cacheRestore = cache
? startCacheRestore(cache, cacheDependencyPath, cachePath)
? settle(startCacheRestore(cache, cacheDependencyPath, cachePath))
: undefined;
for (const [index, version] of versions.entries()) {
toolchainConfigurations.push(
@@ -144,12 +146,9 @@ export async function run() {
}
if (cacheRestore) {
try {
await cacheRestore;
} catch (error) {
if (!actionError) {
actionError = error as Error;
}
const cacheResult = await cacheRestore;
if (cacheResult.status === 'rejected' && !actionError) {
actionError = cacheResult.reason as Error;
}
}
@@ -158,6 +157,21 @@ export async function run() {
}
}
async function validateCacheInput(cache: string): Promise<void> {
if (!cache) {
return;
}
const {validatePackageManager} = await import('./cache.js');
validatePackageManager(cache);
}
function settle<T>(promise: Promise<T>): Promise<PromiseSettledResult<T>> {
return promise.then<PromiseFulfilledResult<T>, PromiseRejectedResult>(
value => ({status: 'fulfilled', value}),
reason => ({status: 'rejected', reason})
);
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
run();
} else {