From cbe3ec3ea18a8adf9ef339c33ff89b256471a9e3 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 ba67317c9..ba7dfbf1f 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ The action defaults to search for the dependency file (`package-lock.json`, `npm **Note:** The action does not cache `node_modules` +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-data) guide. **Caching npm dependencies:** diff --git a/__tests__/cache-restore.test.ts b/__tests__/cache-restore.test.ts index cd9cde55a..68de2af6d 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}-` ); expect(setOutputSpy).toHaveBeenCalledWith('cache-hit', true); } @@ -163,10 +163,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}-` ); expect(setOutputSpy).toHaveBeenCalledWith('cache-hit', false); } diff --git a/action.yml b/action.yml index b22de1ef6..13473abfa 100644 --- a/action.yml +++ b/action.yml @@ -25,6 +25,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 outputs: diff --git a/src/cache-restore.ts b/src/cache-restore.ts index cb81844c5..d72da4ed8 100644 --- a/src/cache-restore.ts +++ b/src/cache-restore.ts @@ -13,7 +13,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); diff --git a/src/main.ts b/src/main.ts index 90cd1d9d9..7708a606d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -61,7 +61,8 @@ export async function run() { if (cache && isCacheFeatureAvailable()) { 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');