diff --git a/__tests__/restore.test.ts b/__tests__/restore.test.ts index c96a2d6..59077ba 100644 --- a/__tests__/restore.test.ts +++ b/__tests__/restore.test.ts @@ -401,3 +401,57 @@ test("restore with cache found for restore key", async () => { ); expect(failedMock).toHaveBeenCalledTimes(0); }); + +test("restore skipped with save-only", async () => { + const key = "node-test"; + const restoreKey = "node-"; + testUtils.setInputs({ + path: "node_modules", + key, + restoreKeys: [restoreKey], + saveOnly: "true" + }); + + const infoMock = jest.spyOn(core, "info"); + const failedMock = jest.spyOn(core, "setFailed"); + const stateMock = jest.spyOn(core, "saveState"); + + const cacheEntry: ArtifactCacheEntry = { + cacheKey: restoreKey, + scope: "refs/heads/master", + archiveLocation: "www.actionscache.test/download" + }; + const getCacheMock = jest.spyOn(cacheHttpClient, "getCacheEntry"); + getCacheMock.mockImplementation(() => { + return Promise.resolve(cacheEntry); + }); + const tempPath = "/foo/bar"; + + const createTempDirectoryMock = jest.spyOn( + actionUtils, + "createTempDirectory" + ); + createTempDirectoryMock.mockImplementation(() => { + return Promise.resolve(tempPath); + }); + + const setCacheStateMock = jest.spyOn(actionUtils, "setCacheState"); + const downloadCacheMock = jest.spyOn(cacheHttpClient, "downloadCache"); + const setCacheHitOutputMock = jest.spyOn(actionUtils, "setCacheHitOutput"); + + await run(); + + expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key); + expect(getCacheMock).toHaveBeenCalledWith([key, restoreKey]); + expect(setCacheStateMock).toHaveBeenCalledWith(cacheEntry); + expect(createTempDirectoryMock).toHaveBeenCalledTimes(0); + expect(downloadCacheMock).toHaveBeenCalledTimes(0); + + expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); + expect(setCacheHitOutputMock).toHaveBeenCalledWith(false); + + expect(infoMock).toHaveBeenCalledWith( + "Cache action configured for save-only, skipping restore step." + ); + expect(failedMock).toHaveBeenCalledTimes(0); +}); diff --git a/__tests__/save.test.ts b/__tests__/save.test.ts index 75938f1..2491434 100644 --- a/__tests__/save.test.ts +++ b/__tests__/save.test.ts @@ -414,7 +414,7 @@ test("save skipped with restore only", async () => { await run(); expect(infoMock).toHaveBeenCalledWith( - "Cache action configured for restore-only, skipping save step" + "Cache action configured for restore-only, skipping save step." ); expect(reserveCacheMock).toHaveBeenCalledTimes(0); diff --git a/action.yml b/action.yml index 7af781e..bf73ef6 100644 --- a/action.yml +++ b/action.yml @@ -14,6 +14,9 @@ inputs: restore-only: description: 'Disables saving a new cache entry when true' required: false + save-only: + description: 'Disables downloading and restoring a new cache entry when true' + 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 9c41c59..60871a9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,7 +2,8 @@ export enum Inputs { Key = "key", Path = "path", RestoreKeys = "restore-keys", - RestoreOnly = "restore-only" + RestoreOnly = "restore-only", + SaveOnly = "save-only" } export enum Outputs { diff --git a/src/restore.ts b/src/restore.ts index 4911e7e..b200c6c 100644 --- a/src/restore.ts +++ b/src/restore.ts @@ -67,15 +67,28 @@ async function run(): Promise { return; } + const isExactKeyMatch = utils.isExactKeyMatch( + primaryKey, + cacheEntry + ); + + // Store the cache result + utils.setCacheState(cacheEntry); + + if (core.getInput(Inputs.SaveOnly) === "true") { + core.info( + "Cache action configured for save-only, skipping restore step." + ); + utils.setCacheHitOutput(isExactKeyMatch); + return; + } + const archivePath = path.join( await utils.createTempDirectory(), "cache.tgz" ); core.debug(`Archive Path: ${archivePath}`); - // Store the cache result - utils.setCacheState(cacheEntry); - // Download the cache from the cache entry await cacheHttpClient.downloadCache( cacheEntry.archiveLocation, @@ -91,10 +104,6 @@ async function run(): Promise { await extractTar(archivePath, cachePath); - const isExactKeyMatch = utils.isExactKeyMatch( - primaryKey, - cacheEntry - ); utils.setCacheHitOutput(isExactKeyMatch); core.info( diff --git a/src/save.ts b/src/save.ts index cf4facf..bac9f00 100644 --- a/src/save.ts +++ b/src/save.ts @@ -20,7 +20,7 @@ async function run(): Promise { if (core.getInput(Inputs.RestoreOnly) === "true") { core.info( - "Cache action configured for restore-only, skipping save step" + "Cache action configured for restore-only, skipping save step." ); return; } diff --git a/src/utils/testUtils.ts b/src/utils/testUtils.ts index b1d20d0..115fe37 100644 --- a/src/utils/testUtils.ts +++ b/src/utils/testUtils.ts @@ -13,6 +13,8 @@ interface CacheInput { path: string; key: string; restoreKeys?: string[]; + restoreOnly?: string; + saveOnly?: string; } export function setInputs(input: CacheInput): void { @@ -20,10 +22,14 @@ export function setInputs(input: CacheInput): void { setInput(Inputs.Key, input.key); input.restoreKeys && setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n")); + input.restoreOnly && setInput(Inputs.RestoreOnly, input.restoreOnly); + input.saveOnly && setInput(Inputs.SaveOnly, input.saveOnly); } export function clearInputs(): void { delete process.env[getInputName(Inputs.Path)]; delete process.env[getInputName(Inputs.Key)]; delete process.env[getInputName(Inputs.RestoreKeys)]; + delete process.env[getInputName(Inputs.RestoreOnly)]; + delete process.env[getInputName(Inputs.SaveOnly)]; }