From 98c23c3cba7d425e52459f1c7f8009b05fdfa5e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Jul 2026 02:09:59 +0000 Subject: [PATCH] Add force-download input --- README.md | 2 ++ __tests__/distributors/base-installer.test.ts | 29 +++++++++++++++++++ .../distributors/local-installer.test.ts | 23 +++++++++++++++ action.yml | 4 +++ src/constants.ts | 1 + src/distributions/base-installer.ts | 9 ++++-- src/distributions/base-models.ts | 1 + src/distributions/local/installer.ts | 2 +- src/setup-java.ts | 9 ++++++ 9 files changed, 77 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 461338a9..dba72b63 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ For more details, see the full release notes on the [releases page](https://git - `check-latest`: Setting this option makes the action to check for the latest available version for the version spec. + - `force-download`: Set to `true` to always download Java and replace any matching version in the tool cache. This can help make builds reproducible when a runner image has modified a pre-installed JDK, such as its `cacerts` file. Default value: `false`. + - `set-default`: Set to `false` to install a JDK without making it the default. When `false`, `JAVA_HOME` and `PATH` are not updated, but `JAVA_HOME__` is still set so the JDK remains discoverable. Default value: `true`. See [Installing JDK without setting as default](docs/advanced-usage.md#Installing-JDK-without-setting-as-default) for more details. - `problem-matcher`: Set to `false` to disable Java problem matcher annotations (compiler diagnostics and uncaught exceptions). Default value: `true`. See [Java problem matcher](docs/advanced-usage.md#java-problem-matcher-compiler-annotations) for details and annotation limits. diff --git a/__tests__/distributors/base-installer.test.ts b/__tests__/distributors/base-installer.test.ts index ad3b0afc..457a2b24 100644 --- a/__tests__/distributors/base-installer.test.ts +++ b/__tests__/distributors/base-installer.test.ts @@ -443,6 +443,35 @@ describe('setupJava', () => { ); }); + it('should download java when force-download is enabled, even if the version is cached', async () => { + mockJavaBase = new EmptyJavaBase({ + version: actualJavaVersion, + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + forceDownload: true + }); + const findInToolcache = jest.fn(() => ({ + version: actualJavaVersion, + path: javaPathInstalled + })); + mockJavaBase['findInToolcache'] = findInToolcache; + + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: actualJavaVersion, + path: javaPathInstalled + }); + + expect(findInToolcache).not.toHaveBeenCalled(); + expect(spyCoreInfo).toHaveBeenCalledWith('Trying to download...'); + expect(spyCoreInfo).toHaveBeenCalledWith( + `Java ${actualJavaVersion} was downloaded` + ); + expect(spyCoreInfo).not.toHaveBeenCalledWith( + `Resolved Java ${actualJavaVersion} from tool-cache` + ); + }); + it.each([ [ { diff --git a/__tests__/distributors/local-installer.test.ts b/__tests__/distributors/local-installer.test.ts index 3266f8a8..47997888 100644 --- a/__tests__/distributors/local-installer.test.ts +++ b/__tests__/distributors/local-installer.test.ts @@ -208,6 +208,29 @@ describe('setupJava', () => { ); }); + it('java is unpacked from jdkfile when force-download is enabled', async () => { + const inputs = { + version: actualJavaVersion, + architecture: 'x86', + packageType: 'jdk', + checkLatest: false, + forceDownload: true + }; + + mockJavaBase = new LocalDistribution(inputs, expectedJdkFile); + await expect(mockJavaBase.setupJava()).resolves.toEqual({ + version: actualJavaVersion, + path: javaPath + }); + + expect(spyGetToolcachePath).not.toHaveBeenCalled(); + expect(spyUtilsExtractJdkFile).toHaveBeenCalledWith(expectedJdkFile); + expect(spyTcCacheDir).toHaveBeenCalled(); + expect(spyCoreInfo).not.toHaveBeenCalledWith( + `Resolved Java ${actualJavaVersion} from tool-cache` + ); + }); + it("java is resolved from toolcache, jdkfile doesn't exist", async () => { const inputs = { version: actualJavaVersion, diff --git a/action.yml b/action.yml index 98a95e0d..2412e840 100644 --- a/action.yml +++ b/action.yml @@ -30,6 +30,10 @@ inputs: description: 'Set this option if you want the action to check for the latest available version that satisfies the version spec' required: false default: false + force-download: + description: 'Set this option to always download Java and replace any matching version in the tool cache' + required: false + default: false set-default: description: 'Set this option to false if you want to install a JDK but not make it the default. When false, JAVA_HOME and PATH are not updated, but JAVA_HOME__ is still set.' required: false diff --git a/src/constants.ts b/src/constants.ts index 145d78b4..e1688db4 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -7,6 +7,7 @@ export const INPUT_DISTRIBUTION = 'distribution'; export const INPUT_JDK_FILE = 'jdk-file'; export const INPUT_JDK_FILE_DEPRECATED = 'jdkFile'; export const INPUT_CHECK_LATEST = 'check-latest'; +export const INPUT_FORCE_DOWNLOAD = 'force-download'; export const INPUT_SET_DEFAULT = 'set-default'; export const INPUT_PROBLEM_MATCHER = 'problem-matcher'; export const INPUT_VERIFY_SIGNATURE = 'verify-signature'; diff --git a/src/distributions/base-installer.ts b/src/distributions/base-installer.ts index 07e7c444..c00d21d2 100644 --- a/src/distributions/base-installer.ts +++ b/src/distributions/base-installer.ts @@ -25,6 +25,7 @@ export abstract class JavaBase { protected stable: boolean; protected latest: boolean; protected checkLatest: boolean; + protected forceDownload: boolean; protected setDefault: boolean; protected verifySignature: boolean; protected verifySignaturePublicKey: string | undefined; @@ -46,6 +47,7 @@ export abstract class JavaBase { this.architecture = installerOptions.architecture || os.arch(); this.packageType = installerOptions.packageType; this.checkLatest = installerOptions.checkLatest; + this.forceDownload = installerOptions.forceDownload ?? false; this.setDefault = installerOptions.setDefault !== undefined ? installerOptions.setDefault @@ -68,7 +70,7 @@ export abstract class JavaBase { ); } - let foundJava = this.findInToolcache(); + let foundJava = this.forceDownload ? null : this.findInToolcache(); if (foundJava && !this.checkLatest && !this.latest) { core.info(`Resolved Java ${foundJava.version} from tool-cache`); } else { @@ -91,7 +93,10 @@ export abstract class JavaBase { } const javaRelease = await this.findPackageForDownload(this.version); core.info(`Resolved latest version as ${javaRelease.version}`); - if (foundJava?.version === javaRelease.version) { + if ( + !this.forceDownload && + foundJava?.version === javaRelease.version + ) { core.info(`Resolved Java ${foundJava.version} from tool-cache`); } else { core.info('Trying to download...'); diff --git a/src/distributions/base-models.ts b/src/distributions/base-models.ts index b2ca3f0f..3bfe4bb9 100644 --- a/src/distributions/base-models.ts +++ b/src/distributions/base-models.ts @@ -3,6 +3,7 @@ export interface JavaInstallerOptions { architecture: string; packageType: string; checkLatest: boolean; + forceDownload?: boolean; setDefault?: boolean; verifySignature?: boolean; verifySignaturePublicKey?: string; diff --git a/src/distributions/local/installer.ts b/src/distributions/local/installer.ts index 6447c429..840c19dc 100644 --- a/src/distributions/local/installer.ts +++ b/src/distributions/local/installer.ts @@ -28,7 +28,7 @@ export class LocalDistribution extends JavaBase { ); } - let foundJava = this.findInToolcache(); + let foundJava = this.forceDownload ? null : this.findInToolcache(); if (foundJava) { core.info(`Resolved Java ${foundJava.version} from tool-cache`); diff --git a/src/setup-java.ts b/src/setup-java.ts index 3efaf912..cc0f9370 100644 --- a/src/setup-java.ts +++ b/src/setup-java.ts @@ -29,6 +29,10 @@ async function run() { constants.INPUT_CACHE_DEPENDENCY_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, @@ -83,6 +87,7 @@ async function run() { architecture, packageType, checkLatest, + forceDownload, setDefault, verifySignature, verifySignaturePublicKey, @@ -102,6 +107,7 @@ async function run() { architecture, packageType, checkLatest, + forceDownload, setDefault, verifySignature, verifySignaturePublicKey, @@ -159,6 +165,7 @@ async function installVersion( architecture, packageType, checkLatest, + forceDownload, setDefault, verifySignature, verifySignaturePublicKey, @@ -169,6 +176,7 @@ async function installVersion( architecture, packageType, checkLatest, + forceDownload, setDefault, verifySignature, verifySignaturePublicKey, @@ -212,6 +220,7 @@ interface installerInputsOptions { architecture: string; packageType: string; checkLatest: boolean; + forceDownload: boolean; setDefault: boolean; verifySignature: boolean; verifySignaturePublicKey: string | undefined;