diff --git a/src/cache-base.ts b/src/cache-base.ts index 5265b73..e7a6868 100644 --- a/src/cache-base.ts +++ b/src/cache-base.ts @@ -83,21 +83,16 @@ export abstract class AbstractCache { /** * Restores the cache entry, finding the closest match to the currently running job. - * If the target output already exists, caching will be skipped. */ async restore(listener: CacheListener): Promise { - if (this.cacheOutputExists()) { - core.info(`${this.cacheDescription} already exists. Not restoring from cache.`) - return - } const entryListener = listener.entry(this.cacheDescription) const cacheKey = this.prepareCacheKey() this.debug( `Requesting ${this.cacheDescription} with - key:${cacheKey.key} - restoreKeys:[${cacheKey.restoreKeys}]` + key:${cacheKey.key} + restoreKeys:[${cacheKey.restoreKeys}]` ) const cacheResult = await this.restoreCache(this.getCachePath(), cacheKey.key, cacheKey.restoreKeys) @@ -142,28 +137,17 @@ export abstract class AbstractCache { protected async afterRestore(_listener: CacheListener): Promise {} /** - * Saves the cache entry based on the current cache key, unless: - * - If the cache output existed before restore, then it is not saved. - * - If the cache was restored with the exact key, we cannot overwrite it. + * Saves the cache entry based on the current cache key unless the cache was restored with the exact key, + * in which case we cannot overwrite it. * * If the cache entry was restored with a partial match on a restore key, then * it is saved with the exact key. */ async save(listener: CacheListener): Promise { - if (!this.cacheOutputExists()) { - core.info(`No ${this.cacheDescription} to cache.`) - return - } - // Retrieve the state set in the previous 'restore' step. const cacheKeyFromRestore = core.getState(this.cacheKeyStateKey) const cacheResultFromRestore = core.getState(this.cacheResultStateKey) - if (!cacheKeyFromRestore) { - core.info(`${this.cacheDescription} existed prior to cache restore. Not saving.`) - return - } - if (cacheResultFromRestore && cacheKeyFromRestore === cacheResultFromRestore) { core.info(`Cache hit occurred on the cache key ${cacheKeyFromRestore}, not saving cache.`) return @@ -206,6 +190,5 @@ export abstract class AbstractCache { } } - protected abstract cacheOutputExists(): boolean protected abstract getCachePath(): string[] } diff --git a/src/cache-gradle-user-home.ts b/src/cache-gradle-user-home.ts index 90d996f..709343e 100644 --- a/src/cache-gradle-user-home.ts +++ b/src/cache-gradle-user-home.ts @@ -294,12 +294,6 @@ export class GradleUserHomeCache extends AbstractCache { return path.resolve(os.homedir(), '.gradle') } - protected cacheOutputExists(): boolean { - // Need to check for 'caches' directory to avoid incorrect detection on MacOS agents - const dir = path.resolve(this.gradleUserHome, 'caches') - return fs.existsSync(dir) - } - /** * Determines the paths within Gradle User Home to cache. * By default, this is the 'caches' and 'notifications' directories, diff --git a/src/cache-project-dot-gradle.ts b/src/cache-project-dot-gradle.ts index 57d2a48..97380d2 100644 --- a/src/cache-project-dot-gradle.ts +++ b/src/cache-project-dot-gradle.ts @@ -1,5 +1,4 @@ import path from 'path' -import fs from 'fs' import {AbstractCache} from './cache-base' // TODO: Maybe allow the user to override / tweak this set @@ -17,11 +16,6 @@ export class ProjectDotGradleCache extends AbstractCache { this.rootDir = rootDir } - protected cacheOutputExists(): boolean { - const dir = this.getProjectDotGradleDir() - return fs.existsSync(dir) - } - protected getCachePath(): string[] { const dir = this.getProjectDotGradleDir() return PATHS_TO_CACHE.map(x => path.resolve(dir, x)) diff --git a/src/caches.ts b/src/caches.ts index 2e7255e..062fec9 100644 --- a/src/caches.ts +++ b/src/caches.ts @@ -4,20 +4,20 @@ import {ProjectDotGradleCache} from './cache-project-dot-gradle' import {isCacheDisabled, isCacheReadOnly} from './cache-utils' import {logCachingReport, CacheListener} from './cache-reporting' +const CACHE_RESTORED_VAR = 'GRADLE_BUILD_ACTION_CACHE_RESTORED' const BUILD_ROOT_DIR = 'BUILD_ROOT_DIR' const CACHE_LISTENER = 'CACHE_LISTENER' export async function restore(buildRootDirectory: string): Promise { + if (!shouldRestoreCaches()) { + return + } + const gradleUserHomeCache = new GradleUserHomeCache(buildRootDirectory) const projectDotGradleCache = new ProjectDotGradleCache(buildRootDirectory) gradleUserHomeCache.init() - if (isCacheDisabled()) { - core.info('Cache is disabled: will not restore state from previous builds.') - return - } - await core.group('Restore Gradle state from cache', async () => { core.saveState(BUILD_ROOT_DIR, buildRootDirectory) @@ -38,6 +38,10 @@ export async function restore(buildRootDirectory: string): Promise { } export async function save(): Promise { + if (!shouldSaveCaches()) { + return + } + const cacheListener: CacheListener = CacheListener.rehydrate(core.getState(CACHE_LISTENER)) if (isCacheReadOnly()) { @@ -56,3 +60,35 @@ export async function save(): Promise { logCachingReport(cacheListener) } + +function shouldRestoreCaches(): boolean { + if (isCacheDisabled()) { + core.info('Cache is disabled: will not restore state from previous builds.') + return false + } + + if (process.env[CACHE_RESTORED_VAR]) { + core.info('Cache only restored on first action step.') + return false + } + + // Export var that is detected in all later restore steps + core.exportVariable(CACHE_RESTORED_VAR, true) + // Export state that is detected in corresponding post-action step + core.saveState(CACHE_RESTORED_VAR, true) + return true +} + +function shouldSaveCaches(): boolean { + if (isCacheDisabled()) { + core.info('Cache is disabled: will not save state for later builds.') + return false + } + + if (!core.getState(CACHE_RESTORED_VAR)) { + core.info('Cache will only be saved in final post-action step.') + return false + } + + return true +}