Use monolithic cache for Gradle User Home

- Do not restore cache when GUH exists
- Include RUNNER_OS in the cache key
- Do not save cache on exact hit
- Only save cache in the final post action
- Log before saving cache
This commit is contained in:
Daz DeBoer 2021-08-22 20:14:47 -06:00
parent b3afdc78a7
commit c211be411e
No known key found for this signature in database
GPG key ID: DD6B9F0B06683D5D
7 changed files with 247 additions and 22 deletions

View file

@ -0,0 +1,101 @@
import path from 'path'
import fs from 'fs'
import os from 'os'
import * as core from '@actions/core'
import * as cache from '@actions/cache'
import * as github from '@actions/github'
import {truncateArgs} from './cache-utils'
const CACHE_PATH = [
'~/.gradle/caches/*', // All directories in 'caches'
'~/.gradle/notifications/*', // Prevent the re-rendering of first-use message for version
'~/.gradle/wrapper/dists/*/*/*.zip' // Only wrapper zips are required : Gradle will expand these on demand
]
const GUH_CACHE_KEY = 'GUH_CACHE_KEY'
const GUH_CACHE_RESULT = 'GUH_CACHE_RESULT'
export async function restore(): Promise<void> {
if (!isGradleUserHomeCacheEnabled()) return
if (gradleUserHomeExists()) {
core.debug('Gradle User Home already exists. Not restoring from cache.')
return
}
const runnerOs = process.env[`RUNNER_OS`] || ''
const cacheKeyPrefix = `${runnerOs}-gradle|`
const args = truncateArgs(core.getInput('arguments'))
const cacheKeyWithArgs = `${cacheKeyPrefix}${args}|`
const cacheKey = `${cacheKeyWithArgs}${github.context.sha}`
core.saveState(GUH_CACHE_KEY, cacheKey)
const cacheResult = await cache.restoreCache(CACHE_PATH, cacheKey, [
cacheKeyWithArgs,
cacheKeyPrefix
])
if (!cacheResult) {
core.info(
'Gradle User Home cache not found. Will start with empty home.'
)
return
}
core.info(`Gradle User Home restored from cache key: ${cacheResult}`)
return
}
export async function save(): Promise<void> {
if (!isGradleUserHomeCacheEnabled()) return
if (!gradleUserHomeExists()) {
core.debug('No Gradle User Home to cache.')
return
}
const cacheKey = core.getState(GUH_CACHE_KEY)
const cacheResult = core.getState(GUH_CACHE_RESULT)
if (!cacheKey) {
core.info(
'Gradle User Home existed prior to cache restore. Not saving.'
)
return
}
if (cacheResult && cacheKey === cacheResult) {
core.info(
`Cache hit occurred on the cache key ${cacheKey}, not saving cache.`
)
return
}
core.info(`Caching Gradle User Home with cache key: ${cacheKey}`)
try {
await cache.saveCache(CACHE_PATH, 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
}
export function isGradleUserHomeCacheEnabled(): boolean {
return core.getBooleanInput('gradle-user-home-cache-enabled')
}
function gradleUserHomeExists(): boolean {
// Need to check for 'caches' directory to avoid incorrect detection on MacOS agents
const dir = path.resolve(os.homedir(), '.gradle/caches')
return fs.existsSync(dir)
}

View file

@ -1,15 +1,10 @@
import * as exec from '@actions/exec'
import * as cacheDependencies from './cache-dependencies'
import * as cacheConfiguration from './cache-configuration'
export async function execute(
executable: string,
root: string,
argv: string[]
): Promise<BuildResult> {
await cacheDependencies.restoreCachedDependencies(root)
await cacheConfiguration.restoreCachedConfiguration(root)
let publishing = false
let buildScanUrl: string | undefined

View file

@ -2,13 +2,15 @@ import * as core from '@actions/core'
import * as path from 'path'
import {parseArgsStringToArgv} from 'string-argv'
import * as cacheWrapper from './cache-wrapper'
import * as cacheGradleUserHome from './cache-gradle-user-home'
import * as execution from './execution'
import * as gradlew from './gradlew'
import * as provision from './provision'
// Invoked by GitHub Actions
export async function run(): Promise<void> {
await cacheGradleUserHome.restore()
try {
const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || ''
const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory)
@ -47,11 +49,6 @@ async function resolveGradleExecutable(
const gradleExecutable = core.getInput('gradle-executable')
if (gradleExecutable !== '') {
if (gradleExecutable.endsWith(gradlew.wrapperFilename())) {
await cacheWrapper.restoreCachedWrapperDist(
path.resolve(gradleExecutable, '..')
)
}
return path.resolve(workspaceDirectory, gradleExecutable)
}
@ -62,8 +59,6 @@ async function resolveGradleExecutable(
: buildRootDirectory
gradlew.validateGradleWrapper(gradlewDirectory)
await cacheWrapper.restoreCachedWrapperDist(gradlewDirectory)
return path.resolve(gradlewDirectory, gradlew.wrapperFilename())
}

View file

@ -1,16 +1,12 @@
import * as core from '@actions/core'
import * as cacheWrapper from './cache-wrapper'
import * as cacheDependencies from './cache-dependencies'
import * as cacheConfiguration from './cache-configuration'
import * as cacheGradleUserHome from './cache-gradle-user-home'
// Invoked by GitHub Actions
export async function run(): Promise<void> {
if (isCacheReadOnly()) return
await cacheWrapper.cacheWrapperDist()
await cacheDependencies.cacheDependencies()
await cacheConfiguration.cacheConfiguration()
await cacheGradleUserHome.save()
}
function isCacheReadOnly(): boolean {