From 2d697b4d9cc7a3054d37ee7201c1448654f24973 Mon Sep 17 00:00:00 2001
From: davidsbond <davidsbond93@gmail.com>
Date: Thu, 18 Jun 2020 22:30:32 +0100
Subject: [PATCH 1/5] Allow updating cache with 'update' key

---
 __tests__/actionUtils.test.ts | 10 ++++++++++
 __tests__/save.test.ts        | 35 +++++++++++++++++++++++++++++++++++
 action.yml                    |  3 +++
 src/constants.ts              |  3 ++-
 src/save.ts                   |  8 +++++---
 src/utils/actionUtils.ts      |  7 +++++++
 6 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/__tests__/actionUtils.test.ts b/__tests__/actionUtils.test.ts
index a6dc291..0a11d1f 100644
--- a/__tests__/actionUtils.test.ts
+++ b/__tests__/actionUtils.test.ts
@@ -194,3 +194,13 @@ test("getInputAsArray handles empty lines correctly", () => {
     testUtils.setInput("foo", "\n\nbar\n\nbaz\n\n");
     expect(actionUtils.getInputAsArray("foo")).toEqual(["bar", "baz"]);
 });
+
+test("getInputAsBoolean returns true if the value is set to 'true'", () => {
+    testUtils.setInput("foo", "true");
+    expect(actionUtils.getInputAsBoolean("foo")).toEqual(true);
+});
+
+test("getInputAsBoolean returns false if the value is set to anything else", () => {
+    testUtils.setInput("foo", "false");
+    expect(actionUtils.getInputAsBoolean("foo")).toEqual(false);
+});
diff --git a/__tests__/save.test.ts b/__tests__/save.test.ts
index 943a2bd..3c55645 100644
--- a/__tests__/save.test.ts
+++ b/__tests__/save.test.ts
@@ -118,6 +118,41 @@ test("save with exact match returns early", async () => {
     expect(failedMock).toHaveBeenCalledTimes(0);
 });
 
