1
0
mirror of https://github.com/actions/cache.git synced 2026-08-05 19:02:14 +08:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Bishal Prasad 8f35dac68e streamToBuffer logging 2023-03-23 22:26:57 +05:30
Bishal Prasad 938b484130 add more logs 2023-03-23 16:59:47 +05:30
Bishal Prasad eff27e646c Add paralleExecute index to logs 2023-03-23 10:23:51 +05:30
38 changed files with 114908 additions and 113421 deletions
-2
View File
@@ -15,5 +15,3 @@ jobs:
call-check-dist: call-check-dist:
name: Check dist/ name: Check dist/
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
with:
node-version: "20.x"
@@ -14,3 +14,9 @@ jobs:
- name: add_assignees - name: add_assignees
run: | run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.issue.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}' curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.issue.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
- uses: actions/add-to-project@v0.4.0
name: Add to Project Board
with:
project-url: https://github.com/orgs/actions/projects/12
github-token: ${{ secrets.CACHE_BOARD_TOKEN }}
+6
View File
@@ -18,3 +18,9 @@ jobs:
- name: Add Assignee - name: Add Assignee
run: | run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.pull_request.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}' curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN}}" https://api.github.com/repos/${{github.repository}}/issues/${{ github.event.pull_request.number}}/assignees -d '{"assignees":["${{steps.oncall.outputs.CURRENT}}"]}'
- uses: actions/add-to-project@v0.4.0
name: Add to Project Board
with:
project-url: https://github.com/orgs/actions/projects/12
github-token: ${{ secrets.CACHE_BOARD_TOKEN }}
@@ -1,28 +0,0 @@
name: Release new action version
on:
release:
types: [released]
workflow_dispatch:
inputs:
TAG_NAME:
description: 'Tag name that the major tag will point to'
required: true
env:
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
permissions:
contents: write
jobs:
update_tag:
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
environment:
name: releaseNewActionVersion
runs-on: ubuntu-latest
steps:
- name: Update the ${{ env.TAG_NAME }} tag
id: update-major-tag
uses: actions/publish-action@v0.3.0
with:
source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
+2 -2
View File
@@ -21,10 +21,10 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Setup Node.js 20.x - name: Setup Node.js 16.x
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 16.x
cache: npm cache: npm
- run: npm ci - run: npm ci
- name: Prettier Format Check - name: Prettier Format Check
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+9 -14
View File
@@ -14,11 +14,6 @@ See ["Caching dependencies to speed up workflows"](https://docs.github.com/en/ac
## What's New ## What's New
### v4
* Updated to node 20
* Added a `save-always` flag to save the cache even if a prior step fails
### v3 ### v3
* Added support for caching in GHES 3.5+. * Added support for caching in GHES 3.5+.
@@ -95,7 +90,7 @@ jobs:
- name: Cache Primes - name: Cache Primes
id: cache-primes id: cache-primes
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: prime-numbers path: prime-numbers
key: ${{ runner.os }}-primes key: ${{ runner.os }}-primes
@@ -126,7 +121,7 @@ jobs:
- name: Restore cached Primes - name: Restore cached Primes
id: cache-primes-restore id: cache-primes-restore
uses: actions/cache/restore@v4 uses: actions/cache/restore@v3
with: with:
path: | path: |
path/to/dependencies path/to/dependencies
@@ -137,7 +132,7 @@ jobs:
. .
- name: Save Primes - name: Save Primes
id: cache-primes-save id: cache-primes-save
uses: actions/cache/save@v4 uses: actions/cache/save@v3
with: with:
path: | path: |
path/to/dependencies path/to/dependencies
@@ -191,7 +186,7 @@ A cache key can include any of the contexts, functions, literals, and operators
For example, using the [`hashFiles`](https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles) function allows you to create a new cache when dependencies change. For example, using the [`hashFiles`](https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles) function allows you to create a new cache when dependencies change.
```yaml ```yaml
- uses: actions/cache@v4 - uses: actions/cache@v3
with: with:
path: | path: |
path/to/dependencies path/to/dependencies
@@ -209,7 +204,7 @@ Additionally, you can use arbitrary command output in a cache key, such as a dat
echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
shell: bash shell: bash
- uses: actions/cache@v4 - uses: actions/cache@v3
with: with:
path: path/to/dependencies path: path/to/dependencies
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/lockfiles') }} key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/lockfiles') }}
@@ -231,7 +226,7 @@ Example:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/cache@v4 - uses: actions/cache@v3
id: cache id: cache
with: with:
path: path/to/dependencies path: path/to/dependencies
@@ -263,7 +258,7 @@ jobs:
- name: Cache Primes - name: Cache Primes
id: cache-primes id: cache-primes
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: prime-numbers path: prime-numbers
key: primes key: primes
@@ -274,7 +269,7 @@ jobs:
- name: Cache Numbers - name: Cache Numbers
id: cache-numbers id: cache-numbers
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: numbers path: numbers
key: primes key: primes
@@ -290,7 +285,7 @@ jobs:
- name: Cache Primes - name: Cache Primes
id: cache-primes id: cache-primes
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: prime-numbers path: prime-numbers
key: primes key: primes
+64 -85
View File
@@ -1,54 +1,77 @@
# Releases # Releases
### 4.0.2 ### 3.0.0
- Fixed restore `fail-on-cache-miss` not working. - Updated minimum runner version support from node 12 -> node 16
### 4.0.1 ### 3.0.1
- Updated `isGhes` check - Added support for caching from GHES 3.5.
- Fixed download issue for files > 2GB during restore.
### 4.0.0 ### 3.0.2
- Updated minimum runner version support from node 12 -> node 20 - Added support for dynamic cache size cap on GHES.
### 3.3.3 ### 3.0.3
- Updates @actions/cache to v3.2.3 to fix accidental mutated path arguments to `getCacheVersion` [actions/toolkit#1378](https://github.com/actions/toolkit/pull/1378) - Fixed avoiding empty cache save when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
- Additional audit fixes of npm package(s)
### 3.3.2 ### 3.0.4
- Fixes bug with Azure SDK causing blob downloads to get stuck. - Fixed tar creation error while trying to create tar with path as `~/` home folder on `ubuntu-latest`. ([issue](https://github.com/actions/cache/issues/689))
### 3.3.1 ### 3.0.5
- Reduced segment size to 128MB and segment timeout to 10 minutes to fail fast in case the cache download is stuck. - Removed error handling by consuming actions/cache 3.0 toolkit, Now cache server error handling will be done by toolkit. ([PR](https://github.com/actions/cache/pull/834))
### 3.3.0 ### 3.0.6
- Added option to lookup cache without downloading it. - Fixed [#809](https://github.com/actions/cache/issues/809) - zstd -d: no such file or directory error
- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory
### 3.2.6 ### 3.0.7
- Fix zstd not being used after zstd version upgrade to 1.5.4 on hosted runners. - Fixed [#810](https://github.com/actions/cache/issues/810) - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour.
### 3.2.5 ### 3.0.8
- Added fix to prevent from setting MYSYS environment variable globally. - Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
### 3.2.4 ### 3.0.9
- Added option to fail job on cache miss. - Enhanced the warning message for cache unavailablity in case of GHES.
### 3.2.3 ### 3.0.10
- Support cross os caching on Windows as an opt-in feature. - Fix a bug with sorting inputs.
- Fix issue with symlink restoration on Windows for cross-os caches. - Update definition for restore-keys in README.md
### 3.2.2 ### 3.0.11
- Reverted the changes made in 3.2.1 to use gnu tar and zstd by default on windows. - Update toolkit version to 3.0.5 to include `@actions/core@^1.10.0`
- Update `@actions/cache` to use updated `saveState` and `setOutput` functions from `@actions/core@^1.10.0`
### 3.1.0-beta.1
- Update `@actions/cache` on windows to use gnu tar and zstd by default and fallback to bsdtar and zstd if gnu tar is not available. ([issue](https://github.com/actions/cache/issues/984))
### 3.1.0-beta.2
- Added support for fallback to gzip to restore old caches on windows.
### 3.1.0-beta.3
- Bug fixes for bsdtar fallback if gnutar not available and gzip fallback if cache saved using old cache action on windows.
### 3.2.0-beta.1
- Added two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache.
### 3.2.0
- Released the two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache
### 3.2.1 ### 3.2.1
@@ -56,75 +79,31 @@
- Added support for fallback to gzip to restore old caches on windows. - Added support for fallback to gzip to restore old caches on windows.
- Added logs for cache version in case of a cache miss. - Added logs for cache version in case of a cache miss.
### 3.2.0 ### 3.2.2
- Released the two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache - Reverted the changes made in 3.2.1 to use gnu tar and zstd by default on windows.
### 3.2.0-beta.1 ### 3.2.3
- Added two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache. - Support cross os caching on Windows as an opt-in feature.
- Fix issue with symlink restoration on Windows for cross-os caches.
### 3.1.0-beta.3 ### 3.2.4
- Bug fixes for bsdtar fallback if gnutar not available and gzip fallback if cache saved using old cache action on windows. - Added option to fail job on cache miss.
### 3.1.0-beta.2 ### 3.2.5
- Added support for fallback to gzip to restore old caches on windows. - Added fix to prevent from setting MYSYS environment variable globally.
### 3.1.0-beta.1 ### 3.2.6
- Update `@actions/cache` on windows to use gnu tar and zstd by default and fallback to bsdtar and zstd if gnu tar is not available. ([issue](https://github.com/actions/cache/issues/984)) - Fix zstd not being used after zstd version upgrade to 1.5.4 on hosted runners.
### 3.0.11 ### 3.3.0
- Update toolkit version to 3.0.5 to include `@actions/core@^1.10.0` - Added option to lookup cache without downloading it.
- Update `@actions/cache` to use updated `saveState` and `setOutput` functions from `@actions/core@^1.10.0`
### 3.0.10 ### 3.3.1
- Fix a bug with sorting inputs. - Reduced segment size to 128MB and segment timeout to 10 minutes to fail fast in case the cache download is stuck.
- Update definition for restore-keys in README.md
### 3.0.9
- Enhanced the warning message for cache unavailablity in case of GHES.
### 3.0.8
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
### 3.0.7
- Fixed [#810](https://github.com/actions/cache/issues/810) - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour.
### 3.0.6
- Fixed [#809](https://github.com/actions/cache/issues/809) - zstd -d: no such file or directory error
- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory
### 3.0.5
- Removed error handling by consuming actions/cache 3.0 toolkit, Now cache server error handling will be done by toolkit. ([PR](https://github.com/actions/cache/pull/834))
### 3.0.4
- Fixed tar creation error while trying to create tar with path as `~/` home folder on `ubuntu-latest`. ([issue](https://github.com/actions/cache/issues/689))
### 3.0.3
- Fixed avoiding empty cache save when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
### 3.0.2
- Added support for dynamic cache size cap on GHES.
### 3.0.1
- Added support for caching from GHES 3.5.
- Fixed download issue for files > 2GB during restore.
### 3.0.0
- Updated minimum runner version support from node 12 -> node 16
+8 -8
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, RefKey } from "../src/constants"; import { Events, RefKey } from "../src/constants";
import { restoreRun } from "../src/restoreImpl"; import run from "../src/restore";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -71,7 +71,7 @@ test("restore with no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -114,7 +114,7 @@ test("restore with restore keys and no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -156,7 +156,7 @@ test("restore with cache found for key", async () => {
return Promise.resolve(key); return Promise.resolve(key);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -201,7 +201,7 @@ test("restore with cache found for restore key", async () => {
return Promise.resolve(restoreKey); return Promise.resolve(restoreKey);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -246,7 +246,7 @@ test("Fail restore when fail on cache miss is enabled and primary + restore keys
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -289,7 +289,7 @@ test("restore when fail on cache miss is enabled and primary key doesn't match r
return Promise.resolve(restoreKey); return Promise.resolve(restoreKey);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -335,7 +335,7 @@ test("restore with fail on cache miss disabled and no cache found", async () =>
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
+15 -31
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, RefKey } from "../src/constants"; import { Events, Inputs, RefKey } from "../src/constants";
import { restoreImpl } from "../src/restoreImpl"; import run from "../src/restoreImpl";
import { StateProvider } from "../src/stateProvider"; import { StateProvider } from "../src/stateProvider";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -60,7 +60,7 @@ test("restore with invalid event outputs warning", async () => {
const invalidEvent = "commit_comment"; const invalidEvent = "commit_comment";
process.env[Events.Key] = invalidEvent; process.env[Events.Key] = invalidEvent;
delete process.env[RefKey]; delete process.env[RefKey];
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(logWarningMock).toHaveBeenCalledWith( expect(logWarningMock).toHaveBeenCalledWith(
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.` `Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
); );
@@ -76,7 +76,7 @@ test("restore without AC available should no-op", async () => {
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
const setCacheHitOutputMock = jest.spyOn(core, "setOutput"); const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(0); expect(restoreCacheMock).toHaveBeenCalledTimes(0);
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
@@ -92,7 +92,7 @@ test("restore on GHES without AC available should no-op", async () => {
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
const setCacheHitOutputMock = jest.spyOn(core, "setOutput"); const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(0); expect(restoreCacheMock).toHaveBeenCalledTimes(0);
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1); expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
@@ -119,7 +119,7 @@ test("restore on GHES with AC available ", async () => {
return Promise.resolve(key); return Promise.resolve(key);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -143,7 +143,7 @@ test("restore on GHES with AC available ", async () => {
test("restore with no path should fail", async () => { test("restore with no path should fail", async () => {
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(0); expect(restoreCacheMock).toHaveBeenCalledTimes(0);
// this input isn't necessary for restore b/c tarball contains entries relative to workspace // this input isn't necessary for restore b/c tarball contains entries relative to workspace
expect(failedMock).not.toHaveBeenCalledWith( expect(failedMock).not.toHaveBeenCalledWith(
@@ -155,7 +155,7 @@ test("restore with no key", async () => {
testUtils.setInput(Inputs.Path, "node_modules"); testUtils.setInput(Inputs.Path, "node_modules");
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(0); expect(restoreCacheMock).toHaveBeenCalledTimes(0);
expect(failedMock).toHaveBeenCalledWith( expect(failedMock).toHaveBeenCalledWith(
"Input required and not supplied: key" "Input required and not supplied: key"
@@ -174,7 +174,7 @@ test("restore with too many keys should fail", async () => {
}); });
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
[path], [path],
@@ -200,7 +200,7 @@ test("restore with large key should fail", async () => {
}); });
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
[path], [path],
@@ -226,7 +226,7 @@ test("restore with invalid key should fail", async () => {
}); });
const failedMock = jest.spyOn(core, "setFailed"); const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache"); const restoreCacheMock = jest.spyOn(cache, "restoreCache");
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
[path], [path],
@@ -260,7 +260,7 @@ test("restore with no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -301,7 +301,7 @@ test("restore with restore keys and no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -341,7 +341,7 @@ test("restore with cache found for key", async () => {
return Promise.resolve(key); return Promise.resolve(key);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -383,7 +383,7 @@ test("restore with cache found for restore key", async () => {
return Promise.resolve(restoreKey); return Promise.resolve(restoreKey);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -424,7 +424,7 @@ test("restore with lookup-only set", async () => {
return Promise.resolve(key); return Promise.resolve(key);
}); });
await restoreImpl(new StateProvider()); await run(new StateProvider());
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -449,19 +449,3 @@ test("restore with lookup-only set", async () => {
); );
expect(failedMock).toHaveBeenCalledTimes(0); expect(failedMock).toHaveBeenCalledTimes(0);
}); });
test("restore failure with earlyExit should call process exit", async () => {
testUtils.setInput(Inputs.Path, "node_modules");
const failedMock = jest.spyOn(core, "setFailed");
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
const processExitMock = jest.spyOn(process, "exit").mockImplementation();
// call restoreImpl with `earlyExit` set to true
await restoreImpl(new StateProvider(), true);
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
expect(failedMock).toHaveBeenCalledWith(
"Input required and not supplied: key"
);
expect(processExitMock).toHaveBeenCalledWith(1);
});
+5 -5
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, RefKey } from "../src/constants"; import { Events, RefKey } from "../src/constants";
import { restoreOnlyRun } from "../src/restoreImpl"; import run from "../src/restoreOnly";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -72,7 +72,7 @@ test("restore with no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreOnlyRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -114,7 +114,7 @@ test("restore with restore keys and no cache found", async () => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}); });
await restoreOnlyRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -153,7 +153,7 @@ test("restore with cache found for key", async () => {
return Promise.resolve(key); return Promise.resolve(key);
}); });
await restoreOnlyRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
@@ -196,7 +196,7 @@ test("restore with cache found for restore key", async () => {
return Promise.resolve(restoreKey); return Promise.resolve(restoreKey);
}); });
await restoreOnlyRun(); await run();
expect(restoreCacheMock).toHaveBeenCalledTimes(1); expect(restoreCacheMock).toHaveBeenCalledTimes(1);
expect(restoreCacheMock).toHaveBeenCalledWith( expect(restoreCacheMock).toHaveBeenCalledWith(
+2 -2
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, RefKey } from "../src/constants"; import { Events, Inputs, RefKey } from "../src/constants";
import { saveRun } from "../src/saveImpl"; import run from "../src/save";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -100,7 +100,7 @@ test("save with valid inputs uploads a cache", async () => {
return Promise.resolve(cacheId); return Promise.resolve(cacheId);
}); });
await saveRun(); await run();
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
+12 -12
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, RefKey } from "../src/constants"; import { Events, Inputs, RefKey } from "../src/constants";
import { saveImpl } from "../src/saveImpl"; import run from "../src/saveImpl";
import { StateProvider } from "../src/stateProvider"; import { StateProvider } from "../src/stateProvider";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -77,7 +77,7 @@ test("save with invalid event outputs warning", async () => {
const invalidEvent = "commit_comment"; const invalidEvent = "commit_comment";
process.env[Events.Key] = invalidEvent; process.env[Events.Key] = invalidEvent;
delete process.env[RefKey]; delete process.env[RefKey];
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(logWarningMock).toHaveBeenCalledWith( expect(logWarningMock).toHaveBeenCalledWith(
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.` `Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
); );
@@ -100,7 +100,7 @@ test("save with no primary key in state outputs warning", async () => {
}); });
const saveCacheMock = jest.spyOn(cache, "saveCache"); const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(saveCacheMock).toHaveBeenCalledTimes(0);
expect(logWarningMock).toHaveBeenCalledWith(`Key is not specified.`); expect(logWarningMock).toHaveBeenCalledWith(`Key is not specified.`);
@@ -115,7 +115,7 @@ test("save without AC available should no-op", async () => {
const saveCacheMock = jest.spyOn(cache, "saveCache"); const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(saveCacheMock).toHaveBeenCalledTimes(0);
}); });
@@ -128,7 +128,7 @@ test("save on ghes without AC available should no-op", async () => {
const saveCacheMock = jest.spyOn(cache, "saveCache"); const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(saveCacheMock).toHaveBeenCalledTimes(0);
}); });
@@ -161,7 +161,7 @@ test("save on GHES with AC available", async () => {
return Promise.resolve(cacheId); return Promise.resolve(cacheId);
}); });
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
@@ -194,7 +194,7 @@ test("save with exact match returns early", async () => {
}); });
const saveCacheMock = jest.spyOn(cache, "saveCache"); const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(saveCacheMock).toHaveBeenCalledTimes(0);
expect(infoMock).toHaveBeenCalledWith( expect(infoMock).toHaveBeenCalledWith(
@@ -221,7 +221,7 @@ test("save with missing input outputs warning", async () => {
}); });
const saveCacheMock = jest.spyOn(cache, "saveCache"); const saveCacheMock = jest.spyOn(cache, "saveCache");
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(0); expect(saveCacheMock).toHaveBeenCalledTimes(0);
expect(logWarningMock).toHaveBeenCalledWith( expect(logWarningMock).toHaveBeenCalledWith(
@@ -259,7 +259,7 @@ test("save with large cache outputs warning", async () => {
); );
}); });
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
@@ -306,7 +306,7 @@ test("save with reserve cache failure outputs warning", async () => {
throw error; throw error;
}); });
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
@@ -349,7 +349,7 @@ test("save with server error outputs warning", async () => {
throw new Error("HTTP Error Occurred"); throw new Error("HTTP Error Occurred");
}); });
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
@@ -392,7 +392,7 @@ test("save with valid inputs uploads a cache", async () => {
return Promise.resolve(cacheId); return Promise.resolve(cacheId);
}); });
await saveImpl(new StateProvider()); await run(new StateProvider());
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
+3 -3
View File
@@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, RefKey } from "../src/constants"; import { Events, Inputs, RefKey } from "../src/constants";
import { saveOnlyRun } from "../src/saveImpl"; import run from "../src/saveOnly";
import * as actionUtils from "../src/utils/actionUtils"; import * as actionUtils from "../src/utils/actionUtils";
import * as testUtils from "../src/utils/testUtils"; import * as testUtils from "../src/utils/testUtils";
@@ -90,7 +90,7 @@ test("save with valid inputs uploads a cache", async () => {
return Promise.resolve(cacheId); return Promise.resolve(cacheId);
}); });
await saveOnlyRun(); await run();
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
@@ -122,7 +122,7 @@ test("save failing logs the warning message", async () => {
return Promise.resolve(cacheId); return Promise.resolve(cacheId);
}); });
await saveOnlyRun(); await run();
expect(saveCacheMock).toHaveBeenCalledTimes(1); expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith( expect(saveCacheMock).toHaveBeenCalledWith(
+2 -6
View File
@@ -26,18 +26,14 @@ inputs:
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache' description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
default: 'false' default: 'false'
required: false required: false
save-always:
description: 'Run the post step to save the cache even if another step before fails'
default: 'false'
required: false
outputs: outputs:
cache-hit: cache-hit:
description: 'A boolean value to indicate an exact match was found for the primary key' description: 'A boolean value to indicate an exact match was found for the primary key'
runs: runs:
using: 'node20' using: 'node16'
main: 'dist/restore/index.js' main: 'dist/restore/index.js'
post: 'dist/save/index.js' post: 'dist/save/index.js'
post-if: "success() || github.event.inputs.save-always" post-if: success()
branding: branding:
icon: 'archive' icon: 'archive'
color: 'gray-dark' color: 'gray-dark'
+28346 -28023
View File
File diff suppressed because one or more lines are too long
+28358 -28024
View File
File diff suppressed because one or more lines are too long
+28367 -28036
View File
File diff suppressed because one or more lines are too long
+28357 -28053
View File
File diff suppressed because one or more lines are too long
+751 -442
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "cache", "name": "cache",
"version": "4.0.2", "version": "3.3.1",
"private": true, "private": true,
"description": "Cache dependencies and build outputs", "description": "Cache dependencies and build outputs",
"main": "dist/restore/index.js", "main": "dist/restore/index.js",
@@ -23,7 +23,7 @@
"author": "GitHub", "author": "GitHub",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/cache": "^3.2.3", "@actions/cache": "^3.2.1",
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@actions/exec": "^1.1.1", "@actions/exec": "^1.1.1",
"@actions/io": "^1.1.2" "@actions/io": "^1.1.2"
@@ -34,7 +34,7 @@
"@types/node": "^16.18.3", "@types/node": "^16.18.3",
"@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"@vercel/ncc": "^0.38.1", "@zeit/ncc": "^0.20.5",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
+1 -1
View File
@@ -31,7 +31,7 @@ outputs:
cache-matched-key: cache-matched-key:
description: 'Key of the cache that was restored, it could either be the primary key on cache-hit or a partial/complete match of one of the restore keys' description: 'Key of the cache that was restored, it could either be the primary key on cache-hit or a partial/complete match of one of the restore keys'
runs: runs:
using: 'node20' using: 'node16'
main: '../dist/restore-only/index.js' main: '../dist/restore-only/index.js'
branding: branding:
icon: 'archive' icon: 'archive'
+1 -1
View File
@@ -16,7 +16,7 @@ inputs:
default: 'false' default: 'false'
required: false required: false
runs: runs:
using: 'node20' using: 'node16'
main: '../dist/save-only/index.js' main: '../dist/save-only/index.js'
branding: branding:
icon: 'archive' icon: 'archive'
+9 -2
View File
@@ -1,3 +1,10 @@
import { restoreRun } from "./restoreImpl"; import restoreImpl from "./restoreImpl";
import { StateProvider } from "./stateProvider";
restoreRun(true); async function run(): Promise<void> {
await restoreImpl(new StateProvider());
}
run();
export default run;
+4 -38
View File
@@ -2,16 +2,11 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, Outputs, State } from "./constants"; import { Events, Inputs, Outputs, State } from "./constants";
import { import { IStateProvider } from "./stateProvider";
IStateProvider,
NullStateProvider,
StateProvider
} from "./stateProvider";
import * as utils from "./utils/actionUtils"; import * as utils from "./utils/actionUtils";
export async function restoreImpl( async function restoreImpl(
stateProvider: IStateProvider, stateProvider: IStateProvider
earlyExit?: boolean | undefined
): Promise<string | undefined> { ): Promise<string | undefined> {
try { try {
if (!utils.isCacheFeatureAvailable()) { if (!utils.isCacheFeatureAvailable()) {
@@ -84,36 +79,7 @@ export async function restoreImpl(
return cacheKey; return cacheKey;
} catch (error: unknown) { } catch (error: unknown) {
core.setFailed((error as Error).message); core.setFailed((error as Error).message);
if (earlyExit) {
process.exit(1);
}
}
}
async function run(
stateProvider: IStateProvider,
earlyExit: boolean | undefined
): Promise<void> {
await restoreImpl(stateProvider, earlyExit);
// node will stay alive if any promises are not resolved,
// which is a possibility if HTTP requests are dangling
// due to retries or timeouts. We know that if we got here
// that all promises that we care about have successfully
// resolved, so simply exit with success.
if (earlyExit) {
process.exit(0);
} }
} }
export async function restoreOnlyRun( export default restoreImpl;
earlyExit?: boolean | undefined
): Promise<void> {
await run(new NullStateProvider(), earlyExit);
}
export async function restoreRun(
earlyExit?: boolean | undefined
): Promise<void> {
await run(new StateProvider(), earlyExit);
}
+9 -2
View File
@@ -1,3 +1,10 @@
import { restoreOnlyRun } from "./restoreImpl"; import restoreImpl from "./restoreImpl";
import { NullStateProvider } from "./stateProvider";
restoreOnlyRun(true); async function run(): Promise<void> {
await restoreImpl(new NullStateProvider());
}
run();
export default run;
+9 -2
View File
@@ -1,3 +1,10 @@
import { saveRun } from "./saveImpl"; import saveImpl from "./saveImpl";
import { StateProvider } from "./stateProvider";
saveRun(true); async function run(): Promise<void> {
await saveImpl(new StateProvider());
}
run();
export default run;
+3 -52
View File
@@ -2,11 +2,7 @@ import * as cache from "@actions/cache";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { Events, Inputs, State } from "./constants"; import { Events, Inputs, State } from "./constants";
import { import { IStateProvider } from "./stateProvider";
IStateProvider,
NullStateProvider,
StateProvider
} from "./stateProvider";
import * as utils from "./utils/actionUtils"; import * as utils from "./utils/actionUtils";
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in // Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
@@ -14,9 +10,7 @@ import * as utils from "./utils/actionUtils";
// throw an uncaught exception. Instead of failing this action, just warn. // throw an uncaught exception. Instead of failing this action, just warn.
process.on("uncaughtException", e => utils.logWarning(e.message)); process.on("uncaughtException", e => utils.logWarning(e.message));
export async function saveImpl( async function saveImpl(stateProvider: IStateProvider): Promise<number | void> {
stateProvider: IStateProvider
): Promise<number | void> {
let cacheId = -1; let cacheId = -1;
try { try {
if (!utils.isCacheFeatureAvailable()) { if (!utils.isCacheFeatureAvailable()) {
@@ -78,47 +72,4 @@ export async function saveImpl(
return cacheId; return cacheId;
} }
export async function saveOnlyRun( export default saveImpl;
earlyExit?: boolean | undefined
): Promise<void> {
try {
const cacheId = await saveImpl(new NullStateProvider());
if (cacheId === -1) {
core.warning(`Cache save failed.`);
}
} catch (err) {
console.error(err);
if (earlyExit) {
process.exit(1);
}
}
// node will stay alive if any promises are not resolved,
// which is a possibility if HTTP requests are dangling
// due to retries or timeouts. We know that if we got here
// that all promises that we care about have successfully
// resolved, so simply exit with success.
if (earlyExit) {
process.exit(0);
}
}
export async function saveRun(earlyExit?: boolean | undefined): Promise<void> {
try {
await saveImpl(new StateProvider());
} catch (err) {
console.error(err);
if (earlyExit) {
process.exit(1);
}
}
// node will stay alive if any promises are not resolved,
// which is a possibility if HTTP requests are dangling
// due to retries or timeouts. We know that if we got here
// that all promises that we care about have successfully
// resolved, so simply exit with success.
if (earlyExit) {
process.exit(0);
}
}
+14 -2
View File
@@ -1,3 +1,15 @@
import { saveOnlyRun } from "./saveImpl"; import * as core from "@actions/core";
saveOnlyRun(true); import saveImpl from "./saveImpl";
import { NullStateProvider } from "./stateProvider";
async function run(): Promise<void> {
const cacheId = await saveImpl(new NullStateProvider());
if (cacheId === -1) {
core.warning(`Cache save failed.`);
}
}
run();
export default run;