From 973a4e4afe9a8756213ac30c1d5c31ee5761aca9 Mon Sep 17 00:00:00 2001 From: daz Date: Fri, 24 Jan 2025 07:19:28 -0700 Subject: [PATCH] Use gradle wrapper for cache cleanup if available --- sources/src/caching/cache-cleaner.ts | 21 +++++++++-- sources/src/execution/gradle.ts | 21 +++-------- sources/src/execution/provision.ts | 55 ++++++++++++++++------------ 3 files changed, 55 insertions(+), 42 deletions(-) diff --git a/sources/src/caching/cache-cleaner.ts b/sources/src/caching/cache-cleaner.ts index 91ed908..5b25931 100644 --- a/sources/src/caching/cache-cleaner.ts +++ b/sources/src/caching/cache-cleaner.ts @@ -4,8 +4,9 @@ import * as exec from '@actions/exec' import fs from 'fs' import path from 'path' import * as provisioner from '../execution/provision' -import {BuildResults} from '../build-results' +import {BuildResult, BuildResults} from '../build-results' import {versionIsAtLeast} from '../execution/gradle' +import {gradleWrapperScript} from '../execution/gradlew' export class CacheCleaner { private readonly gradleUserHome: string @@ -38,7 +39,11 @@ export class CacheCleaner { const preferredVersion = buildResults.highestGradleVersion() if (preferredVersion && versionIsAtLeast(preferredVersion, '8.11')) { try { - return await provisioner.provisionGradleAtLeast(preferredVersion) + const wrapperScripts = buildResults.results + .map(result => this.findGradleWrapperScript(result)) + .filter(Boolean) as string[] + + return await provisioner.provisionGradleWithVersionAtLeast(preferredVersion, wrapperScripts) } catch (e) { // Ignore the case where the preferred version cannot be located in https://services.gradle.org/versions/all. // This can happen for snapshot Gradle versions. @@ -49,7 +54,17 @@ export class CacheCleaner { } // Fallback to the minimum version required for cache-cleanup - return await provisioner.provisionGradleAtLeast('8.11') + return await provisioner.provisionGradleWithVersionAtLeast('8.11') + } + + private findGradleWrapperScript(result: BuildResult): string | null { + try { + const wrapperScript = gradleWrapperScript(result.rootProjectDir) + return path.resolve(result.rootProjectDir, wrapperScript) + } catch (error) { + core.debug(`No Gradle Wrapper found for ${result.rootProjectName}: ${error}`) + return null + } } // Visible for testing diff --git a/sources/src/execution/gradle.ts b/sources/src/execution/gradle.ts index 86f72db..425f3d9 100644 --- a/sources/src/execution/gradle.ts +++ b/sources/src/execution/gradle.ts @@ -76,15 +76,13 @@ export function versionIsAtLeast(actualVersion: string, requiredVersion: string) return true // Actual has no stage part or snapshot part, so it cannot be older than required. } -export async function findGradleVersionOnPath(): Promise { - const gradleExecutable = await which('gradle', {nothrow: true}) - if (gradleExecutable) { - const output = await exec.getExecOutput(gradleExecutable, ['-v'], {silent: true}) - const version = parseGradleVersionFromOutput(output.stdout) - return version ? new GradleExecutable(version, gradleExecutable) : undefined - } +export async function findGradleExecutableOnPath(): Promise { + return await which('gradle', {nothrow: true}) +} - return undefined +export async function determineGradleVersion(gradleExecutable: string): Promise { + const output = await exec.getExecOutput(gradleExecutable, ['-v'], {silent: true}) + return parseGradleVersionFromOutput(output.stdout) } export function parseGradleVersionFromOutput(output: string): string | undefined { @@ -93,13 +91,6 @@ export function parseGradleVersionFromOutput(output: string): string | undefined return versionString } -class GradleExecutable { - constructor( - readonly version: string, - readonly executable: string - ) {} -} - class GradleVersion { static PATTERN = /((\d+)(\.\d+)+)(-([a-z]+)-(\w+))?(-(SNAPSHOT|\d{14}([-+]\d{4})?))?/ diff --git a/sources/src/execution/provision.ts b/sources/src/execution/provision.ts index a3404fb..40402a1 100644 --- a/sources/src/execution/provision.ts +++ b/sources/src/execution/provision.ts @@ -6,7 +6,7 @@ import * as core from '@actions/core' import * as cache from '@actions/cache' import * as toolCache from '@actions/tool-cache' -import {findGradleVersionOnPath, versionIsAtLeast} from './gradle' +import {determineGradleVersion, findGradleExecutableOnPath, versionIsAtLeast} from './gradle' import * as gradlew from './gradlew' import {handleCacheFailure} from '../caching/cache-utils' import {CacheConfig} from '../configuration' @@ -25,16 +25,6 @@ export async function provisionGradle(gradleVersion: string): Promise { - const installedVersion = await installGradleVersionAtLeast(await gradleRelease(gradleVersion)) - return addToPath(installedVersion) -} - async function addToPath(executable: string): Promise { core.addPath(path.dirname(executable)) return executable @@ -106,27 +96,44 @@ async function findGradleVersionDeclaration(version: string): Promise { return core.group(`Provision Gradle ${versionInfo.version}`, async () => { - const gradleOnPath = await findGradleVersionOnPath() - if (gradleOnPath?.version === versionInfo.version) { - core.info(`Gradle version ${versionInfo.version} is already available on PATH. Not installing.`) - return gradleOnPath.executable + const gradleOnPath = await findGradleExecutableOnPath() + if (gradleOnPath) { + const gradleOnPathVersion = await determineGradleVersion(gradleOnPath) + if (gradleOnPathVersion === versionInfo.version) { + core.info(`Gradle version ${versionInfo.version} is already available on PATH. Not installing.`) + return gradleOnPath + } } return locateGradleAndDownloadIfRequired(versionInfo) }) } -async function installGradleVersionAtLeast(versionInfo: GradleVersionInfo): Promise { - return core.group(`Provision Gradle >= ${versionInfo.version}`, async () => { - const gradleOnPath = await findGradleVersionOnPath() - if (gradleOnPath && versionIsAtLeast(gradleOnPath.version, versionInfo.version)) { - core.info( - `Gradle version ${gradleOnPath.version} is available on PATH and >= ${versionInfo.version}. Not installing.` - ) - return gradleOnPath.executable +/** + * Find (or install) a Gradle executable that meets the specified version requirement. + * The Gradle version on PATH and all candidates are first checked for version compatibility. + * If no existing Gradle version meets the requirement, the required version is installed. + * @return Gradle executable with at least the required version. + */ +export async function provisionGradleWithVersionAtLeast( + minimumVersion: string, + candidates: string[] = [] +): Promise { + const gradleOnPath = await findGradleExecutableOnPath() + const allCandidates = gradleOnPath ? [gradleOnPath, ...candidates] : candidates + + return core.group(`Provision Gradle >= ${minimumVersion}`, async () => { + for (const candidate of allCandidates) { + const candidateVersion = await determineGradleVersion(candidate) + if (candidateVersion && versionIsAtLeast(candidateVersion, minimumVersion)) { + core.info( + `Gradle version ${candidateVersion} is available at ${candidate} and >= ${minimumVersion}. Not installing.` + ) + return candidate + } } - return locateGradleAndDownloadIfRequired(versionInfo) + return locateGradleAndDownloadIfRequired(await gradleRelease(minimumVersion)) }) }