diff --git a/action.yml b/action.yml index 548e89e..5f5511f 100644 --- a/action.yml +++ b/action.yml @@ -28,6 +28,10 @@ inputs: description: Whether caching of state in Gradle User Home is enabled, default to 'true' required: false default: true + project-dot-gradle-cache-enabled: + description: Whether caching of state in project .gradle dir is enabled, default to 'false' + required: false + default: true wrapper-cache-enabled: description: Whether caching wrapper installation is enabled or not, default to 'true' required: false diff --git a/src/cache-gradle-user-home.ts b/src/cache-gradle-user-home.ts index d2381fd..5d15578 100644 --- a/src/cache-gradle-user-home.ts +++ b/src/cache-gradle-user-home.ts @@ -12,8 +12,8 @@ const CACHE_PATH = [ '~/.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' +const CACHE_KEY = 'GUH_CACHE_KEY' +const CACHE_RESULT = 'GUH_CACHE_RESULT' export async function restore(): Promise { if (!isGradleUserHomeCacheEnabled()) return @@ -31,7 +31,7 @@ export async function restore(): Promise { const cacheKey = `${cacheKeyWithArgs}${github.context.sha}` - core.saveState(GUH_CACHE_KEY, cacheKey) + core.saveState(CACHE_KEY, cacheKey) const cacheResult = await cache.restoreCache(CACHE_PATH, cacheKey, [ cacheKeyWithArgs, @@ -57,8 +57,8 @@ export async function save(): Promise { return } - const cacheKey = core.getState(GUH_CACHE_KEY) - const cacheResult = core.getState(GUH_CACHE_RESULT) + const cacheKey = core.getState(CACHE_KEY) + const cacheResult = core.getState(CACHE_RESULT) if (!cacheKey) { core.info( diff --git a/src/cache-project-dot-gradle.ts b/src/cache-project-dot-gradle.ts new file mode 100644 index 0000000..8777e4f --- /dev/null +++ b/src/cache-project-dot-gradle.ts @@ -0,0 +1,109 @@ +import path from 'path' +import fs from 'fs' + +import * as core from '@actions/core' +import * as cache from '@actions/cache' +import * as github from '@actions/github' +import {truncateArgs} from './cache-utils' + +const PATHS_TO_CACHE = [ + 'configuration-cache' // Only configuration-cache is stored at present +] +const CACHE_KEY = 'PROJECT_CACHE_KEY' +const CACHE_RESULT = 'PROJECT_CACHE_RESULT' + +export async function restore(rootDir: string): Promise { + if (!isProjectDotGradleCacheEnabled()) return + + if (projectDotGradleDirExists(rootDir)) { + core.debug( + 'Project .gradle directory already exists. Not restoring from cache.' + ) + return + } + + const runnerOs = process.env[`RUNNER_OS`] || '' + const cacheKeyPrefix = `${runnerOs}-project|` + + const args = truncateArgs(core.getInput('arguments')) + const cacheKeyWithArgs = `${cacheKeyPrefix}${args}|` + + const cacheKey = `${cacheKeyWithArgs}${github.context.sha}` + + core.saveState(CACHE_KEY, cacheKey) + + const cacheResult = await cache.restoreCache( + getCachePath(rootDir), + cacheKey, + [cacheKeyWithArgs, cacheKeyPrefix] + ) + + if (!cacheResult) { + core.info('Project .gradle cache not found. Will start with empty.') + return + } + + core.info(`Project .gradle dir restored from cache key: ${cacheResult}`) + return +} + +export async function save(rootDir: string): Promise { + if (!isProjectDotGradleCacheEnabled()) return + + if (!projectDotGradleDirExists(rootDir)) { + core.debug('No project .gradle dir to cache.') + return + } + + const cacheKey = core.getState(CACHE_KEY) + const cacheResult = core.getState(CACHE_RESULT) + + if (!cacheKey) { + core.info( + 'Project .gradle dir 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 project .gradle dir with cache key: ${cacheKey}`) + try { + await cache.saveCache(getCachePath(rootDir), 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 +} + +function isProjectDotGradleCacheEnabled(): boolean { + return core.getBooleanInput('project-dot-gradle-cache-enabled') +} + +function getCachePath(rootDir: string): string[] { + const dir = getProjectDotGradleDir(rootDir) + return PATHS_TO_CACHE.map(x => path.resolve(dir, x)) +} + +function getProjectDotGradleDir(rootDir: string): string { + core.debug(`Resolving .gradle dir in ${rootDir}`) + return path.resolve(rootDir, '.gradle') +} + +function projectDotGradleDirExists(rootDir: string): boolean { + const dir = getProjectDotGradleDir(rootDir) + core.debug(`Checking for existence of project .gradle dir: ${dir}`) + return fs.existsSync(dir) +} diff --git a/src/caches.ts b/src/caches.ts new file mode 100644 index 0000000..0164168 --- /dev/null +++ b/src/caches.ts @@ -0,0 +1,19 @@ +import * as cacheGradleUserHome from './cache-gradle-user-home' +import * as cacheProjectDotGradle from './cache-project-dot-gradle' +import * as core from '@actions/core' + +const BUILD_ROOT_DIR = 'BUILD_ROOT_DIR' + +export async function restore(buildRootDirectory: string): Promise { + core.saveState(BUILD_ROOT_DIR, buildRootDirectory) + + await cacheGradleUserHome.restore() + await cacheProjectDotGradle.restore(buildRootDirectory) +} + +export async function save(): Promise { + const buildRootDirectory = core.getState(BUILD_ROOT_DIR) + + await cacheGradleUserHome.save() + await cacheProjectDotGradle.save(buildRootDirectory) +} diff --git a/src/main.ts b/src/main.ts index b39ca59..a238619 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,19 +2,19 @@ import * as core from '@actions/core' import * as path from 'path' import {parseArgsStringToArgv} from 'string-argv' -import * as cacheGradleUserHome from './cache-gradle-user-home' +import * as caches from './caches' import * as execution from './execution' import * as gradlew from './gradlew' import * as provision from './provision' // Invoked by GitHub Actions export async function run(): Promise { - await cacheGradleUserHome.restore() + const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || '' + const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory) + + await caches.restore(buildRootDirectory) try { - const workspaceDirectory = process.env[`GITHUB_WORKSPACE`] || '' - const buildRootDirectory = resolveBuildRootDirectory(workspaceDirectory) - const result = await execution.execute( await resolveGradleExecutable( workspaceDirectory, diff --git a/src/post.ts b/src/post.ts index 31476cc..2b4c83a 100644 --- a/src/post.ts +++ b/src/post.ts @@ -1,12 +1,12 @@ import * as core from '@actions/core' -import * as cacheGradleUserHome from './cache-gradle-user-home' +import * as caches from './caches' // Invoked by GitHub Actions export async function run(): Promise { if (isCacheReadOnly()) return - await cacheGradleUserHome.save() + await caches.save() } function isCacheReadOnly(): boolean {