From 4c023f01d613e60293d8004f251a18bfb9bbd71d Mon Sep 17 00:00:00 2001 From: ericLemanissier Date: Thu, 10 Apr 2025 13:49:21 +0000 Subject: [PATCH] make action caches immutable With this change, caches become immutable by appending the workflow run_id, which makes the actual key unique (appart from re-run) The cache restore works because the primaryKey is a prefix anyway: https://github.com/actions/toolkit/blob/1b1e81526b802d1d641911393281c2fb45ed5f11/packages/cache/src/cache.ts#L67 This follows recommendations from https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache Unused caches are removed after 7 days by github: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy This avoids users having to define unneeded permission `actions: write` --- dist/index.js | 10 +++++----- src/classes/state/state-cache-storage.ts | 14 ++++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dist/index.js b/dist/index.js index 50ec5fed2..94d7872f0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1650,16 +1650,17 @@ class StateCacheStorage { const filePath = path_1.default.join(tmpDir, STATE_FILE); fs_1.default.writeFileSync(filePath, serializedState); try { - const cacheExists = yield checkIfCacheExists(CACHE_KEY); + const full_cache_key = CACHE_KEY + '_' + github_1.context.runId; + const cacheExists = yield checkIfCacheExists(full_cache_key); if (cacheExists) { - yield resetCacheWithOctokit(CACHE_KEY); + yield resetCacheWithOctokit(full_cache_key); } const fileSize = fs_1.default.statSync(filePath).size; if (fileSize === 0) { core.info(`the state will be removed`); return; } - yield cache.saveCache([path_1.default.dirname(filePath)], CACHE_KEY); + yield cache.saveCache([path_1.default.dirname(filePath)], full_cache_key); } catch (error) { core.warning(`Saving the state was not successful due to "${error.message || 'unknown reason'}"`); @@ -1675,12 +1676,11 @@ class StateCacheStorage { const filePath = path_1.default.join(tmpDir, STATE_FILE); unlinkSafely(filePath); try { - const cacheExists = yield checkIfCacheExists(CACHE_KEY); + const cacheExists = yield cache.restoreCache([path_1.default.dirname(filePath)], CACHE_KEY); if (!cacheExists) { core.info('The saved state was not found, the process starts from the first issue.'); return ''; } - yield cache.restoreCache([path_1.default.dirname(filePath)], CACHE_KEY); if (!fs_1.default.existsSync(filePath)) { core.warning('Unknown error when unpacking the cache, the process starts from the first issue.'); return ''; diff --git a/src/classes/state/state-cache-storage.ts b/src/classes/state/state-cache-storage.ts index b30b503b6..8803339eb 100644 --- a/src/classes/state/state-cache-storage.ts +++ b/src/classes/state/state-cache-storage.ts @@ -71,9 +71,10 @@ export class StateCacheStorage implements IStateStorage { fs.writeFileSync(filePath, serializedState); try { - const cacheExists = await checkIfCacheExists(CACHE_KEY); + const full_cache_key = CACHE_KEY + '_' + context.runId; + const cacheExists = await checkIfCacheExists(full_cache_key); if (cacheExists) { - await resetCacheWithOctokit(CACHE_KEY); + await resetCacheWithOctokit(full_cache_key); } const fileSize = fs.statSync(filePath).size; @@ -82,7 +83,7 @@ export class StateCacheStorage implements IStateStorage { return; } - await cache.saveCache([path.dirname(filePath)], CACHE_KEY); + await cache.saveCache([path.dirname(filePath)], full_cache_key); } catch (error) { core.warning( `Saving the state was not successful due to "${ @@ -99,7 +100,10 @@ export class StateCacheStorage implements IStateStorage { const filePath = path.join(tmpDir, STATE_FILE); unlinkSafely(filePath); try { - const cacheExists = await checkIfCacheExists(CACHE_KEY); + const cacheExists = await cache.restoreCache( + [path.dirname(filePath)], + CACHE_KEY + ); if (!cacheExists) { core.info( 'The saved state was not found, the process starts from the first issue.' @@ -107,8 +111,6 @@ export class StateCacheStorage implements IStateStorage { return ''; } - await cache.restoreCache([path.dirname(filePath)], CACHE_KEY); - if (!fs.existsSync(filePath)) { core.warning( 'Unknown error when unpacking the cache, the process starts from the first issue.'