Cache Gradle distributions downloaded for a particular version (#58)

- Cache is separate from (but similar to) the wrapper distribution cache
- New 'distributions-cache-enabled' flag controls caching of all downloaded distributions
  (including wrapper distributions)
- Deprecated the 'wrapper-cache-enabled' flag for removal in v2
This commit is contained in:
Daz DeBoer 2021-07-08 12:22:48 -06:00 committed by GitHub
parent e4ec586f46
commit 33e91b639d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 36 deletions

View File

@ -122,22 +122,24 @@ jobs:
This action provides 3 levels of caching to help speed up your GitHub Actions: This action provides 3 levels of caching to help speed up your GitHub Actions:
- `wrapper` caches the local [wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) installation, saving time downloading and unpacking Gradle distributions ; - `distributions` caches any downloaded Gradle zips, including any downloaded [wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) versions, saving time downloading Gradle distributions ;
- `dependencies` caches the [dependencies](https://docs.gradle.org/current/userguide/dependency_resolution.html#sub:cache_copy), saving time downloading dependencies ; - `dependencies` caches the [dependencies](https://docs.gradle.org/current/userguide/dependency_resolution.html#sub:cache_copy), saving time downloading dependencies ;
- `configuration` caches the [build configuration](https://docs.gradle.org/nightly/userguide/configuration_cache.html), saving time configuring the build. - `configuration` caches the [build configuration](https://docs.gradle.org/nightly/userguide/configuration_cache.html), saving time configuring the build.
Only the first one, caching the wrapper installation, is enabled by default. Only the first one, caching downloaded distributions, is enabled by default.
Future versions of this action will enable all caching by default. Future versions of this action will enable all caching by default.
You can control which level is enabled as follows: You can control which level is enabled as follows:
```yaml ```yaml
wrapper-cache-enabled: true distributions-cache-enabled: true
dependencies-cache-enabled: true dependencies-cache-enabled: true
configuration-cache-enabled: true configuration-cache-enabled: true
``` ```
The wrapper installation cache is simple and can't be configured further. NOTE: The `wrapper-cache-enabled` flag has been deprecated, replaced by `distributions-cache-enabled` which enables caching for all downloaded distributions, including Gradle wrapper downloads.
The distributions cache is simple and can't be configured further.
The dependencies and configuration cache will compute a cache key in a best effort manner. The dependencies and configuration cache will compute a cache key in a best effort manner.
Keep reading to learn how to better control how they work. Keep reading to learn how to better control how they work.

View File

@ -20,9 +20,13 @@ inputs:
arguments: arguments:
description: Gradle command line arguments, see gradle --help description: Gradle command line arguments, see gradle --help
required: false required: false
distributions-cache-enabled:
description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true'
required: false
wrapper-cache-enabled: wrapper-cache-enabled:
description: Whether caching wrapper installation is enabled or not, default to 'true' description: Whether caching wrapper installation is enabled or not, default to 'true'
required: false required: false
deprecationMessage: Replaced by 'distributions-cache-enabled' which enables caching for all downloaded Gradle distributions
dependencies-cache-enabled: dependencies-cache-enabled:
description: Whether caching dependencies is enabled or not, default to 'false' description: Whether caching dependencies is enabled or not, default to 'false'
required: false required: false

2
dist/main/index.js vendored

File diff suppressed because one or more lines are too long

2
dist/post/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -107,7 +107,16 @@ export function extractGradleWrapperSlugFromDistUri(
} }
function isWrapperCacheDisabled(): boolean { function isWrapperCacheDisabled(): boolean {
return !github.inputBoolean('wrapper-cache-enabled', true) // Check if either 'distributions' or 'wrapper' cache has been disabled
const wrapperCacheEnabled = github.inputBoolean(
'wrapper-cache-enabled',
true
)
const distributionsCacheEnabled = github.inputBoolean(
'distributions-cache-enabled',
true
)
return !wrapperCacheEnabled || !distributionsCacheEnabled
} }
function getCacheKey(wrapperSlug: string): string { function getCacheKey(wrapperSlug: string): string {

View File

@ -3,9 +3,11 @@ import * as os from 'os'
import * as path from 'path' import * as path from 'path'
import * as httpm from '@actions/http-client' import * as httpm from '@actions/http-client'
import * as core from '@actions/core' import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as toolCache from '@actions/tool-cache' import * as toolCache from '@actions/tool-cache'
import * as gradlew from './gradlew' import * as gradlew from './gradlew'
import * as github from './github-utils'
const gradleVersionsBaseUrl = 'https://services.gradle.org/versions' const gradleVersionsBaseUrl = 'https://services.gradle.org/versions'
@ -31,7 +33,7 @@ async function gradleCurrent(): Promise<string> {
const versionInfo = await gradleVersionDeclaration( const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/current` `${gradleVersionsBaseUrl}/current`
) )
return provisionGradle(versionInfo.version, versionInfo.downloadUrl) return provisionGradle(versionInfo)
} }
async function gradleReleaseCandidate(): Promise<string> { async function gradleReleaseCandidate(): Promise<string> {
@ -39,7 +41,7 @@ async function gradleReleaseCandidate(): Promise<string> {
`${gradleVersionsBaseUrl}/release-candidate` `${gradleVersionsBaseUrl}/release-candidate`
) )
if (versionInfo && versionInfo.version && versionInfo.downloadUrl) { if (versionInfo && versionInfo.version && versionInfo.downloadUrl) {
return provisionGradle(versionInfo.version, versionInfo.downloadUrl) return provisionGradle(versionInfo)
} }
core.info('No current release-candidate found, will fallback to current') core.info('No current release-candidate found, will fallback to current')
return gradleCurrent() return gradleCurrent()
@ -49,14 +51,14 @@ async function gradleNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration( const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/nightly` `${gradleVersionsBaseUrl}/nightly`
) )
return provisionGradle(versionInfo.version, versionInfo.downloadUrl) return provisionGradle(versionInfo)
} }
async function gradleReleaseNightly(): Promise<string> { async function gradleReleaseNightly(): Promise<string> {
const versionInfo = await gradleVersionDeclaration( const versionInfo = await gradleVersionDeclaration(
`${gradleVersionsBaseUrl}/release-nightly` `${gradleVersionsBaseUrl}/release-nightly`
) )
return provisionGradle(versionInfo.version, versionInfo.downloadUrl) return provisionGradle(versionInfo)
} }
async function gradle(version: string): Promise<string> { async function gradle(version: string): Promise<string> {
@ -64,7 +66,7 @@ async function gradle(version: string): Promise<string> {
if (!versionInfo) { if (!versionInfo) {
throw new Error(`Gradle version ${version} does not exists`) throw new Error(`Gradle version ${version} does not exists`)
} }
return provisionGradle(versionInfo.version, versionInfo.downloadUrl) return provisionGradle(versionInfo)
} }
async function gradleVersionDeclaration( async function gradleVersionDeclaration(
@ -84,41 +86,79 @@ async function findGradleVersionDeclaration(
}) })
} }
async function provisionGradle(version: string, url: string): Promise<string> { async function provisionGradle(
const cachedInstall: string = toolCache.find('gradle', version) versionInfo: GradleVersionInfo
if (cachedInstall.length > 0) { ): Promise<string> {
const cachedExecutable = executableFrom(cachedInstall) const installsDir = path.join(os.homedir(), 'gradle-installations/installs')
core.info(`Provisioned Gradle executable ${cachedExecutable}`) const installDir = path.join(installsDir, `gradle-${versionInfo.version}`)
return cachedExecutable if (fs.existsSync(installDir)) {
core.info(`Gradle installation already exists at ${installDir}`)
return executableFrom(installDir)
} }
const tmpdir = path.join(os.homedir(), 'gradle-provision-tmpdir') const downloadPath = await downloadAndCacheGradleDistribution(versionInfo)
core.info(`Downloading ${url}`)
const downloadPath = path.join(
tmpdir,
`downloads/gradle-${version}-bin.zip`
)
await toolCache.downloadTool(url, downloadPath)
core.info(
`Downloaded at ${downloadPath}, size ${fs.statSync(downloadPath).size}`
)
const installsDir = path.join(tmpdir, 'installs')
await toolCache.extractZip(downloadPath, installsDir) await toolCache.extractZip(downloadPath, installsDir)
const installDir = path.join(installsDir, `gradle-${version}`) core.info(`Extracted Gradle ${versionInfo.version} to ${installDir}`)
core.info(`Extracted in ${installDir}`)
const executable = executableFrom(installDir) const executable = executableFrom(installDir)
fs.chmodSync(executable, '755') fs.chmodSync(executable, '755')
core.info(`Provisioned Gradle executable ${executable}`) core.info(`Provisioned Gradle executable ${executable}`)
toolCache.cacheDir(installDir, 'gradle', version)
return executable return executable
} }
async function downloadAndCacheGradleDistribution(
versionInfo: GradleVersionInfo
): Promise<string> {
const downloadPath = path.join(
os.homedir(),
`gradle-installations/downloads/gradle-${versionInfo.version}-bin.zip`
)
if (isDistributionsCacheDisabled()) {
await downloadGradleDistribution(versionInfo, downloadPath)
return downloadPath
}
const cacheKey = `gradle-${versionInfo.version}`
const restoreKey = await cache.restoreCache([downloadPath], cacheKey)
if (restoreKey) {
core.info(
`Restored Gradle distribution ${cacheKey} from cache to ${downloadPath}`
)
} else {
core.info(
`Gradle distribution ${versionInfo.version} not found in cache. Will download.`
)
await downloadGradleDistribution(versionInfo, downloadPath)
try {
await cache.saveCache([downloadPath], cacheKey)
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message)
} else {
core.info(`[warning] ${error.message}`)
}
}
}
return downloadPath
}
async function downloadGradleDistribution(
versionInfo: GradleVersionInfo,
downloadPath: string
): Promise<void> {
await toolCache.downloadTool(versionInfo.downloadUrl, downloadPath)
core.info(
`Downloaded ${versionInfo.downloadUrl} to ${downloadPath} (size ${
fs.statSync(downloadPath).size
})`
)
}
function executableFrom(installDir: string): string { function executableFrom(installDir: string): string {
return path.join(installDir, 'bin', `${gradlew.installScriptFilename()}`) return path.join(installDir, 'bin', `${gradlew.installScriptFilename()}`)
} }
@ -139,6 +179,10 @@ async function httpGetString(url: string): Promise<string> {
return response.readBody() return response.readBody()
} }
function isDistributionsCacheDisabled(): boolean {
return !github.inputBoolean('distributions-cache-enabled', true)
}
interface GradleVersionInfo { interface GradleVersionInfo {
version: string version: string
downloadUrl: string downloadUrl: string