diff --git a/README.md b/README.md index 73da3c1..6972979 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Create a workflow `.yml` file in your repositories `.github/workflows` directory > See [Skipping steps based on cache-hit](#Skipping-steps-based-on-cache-hit) for info on using this output +* `cache-key` - A string indicating the matching cache key (if any). + ### Cache scopes The cache is scoped to the key and branch. The default branch cache is available to other branches. diff --git a/__tests__/actionUtils.test.ts b/__tests__/actionUtils.test.ts index 419881e..458600d 100644 --- a/__tests__/actionUtils.test.ts +++ b/__tests__/actionUtils.test.ts @@ -102,7 +102,8 @@ test("setOutputAndState with exact match to set cache-hit output and state", () actionUtils.setOutputAndState(key, cacheKey); expect(setOutputMock).toHaveBeenCalledWith(Outputs.CacheHit, "true"); - expect(setOutputMock).toHaveBeenCalledTimes(1); + expect(setOutputMock).toHaveBeenCalledWith(Outputs.CacheKey, key); + expect(setOutputMock).toHaveBeenCalledTimes(2); expect(saveStateMock).toHaveBeenCalledWith(State.CacheMatchedKey, cacheKey); expect(saveStateMock).toHaveBeenCalledTimes(1); @@ -118,7 +119,8 @@ test("setOutputAndState with no exact match to set cache-hit output and state", actionUtils.setOutputAndState(key, cacheKey); expect(setOutputMock).toHaveBeenCalledWith(Outputs.CacheHit, "false"); - expect(setOutputMock).toHaveBeenCalledTimes(1); + expect(setOutputMock).toHaveBeenCalledWith(Outputs.CacheKey, key); + expect(setOutputMock).toHaveBeenCalledTimes(2); expect(saveStateMock).toHaveBeenCalledWith(State.CacheMatchedKey, cacheKey); expect(saveStateMock).toHaveBeenCalledTimes(1); diff --git a/__tests__/restore.test.ts b/__tests__/restore.test.ts index 4761782..88292bb 100644 --- a/__tests__/restore.test.ts +++ b/__tests__/restore.test.ts @@ -158,6 +158,7 @@ test("restore with no cache found", async () => { const infoMock = jest.spyOn(core, "info"); const failedMock = jest.spyOn(core, "setFailed"); const stateMock = jest.spyOn(core, "saveState"); + const setOutputMock = jest.spyOn(core, "setOutput"); const restoreCacheMock = jest .spyOn(cache, "restoreCache") .mockImplementationOnce(() => { @@ -172,6 +173,8 @@ test("restore with no cache found", async () => { expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key); expect(failedMock).toHaveBeenCalledTimes(0); + expect(setOutputMock).toHaveBeenCalledTimes(0); + expect(infoMock).toHaveBeenCalledWith( `Cache not found for input keys: ${key}` ); @@ -270,7 +273,7 @@ test("restore with cache found for key", async () => { expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledWith(true); - expect(infoMock).toHaveBeenCalledWith(`Cache restored from key: ${key}`); + expect(infoMock).toHaveBeenCalledWith(`Cache restored for key: ${key}`); expect(failedMock).toHaveBeenCalledTimes(0); }); diff --git a/dist/restore/index.js b/dist/restore/index.js index 671451c..b72770f 100644 --- a/dist/restore/index.js +++ b/dist/restore/index.js @@ -4609,6 +4609,7 @@ var Inputs; var Outputs; (function (Outputs) { Outputs["CacheHit"] = "cache-hit"; + Outputs["CacheKey"] = "cache-key"; })(Outputs = exports.Outputs || (exports.Outputs = {})); var State; (function (State) { @@ -36343,8 +36344,9 @@ function isExactKeyMatch(key, cacheKey) { }) === 0); } exports.isExactKeyMatch = isExactKeyMatch; -function setCacheState(state) { +function setCacheState(state, key) { core.saveState(constants_1.State.CacheMatchedKey, state); + core.setOutput(constants_1.Outputs.CacheKey, key); } exports.setCacheState = setCacheState; function setCacheHitOutput(isCacheHit) { @@ -36354,7 +36356,7 @@ exports.setCacheHitOutput = setCacheHitOutput; function setOutputAndState(key, cacheKey) { setCacheHitOutput(isExactKeyMatch(key, cacheKey)); // Store the matched cache key if it exists - cacheKey && setCacheState(cacheKey); + cacheKey && setCacheState(cacheKey, key); } exports.setOutputAndState = setOutputAndState; function getCacheState() { @@ -46748,7 +46750,22 @@ function run() { utils.setCacheState(cacheKey); const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); utils.setCacheHitOutput(isExactKeyMatch); - core.info(`Cache restored from key: ${cacheKey}`); + let foundKey; + if (isExactKeyMatch) { + foundKey = primaryKey; + core.info(`Cache restored for key: ${foundKey}`); + } + else { + let i; + for (i = 0; i < restoreKeys.length - 1; i++) { + const fallbackCacheKey = yield cache.restoreCache(cachePaths, restoreKeys[i]); + if (cacheKey) { + break; + } + } + foundKey = restoreKeys[i]; + core.info(`Cache restored from key: ${foundKey}`); + } } catch (error) { if (error.name === cache.ValidationError.name) { diff --git a/dist/save/index.js b/dist/save/index.js index b0d491d..371bc5b 100644 --- a/dist/save/index.js +++ b/dist/save/index.js @@ -4609,6 +4609,7 @@ var Inputs; var Outputs; (function (Outputs) { Outputs["CacheHit"] = "cache-hit"; + Outputs["CacheKey"] = "cache-key"; })(Outputs = exports.Outputs || (exports.Outputs = {})); var State; (function (State) { @@ -36343,8 +36344,9 @@ function isExactKeyMatch(key, cacheKey) { }) === 0); } exports.isExactKeyMatch = isExactKeyMatch; -function setCacheState(state) { +function setCacheState(state, key) { core.saveState(constants_1.State.CacheMatchedKey, state); + core.setOutput(constants_1.Outputs.CacheKey, key); } exports.setCacheState = setCacheState; function setCacheHitOutput(isCacheHit) { @@ -36354,7 +36356,7 @@ exports.setCacheHitOutput = setCacheHitOutput; function setOutputAndState(key, cacheKey) { setCacheHitOutput(isExactKeyMatch(key, cacheKey)); // Store the matched cache key if it exists - cacheKey && setCacheState(cacheKey); + cacheKey && setCacheState(cacheKey, key); } exports.setOutputAndState = setOutputAndState; function getCacheState() { diff --git a/src/constants.ts b/src/constants.ts index 133f47d..c16344e 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,7 +6,8 @@ export enum Inputs { } export enum Outputs { - CacheHit = "cache-hit" + CacheHit = "cache-hit", + CacheKey = "cache-key" } export enum State { diff --git a/src/restore.ts b/src/restore.ts index d411459..d43bb33 100644 --- a/src/restore.ts +++ b/src/restore.ts @@ -54,7 +54,25 @@ async function run(): Promise { const isExactKeyMatch = utils.isExactKeyMatch(primaryKey, cacheKey); utils.setCacheHitOutput(isExactKeyMatch); - core.info(`Cache restored from key: ${cacheKey}`); + let foundKey: string; + if (isExactKeyMatch) { + foundKey = primaryKey; + core.info(`Cache restored for key: ${foundKey}`); + } else { + let i: number; + for (i = 0; i < restoreKeys.length - 1; i++) { + const fallbackCacheKey = await cache.restoreCache( + cachePaths, + restoreKeys[i] + ); + if (cacheKey) { + break; + } + } + foundKey = restoreKeys[i]; + core.info(`Cache restored from key: ${foundKey}`); + } + } catch (error) { if (error.name === cache.ValidationError.name) { throw error; diff --git a/src/utils/actionUtils.ts b/src/utils/actionUtils.ts index a4d712d..8b7eec9 100644 --- a/src/utils/actionUtils.ts +++ b/src/utils/actionUtils.ts @@ -18,8 +18,9 @@ export function isExactKeyMatch(key: string, cacheKey?: string): boolean { ); } -export function setCacheState(state: string): void { +export function setCacheState(state: string, key?: string): void { core.saveState(State.CacheMatchedKey, state); + core.setOutput(Outputs.CacheKey, key); } export function setCacheHitOutput(isCacheHit: boolean): void { @@ -29,7 +30,7 @@ export function setCacheHitOutput(isCacheHit: boolean): void { export function setOutputAndState(key: string, cacheKey?: string): void { setCacheHitOutput(isExactKeyMatch(key, cacheKey)); // Store the matched cache key if it exists - cacheKey && setCacheState(cacheKey); + cacheKey && setCacheState(cacheKey, key); } export function getCacheState(): string | undefined {