+test("save with exact match updates when configured", async () => {
+    const failedMock = jest.spyOn(core, "setFailed");
+
+    const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
+    const savedCacheKey = primaryKey;
+
+    jest.spyOn(core, "getState")
+        // Cache Entry State
+        .mockImplementationOnce(() => {
+            return savedCacheKey;
+        })
+        // Cache Key State
+        .mockImplementationOnce(() => {
+            return primaryKey;
+        });
+
+    const inputPath = "node_modules";
+    testUtils.setInput(Inputs.Path, inputPath);
+    testUtils.setInput(Inputs.Update, "true");
+
+    const cacheId = 4;
+    const saveCacheMock = jest
+        .spyOn(cache, "saveCache")
+        .mockImplementationOnce(() => {
+            return Promise.resolve(cacheId);
+        });
+
+    await run();
+
+    expect(saveCacheMock).toHaveBeenCalledTimes(1);
+    expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey);
+
+    expect(failedMock).toHaveBeenCalledTimes(0);
+});
+
 test("save with missing input outputs warning", async () => {
     const logWarningMock = jest.spyOn(actionUtils, "logWarning");
     const failedMock = jest.spyOn(core, "setFailed");
diff --git a/action.yml b/action.yml
index e50c38b..47fa26a 100644
--- a/action.yml
+++ b/action.yml
@@ -11,6 +11,9 @@ inputs:
   restore-keys:
     description: 'An ordered list of keys to use for restoring the cache if no cache hit occurred for key'
     required: false
+  update:
+    description: 'If true, the cache will be updated if the key already exists'
+    required: false
 outputs:
   cache-hit:
     description: 'A boolean value to indicate an exact match was found for the primary key'
diff --git a/src/constants.ts b/src/constants.ts
index a190e00..b32968e 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -1,7 +1,8 @@
 export enum Inputs {
     Key = "key",
     Path = "path",
-    RestoreKeys = "restore-keys"
+    RestoreKeys = "restore-keys",
+    Update = "update"
 }
 
 export enum Outputs {
diff --git a/src/save.ts b/src/save.ts
index 80b656c..6897a57 100644
--- a/src/save.ts
+++ b/src/save.ts
@@ -16,15 +16,17 @@ async function run(): Promise<void> {
         }
 
         const state = utils.getCacheState();
-
-        // Inputs are re-evaluted before the post action, so we want the original key used for restore
+        // Inputs are re-evaluated before the post action, so we want the original key used for restore
         const primaryKey = core.getState(State.CachePrimaryKey);
         if (!primaryKey) {
             utils.logWarning(`Error retrieving key from state.`);
             return;
         }
 
-        if (utils.isExactKeyMatch(primaryKey, state)) {
+        if (
+            utils.isExactKeyMatch(primaryKey, state) &&
+            !utils.getInputAsBoolean(Inputs.Update)
+        ) {
             core.info(
                 `Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
             );
diff --git a/src/utils/actionUtils.ts b/src/utils/actionUtils.ts
index 26bb8c1..256b8e6 100644
--- a/src/utils/actionUtils.ts
+++ b/src/utils/actionUtils.ts
@@ -56,3 +56,10 @@ export function getInputAsArray(
         .map(s => s.trim())
         .filter(x => x !== "");
 }
+
+export function getInputAsBoolean(
+    name: string,
+    options?: core.InputOptions
+): boolean {
+    return core.getInput(name, options) === "true";
+}

From 5b41e77e7a897710a0c184a0f4ba8f49943da839 Mon Sep 17 00:00:00 2001
From: Eliza Brock Marcum <eliza@elizamarcum.com>
Date: Wed, 24 Jun 2020 13:50:45 -0500
Subject: [PATCH 2/5] Fix caching using update key

---
 __tests__/actionUtils.test.ts | 10 ----------
 __tests__/save.test.ts        |  7 +++++--
 src/save.ts                   | 22 +++++++++++++---------
 src/utils/actionUtils.ts      |  7 -------
 src/utils/testUtils.ts        |  3 +++
 5 files changed, 21 insertions(+), 28 deletions(-)

diff --git a/__tests__/actionUtils.test.ts b/__tests__/actionUtils.test.ts
index 0a11d1f..a6dc291 100644
--- a/__tests__/actionUtils.test.ts
+++ b/__tests__/actionUtils.test.ts
@@ -194,13 +194,3 @@ test("getInputAsArray handles empty lines correctly", () => {
     testUtils.setInput("foo", "\n\nbar\n\nbaz\n\n");
     expect(actionUtils.getInputAsArray("foo")).toEqual(["bar", "baz"]);
 });
-
-test("getInputAsBoolean returns true if the value is set to 'true'", () => {
-    testUtils.setInput("foo", "true");
-    expect(actionUtils.getInputAsBoolean("foo")).toEqual(true);
-});
-
-test("getInputAsBoolean returns false if the value is set to anything else", () => {
-    testUtils.setInput("foo", "false");
-    expect(actionUtils.getInputAsBoolean("foo")).toEqual(false);
-});
diff --git a/__tests__/save.test.ts b/__tests__/save.test.ts
index 3c55645..ab78d77 100644
--- a/__tests__/save.test.ts
+++ b/__tests__/save.test.ts
@@ -118,7 +118,8 @@ test("save with exact match returns early", async () => {
     expect(failedMock).toHaveBeenCalledTimes(0);
 });
 
-test("save with exact match updates when configured", async () => {
+test("save with exact match and updates enabled updates the cache", async () => {
+    const infoMock = jest.spyOn(core, "info");
     const failedMock = jest.spyOn(core, "setFailed");
 
     const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
@@ -147,9 +148,11 @@ test("save with exact match updates when configured", async () => {
 
     await run();
 
+    expect(infoMock).toHaveBeenCalledWith(
+        `Cache hit occurred on the primary key ${primaryKey}, but updates were enabled, so updating cache.`
+    );
     expect(saveCacheMock).toHaveBeenCalledTimes(1);
     expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey);
-
     expect(failedMock).toHaveBeenCalledTimes(0);
 });
 
diff --git a/src/save.ts b/src/save.ts
index 6897a57..24fa720 100644
--- a/src/save.ts
+++ b/src/save.ts
@@ -16,21 +16,25 @@ async function run(): Promise<void> {
         }
 
         const state = utils.getCacheState();
-        // Inputs are re-evaluated before the post action, so we want the original key used for restore
+
+        // Inputs are re-evaluted before the post action, so we want the original key used for restore
         const primaryKey = core.getState(State.CachePrimaryKey);
         if (!primaryKey) {
             utils.logWarning(`Error retrieving key from state.`);
             return;
         }
 
-        if (
-            utils.isExactKeyMatch(primaryKey, state) &&
-            !utils.getInputAsBoolean(Inputs.Update)
-        ) {
-            core.info(
-                `Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
-            );
-            return;
+        if (utils.isExactKeyMatch(primaryKey, state)) {
+          if (core.getInput(Inputs.Update) === "true") {
+              core.info(
+                  `Cache hit occurred on the primary key ${primaryKey}, but updates were enabled, so updating cache.`
+              );
+          } else {
+              core.info(
+                  `Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
+              );
+              return;
+          }
         }
 
         const cachePaths = utils.getInputAsArray(Inputs.Path, {
diff --git a/src/utils/actionUtils.ts b/src/utils/actionUtils.ts
index 256b8e6..26bb8c1 100644
--- a/src/utils/actionUtils.ts
+++ b/src/utils/actionUtils.ts
@@ -56,10 +56,3 @@ export function getInputAsArray(
         .map(s => s.trim())
         .filter(x => x !== "");
 }
-
-export function getInputAsBoolean(
-    name: string,
-    options?: core.InputOptions
-): boolean {
-    return core.getInput(name, options) === "true";
-}
diff --git a/src/utils/testUtils.ts b/src/utils/testUtils.ts
index b1d20d0..f6b0261 100644
--- a/src/utils/testUtils.ts
+++ b/src/utils/testUtils.ts
@@ -13,11 +13,13 @@ interface CacheInput {
     path: string;
     key: string;
     restoreKeys?: string[];
+    update: string;
 }
 
 export function setInputs(input: CacheInput): void {
     setInput(Inputs.Path, input.path);
     setInput(Inputs.Key, input.key);
+    setInput(Inputs.Update, input.update);
     input.restoreKeys &&
         setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
 }
@@ -25,5 +27,6 @@ export function setInputs(input: CacheInput): void {
 export function clearInputs(): void {
     delete process.env[getInputName(Inputs.Path)];
     delete process.env[getInputName(Inputs.Key)];
+    delete process.env[getInputName(Inputs.Update)];
     delete process.env[getInputName(Inputs.RestoreKeys)];
 }

From b28dbaf08e5be9409ce2dfa3373968b2ea1ac700 Mon Sep 17 00:00:00 2001
From: Eliza Brock Marcum <eliza@elizamarcum.com>
Date: Wed, 24 Jun 2020 14:55:55 -0500
Subject: [PATCH 3/5] For testing in my build

---
 dist/restore/index.js |  1 +
 dist/save/index.js    | 10 ++++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/dist/restore/index.js b/dist/restore/index.js
index 00349f4..811694c 100644
--- a/dist/restore/index.js
+++ b/dist/restore/index.js
@@ -6717,6 +6717,7 @@ var Inputs;
     Inputs["Key"] = "key";
     Inputs["Path"] = "path";
     Inputs["RestoreKeys"] = "restore-keys";
+    Inputs["Update"] = "update";
 })(Inputs = exports.Inputs || (exports.Inputs = {}));
 var Outputs;
 (function (Outputs) {
diff --git a/dist/save/index.js b/dist/save/index.js
index f733e9a..b9ba86f 100644
--- a/dist/save/index.js
+++ b/dist/save/index.js
@@ -6605,8 +6605,13 @@ function run() {
                 return;
             }
             if (utils.isExactKeyMatch(primaryKey, state)) {
-                core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
-                return;
+                if (core.getInput(constants_1.Inputs.Update) === "true") {
+                    core.info(`Cache hit occurred on the primary key ${primaryKey}, but updates were enabled, so updating cache.`);
+                }
+                else {
+                    core.info(`Cache hit occurred on the primary key ${primaryKey}, not saving cache.`);
+                    return;
+                }
             }
             const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
                 required: true
@@ -6802,6 +6807,7 @@ var Inputs;
     Inputs["Key"] = "key";
     Inputs["Path"] = "path";
     Inputs["RestoreKeys"] = "restore-keys";
+    Inputs["Update"] = "update";
 })(Inputs = exports.Inputs || (exports.Inputs = {}));
 var Outputs;
 (function (Outputs) {

From a01a990100d28759e8c55aa09530ec1ca658f3b2 Mon Sep 17 00:00:00 2001
From: Eliza Brock Marcum <eliza@elizamarcum.com>
Date: Thu, 25 Jun 2020 10:02:13 -0500
Subject: [PATCH 4/5] Formatting updates via. prettier

---
 src/save.ts | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/save.ts b/src/save.ts
index 24fa720..0b0a7ca 100644
--- a/src/save.ts
+++ b/src/save.ts
@@ -25,16 +25,16 @@ async function run(): Promise<void> {
         }
 
         if (utils.isExactKeyMatch(primaryKey, state)) {
-          if (core.getInput(Inputs.Update) === "true") {
-              core.info(
-                  `Cache hit occurred on the primary key ${primaryKey}, but updates were enabled, so updating cache.`
-              );
-          } else {
-              core.info(
-                  `Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
-              );
-              return;
-          }
+            if (core.getInput(Inputs.Update) === "true") {
+                core.info(
+                    `Cache hit occurred on the primary key ${primaryKey}, but updates were enabled, so updating cache.`
+                );
+            } else {
+                core.info(
+                    `Cache hit occurred on the primary key ${primaryKey}, not saving cache.`
+                );
+                return;
+            }
         }
 
         const cachePaths = utils.getInputAsArray(Inputs.Path, {

From 82f8348041534f80365ba1e8df5d06c3404f26b8 Mon Sep 17 00:00:00 2001
From: davidsbond <davidsbond93@gmail.com>
Date: Thu, 25 Jun 2020 16:20:02 +0100
Subject: [PATCH 5/5] Make 'update' optional

---
 src/utils/testUtils.ts | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/utils/testUtils.ts b/src/utils/testUtils.ts
index f6b0261..140a2b1 100644
--- a/src/utils/testUtils.ts
+++ b/src/utils/testUtils.ts
@@ -13,13 +13,15 @@ interface CacheInput {
     path: string;
     key: string;
     restoreKeys?: string[];
-    update: string;
+    update?: string;
 }
 
 export function setInputs(input: CacheInput): void {
     setInput(Inputs.Path, input.path);
     setInput(Inputs.Key, input.key);
-    setInput(Inputs.Update, input.update);
+    input.update
+        ? setInput(Inputs.Update, input.update)
+        : setInput(Inputs.Update, "false");
     input.restoreKeys &&
         setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
 }