Skip to content

Commit

Permalink
Use gradle wrapper for cache cleanup if available
Browse files Browse the repository at this point in the history
  • Loading branch information
bigdaz committed Jan 24, 2025
1 parent b4009b3 commit 973a4e4
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 42 deletions.
21 changes: 18 additions & 3 deletions sources/src/caching/cache-cleaner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down
21 changes: 6 additions & 15 deletions sources/src/execution/gradle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<GradleExecutable | undefined> {
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<string | null> {
return await which('gradle', {nothrow: true})
}

return undefined
export async function determineGradleVersion(gradleExecutable: string): Promise<string | undefined> {
const output = await exec.getExecOutput(gradleExecutable, ['-v'], {silent: true})
return parseGradleVersionFromOutput(output.stdout)
}

export function parseGradleVersionFromOutput(output: string): string | undefined {
Expand All @@ -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})?))?/

Expand Down
55 changes: 31 additions & 24 deletions sources/src/execution/provision.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -25,16 +25,6 @@ export async function provisionGradle(gradleVersion: string): Promise<string | u
return undefined
}

/**
* Ensure that the Gradle version on PATH is no older than the specified version.
* If the version on PATH is older, install the specified version and add it to the PATH.
* @return Installed Gradle executable or undefined if no version configured.
*/
export async function provisionGradleAtLeast(gradleVersion: string): Promise<string> {
const installedVersion = await installGradleVersionAtLeast(await gradleRelease(gradleVersion))
return addToPath(installedVersion)
}

async function addToPath(executable: string): Promise<string> {
core.addPath(path.dirname(executable))
return executable
Expand Down Expand Up @@ -106,27 +96,44 @@ async function findGradleVersionDeclaration(version: string): Promise<GradleVers

async function installGradleVersion(versionInfo: GradleVersionInfo): Promise<string> {
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<string> {
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<string> {
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))
})
}

Expand Down

0 comments on commit 973a4e4

Please sign in to comment.