From dbb732b211936d69bacf8009f13f32a0be256003 Mon Sep 17 00:00:00 2001
From: Josh Soref <jsoref@users.noreply.github.com>
Date: Sun, 23 Jan 2022 13:12:58 -0500
Subject: [PATCH 1/2] Clarify cache-hit output

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index bd74444..73da3c1 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ Create a workflow `.yml` file in your repositories `.github/workflows` directory
 
 ### Outputs
 
-* `cache-hit` - A boolean value to indicate an exact match was found for the key
+* `cache-hit` - A boolean value to indicate an exact match was found for the key. It will be `false` if a `restore-key` is matched.
 
 > See [Skipping steps based on cache-hit](#Skipping-steps-based-on-cache-hit) for info on using this output
 

From dde36b38ea79ae648f929b0fa64121f6845fc2d1 Mon Sep 17 00:00:00 2001
From: Josh Soref <jsoref@users.noreply.github.com>
Date: Sun, 23 Jan 2022 13:46:47 -0500
Subject: [PATCH 2/2] Add outputs.cache-key

---
 README.md                     |  2 ++
 __tests__/actionUtils.test.ts |  6 ++++--
 __tests__/restore.test.ts     |  5 ++++-
 dist/restore/index.js         | 23 ++++++++++++++++++++---
 dist/save/index.js            |  6 ++++--
 src/constants.ts              |  3 ++-
 src/restore.ts                | 20 +++++++++++++++++++-
 src/utils/actionUtils.ts      |  5 +++--
 8 files changed, 58 insertions(+), 12 deletions(-)

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<void> {
             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 {