From d2c83d86688f2be29fdae59d8d4d9fb0d20edcb4 Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 27 Feb 2023 19:27:47 +0100 Subject: [PATCH] Simplifies cache fallback + add timed invalidation --- README.md | 2 ++ __tests__/cache-restore.test.ts | 10 +++++----- action.yml | 2 ++ src/cache-restore.ts | 13 ++++++++++--- src/main.ts | 3 ++- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8b405f9ea..0124168e0 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ The action has a built-in functionality for caching and restoring dependencies. The action defaults to search for the dependency file (`package-lock.json` or `yarn.lock`) in the repository root, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases when multiple dependency files are used, or they are located in different subdirectories. +Use `cache-invalidate-after-days` to change the default fallback cache invalidation of every 120 days. Set to 0 to deactivate. + See the examples of using cache for `yarn` / `pnpm` and `cache-dependency-path` input in the [Advanced usage](docs/advanced-usage.md#caching-packages-dependencies) guide. **Caching npm dependencies:** diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts index aa678bdc1..f0c56958d 100644 --- a/__tests__/cache-restore.test.ts +++ b/__tests__/cache-restore.test.ts @@ -132,13 +132,13 @@ describe('cache-restore', () => { } }); - await restoreCache(packageManager); + await restoreCache(packageManager, undefined, '0'); expect(hashFilesSpy).toHaveBeenCalled(); expect(infoSpy).toHaveBeenCalledWith( - `Cache restored from key: ${platform}-setup-node-${packageManager}-${fileHash}` + `Cache restored from key: ${platform}-0-setup-node-${packageManager}-${fileHash}` ); expect(infoSpy).not.toHaveBeenCalledWith( - `Cache not found for input keys: ${platform}-setup-node-${packageManager}-${fileHash}, ${platform}-setup-node-${packageManager}-, ${platform}-setup-node-` + `Cache not found for input keys: ${platform}-0-setup-node-${packageManager}-${fileHash}, ${platform}-0-setup-node-${packageManager}-` ); } ); @@ -162,10 +162,10 @@ describe('cache-restore', () => { }); restoreCacheSpy.mockImplementationOnce(() => undefined); - await restoreCache(packageManager); + await restoreCache(packageManager, undefined, '0'); expect(hashFilesSpy).toHaveBeenCalled(); expect(infoSpy).toHaveBeenCalledWith( - `Cache not found for input keys: ${platform}-setup-node-${packageManager}-${fileHash}, ${platform}-setup-node-${packageManager}-, ${platform}-setup-node-` + `Cache not found for input keys: ${platform}-0-setup-node-${packageManager}-${fileHash}, ${platform}-0-setup-node-${packageManager}-` ); } ); diff --git a/action.yml b/action.yml index 66daef0cf..2cab6d74f 100644 --- a/action.yml +++ b/action.yml @@ -23,6 +23,8 @@ inputs: description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm' cache-dependency-path: description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.' + cache-invalidate-after-days: + description: 'Used to control how often the fallback cache is invalidated automatically.' # TODO: add input to control forcing to pull from cloud or dist. # escape valve for someone having issues or needing the absolute latest which isn't cached yet # Deprecated option, do not use. Will not be supported after October 1, 2019 diff --git a/src/cache-restore.ts b/src/cache-restore.ts index ce610737a..de0a883ad 100644 --- a/src/cache-restore.ts +++ b/src/cache-restore.ts @@ -12,7 +12,8 @@ import { export const restoreCache = async ( packageManager: string, - cacheDependencyPath?: string + cacheDependencyPath?: string, + cacheInvalidateAfterDays?: string ) => { const packageManagerInfo = await getPackageManagerInfo(packageManager); if (!packageManagerInfo) { @@ -35,9 +36,15 @@ export const restoreCache = async ( 'Some specified paths were not resolved, unable to cache dependencies.' ); } - const keyPrefix = `${platform}-setup-node-`; + const numericCacheInvalidateAfterDays = cacheInvalidateAfterDays && cacheInvalidateAfterDays === '0' + ? 0 + : (parseInt(cacheInvalidateAfterDays || '', 10) || 120) + const timedInvalidationPrefix = numericCacheInvalidateAfterDays + ? Math.floor(Date.now() / (1000 * 60 * 60 * 24 * numericCacheInvalidateAfterDays)) % 1000 // % 1000 to get a rolling prefix between 0 and 999 rather than a possibly infinitely large + : 0; + const keyPrefix = `${platform}-${timedInvalidationPrefix}-setup-node-`; const primaryKey = `${keyPrefix}${packageManager}-${fileHash}`; - const restoreKeys = [`${keyPrefix}${packageManager}-`, keyPrefix]; + const restoreKeys = [`${keyPrefix}${packageManager}-`]; core.debug(`primary key is ${primaryKey}`); core.saveState(State.CachePrimaryKey, primaryKey); const cacheKey = await cache.restoreCache(paths, primaryKey, restoreKeys); diff --git a/src/main.ts b/src/main.ts index 956bc1449..a8d30ce62 100644 --- a/src/main.ts +++ b/src/main.ts @@ -52,7 +52,8 @@ export async function run() { throw new Error('Caching is not supported on GHES'); } const cacheDependencyPath = core.getInput('cache-dependency-path'); - await restoreCache(cache, cacheDependencyPath); + const cacheInvalidateAfterDays = core.getInput('cache-invalidate-after-days'); + await restoreCache(cache, cacheDependencyPath, cacheInvalidateAfterDays); } const matchersPath = path.join(__dirname, '../..', '.github');