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

@ -24,6 +24,10 @@ inputs:
description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true' description: Whether caching downloaded Gradle distributions is enabled or not, default to 'true'
required: false required: false
default: true default: true
gradle-user-home-cache-enabled:
description: Whether caching of state in Gradle User Home is enabled, default to 'true'
required: false
default: true
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

139
package-lock.json generated
View file

@ -44,6 +44,17 @@
"@actions/io": "^1.0.1" "@actions/io": "^1.0.1"
} }
}, },
"@actions/github": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-5.0.0.tgz",
"integrity": "sha512-QvE9eAAfEsS+yOOk0cylLBIO/d6WyWIOvsxxzdrPFaud39G6BOkUwScXZn1iBzQzHyu9SBkkLSWlohDWdsasAQ==",
"requires": {
"@actions/http-client": "^1.0.11",
"@octokit/core": "^3.4.0",
"@octokit/plugin-paginate-rest": "^2.13.3",
"@octokit/plugin-rest-endpoint-methods": "^5.1.1"
}
},
"@actions/glob": { "@actions/glob": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.2.0.tgz", "resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.2.0.tgz",
@ -1094,6 +1105,115 @@
"fastq": "^1.6.0" "fastq": "^1.6.0"
} }
}, },
"@octokit/auth-token": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
"requires": {
"@octokit/types": "^6.0.3"
}
},
"@octokit/core": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
"requires": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.0",
"@octokit/request-error": "^2.0.5",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"requires": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
}
}
},
"@octokit/graphql": {
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.4.tgz",
"integrity": "sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==",
"requires": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "9.7.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz",
"integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.15.1.tgz",
"integrity": "sha512-47r52KkhQDkmvUKZqXzA1lKvcyJEfYh3TKAIe5+EzMeyDM3d+/s5v11i2gTk8/n6No6DPi3k5Ind6wtDbo/AEg==",
"requires": {
"@octokit/types": "^6.24.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.8.0.tgz",
"integrity": "sha512-qeLZZLotNkoq+it6F+xahydkkbnvSK0iDjlXFo3jNTB+Ss0qIbYQb9V/soKLMkgGw8Q2sHjY5YEXiA47IVPp4A==",
"requires": {
"@octokit/types": "^6.25.0",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.1.tgz",
"integrity": "sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ==",
"requires": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.1",
"universal-user-agent": "^6.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
}
}
},
"@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"requires": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/types": {
"version": "6.25.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz",
"integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==",
"requires": {
"@octokit/openapi-types": "^9.5.0"
}
},
"@opencensus/web-types": { "@opencensus/web-types": {
"version": "0.0.7", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/@opencensus/web-types/-/web-types-0.0.7.tgz", "resolved": "https://registry.npmjs.org/@opencensus/web-types/-/web-types-0.0.7.tgz",
@ -1807,6 +1927,11 @@
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
}, },
"before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -2202,6 +2327,11 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
}, },
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"detect-newline": { "detect-newline": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@ -5128,7 +5258,6 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -6554,6 +6683,11 @@
"set-value": "^2.0.1" "set-value": "^2.0.1"
} }
}, },
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"universalify": { "universalify": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
@ -6778,8 +6912,7 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"dev": true
}, },
"write-file-atomic": { "write-file-atomic": {
"version": "3.0.3", "version": "3.0.3",

View file

@ -27,6 +27,7 @@
"@actions/cache": "1.0.7", "@actions/cache": "1.0.7",
"@actions/core": "1.4.0", "@actions/core": "1.4.0",
"@actions/exec": "1.1.0", "@actions/exec": "1.1.0",
"@actions/github": "5.0.0",
"@actions/glob": "0.2.0", "@actions/glob": "0.2.0",
"@actions/http-client": "1.0.11", "@actions/http-client": "1.0.11",
"@actions/tool-cache": "1.7.1", "@actions/tool-cache": "1.7.1",

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

View file

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

View file

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