mirror of
https://github.com/actions/cache.git
synced 2025-06-25 20:01:11 +02:00
Compare commits
21 Commits
v3.2.0-bet
...
kotewar/st
Author | SHA1 | Date | |
---|---|---|---|
f46bb21315 | |||
58c146cc91 | |||
6fd2d4538c | |||
1f414295fe | |||
2d5e079d9e | |||
667e98af5a | |||
5b7eeecaeb | |||
365406cb70 | |||
d6217569d5 | |||
84e54000da | |||
4723a57e26 | |||
d1507cccba | |||
3337563725 | |||
60c7666709 | |||
b053f2b699 | |||
501277cfd7 | |||
c1a5de879e | |||
9b0be58822 | |||
c17f4bf466 | |||
35f35f44e8 | |||
ca1c035094 |
@ -6,7 +6,7 @@
|
|||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
// "forwardPorts": [],
|
// "forwardPorts": [],
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
"postCreateCommand": "npm install && npm run build"
|
"postCreateCommand": "npm install"
|
||||||
// Configure tool-specific properties.
|
// Configure tool-specific properties.
|
||||||
// "customizations": {},
|
// "customizations": {},
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
36
.github/workflows/codeql.yml
vendored
36
.github/workflows/codeql.yml
vendored
@ -8,45 +8,39 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL-Build:
|
CodeQL-Build:
|
||||||
|
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
||||||
# CodeQL runs on ubuntu-latest and windows-latest
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# required for all workflows
|
||||||
|
security-events: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
# We must fetch at least the immediate parents so that if this is
|
|
||||||
# a pull request then we can checkout the head.
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
# If this run was triggered by a pull request event, then checkout
|
|
||||||
# the head of the pull request instead of the merge commit.
|
|
||||||
- run: git checkout HEAD^2
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
# Override language selection by uncommenting this and choosing your languages
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
# with:
|
# with:
|
||||||
# languages: go, javascript, csharp, python, cpp, java
|
# languages: go, javascript, csharp, python, cpp, java, ruby
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below).
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following
|
||||||
# and modify them (or add more) to build your code if your project
|
# three lines and modify them (or add more) to build your code if your
|
||||||
# uses a compiled language
|
# project uses a compiled language
|
||||||
|
|
||||||
#- run: |
|
#- run: |
|
||||||
# make bootstrap
|
# make bootstrap
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
2
.licenses/npm/@actions/cache.dep.yml
generated
2
.licenses/npm/@actions/cache.dep.yml
generated
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: "@actions/cache"
|
name: "@actions/cache"
|
||||||
version: 3.0.5
|
version: 3.1.2
|
||||||
type: npm
|
type: npm
|
||||||
summary:
|
summary:
|
||||||
homepage:
|
homepage:
|
||||||
|
@ -27,6 +27,8 @@ See ["Caching dependencies to speed up workflows"](https://docs.github.com/en/ac
|
|||||||
* Fixed the download stuck problem by introducing a timeout of 1 hour for cache downloads.
|
* Fixed the download stuck problem by introducing a timeout of 1 hour for cache downloads.
|
||||||
* Fix zstd not working for windows on gnu tar in issues.
|
* Fix zstd not working for windows on gnu tar in issues.
|
||||||
* 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.
|
* 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.
|
||||||
|
* Two new actions available for granular control over caches - [restore](restore/action.yml) and [save](save/action.yml)
|
||||||
|
* Support cross-os caching as an opt-in feature. See [Cross OS caching](./tips-and-workarounds.md#cross-os-cache) for more info.
|
||||||
|
|
||||||
Refer [here](https://github.com/actions/cache/blob/v2/README.md) for previous versions
|
Refer [here](https://github.com/actions/cache/blob/v2/README.md) for previous versions
|
||||||
|
|
||||||
@ -42,9 +44,10 @@ If you are using this inside a container, a POSIX-compliant `tar` needs to be in
|
|||||||
* `path` - A list of files, directories, and wildcard patterns to cache and restore. See [`@actions/glob`](https://github.com/actions/toolkit/tree/main/packages/glob) for supported patterns.
|
* `path` - A list of files, directories, and wildcard patterns to cache and restore. See [`@actions/glob`](https://github.com/actions/toolkit/tree/main/packages/glob) for supported patterns.
|
||||||
* `key` - An explicit key for restoring and saving the cache
|
* `key` - An explicit key for restoring and saving the cache
|
||||||
* `restore-keys` - An ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key.
|
* `restore-keys` - An ordered list of prefix-matched keys to use for restoring stale cache if no cache hit occurred for key.
|
||||||
|
* `enableCrossOsArchive` - An optional boolean when enabled, allows Windows runners to save or restore caches that can be restored or saved respectively on other platforms. Default: false
|
||||||
|
|
||||||
#### Environment Variables
|
#### Environment Variables
|
||||||
* `SEGMENT_DOWNLOAD_TIMEOUT_MINS` - Segment download timeout (in minutes, default `60`) to abort download of the segment if not completed in the defined number of minutes. [Read more](https://github.com/actions/cache/blob/main/workarounds.md#cache-segment-restore-timeout)
|
* `SEGMENT_DOWNLOAD_TIMEOUT_MINS` - Segment download timeout (in minutes, default `60`) to abort download of the segment if not completed in the defined number of minutes. [Read more](https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout)
|
||||||
|
|
||||||
### Outputs
|
### Outputs
|
||||||
|
|
||||||
@ -120,6 +123,7 @@ See [Examples](examples.md) for a list of `actions/cache` implementations for us
|
|||||||
- [Swift, Objective-C - Carthage](./examples.md#swift-objective-c---carthage)
|
- [Swift, Objective-C - Carthage](./examples.md#swift-objective-c---carthage)
|
||||||
- [Swift, Objective-C - CocoaPods](./examples.md#swift-objective-c---cocoapods)
|
- [Swift, Objective-C - CocoaPods](./examples.md#swift-objective-c---cocoapods)
|
||||||
- [Swift - Swift Package Manager](./examples.md#swift---swift-package-manager)
|
- [Swift - Swift Package Manager](./examples.md#swift---swift-package-manager)
|
||||||
|
- [Swift - Mint](./examples.md#swift---mint)
|
||||||
|
|
||||||
## Creating a cache key
|
## Creating a cache key
|
||||||
|
|
||||||
@ -243,7 +247,7 @@ Following are some of the known practices/workarounds which community has used t
|
|||||||
- [Cache segment restore timeout](./tips-and-workarounds.md#cache-segment-restore-timeout)
|
- [Cache segment restore timeout](./tips-and-workarounds.md#cache-segment-restore-timeout)
|
||||||
- [Update a cache](./tips-and-workarounds.md#update-a-cache)
|
- [Update a cache](./tips-and-workarounds.md#update-a-cache)
|
||||||
- [Use cache across feature branches](./tips-and-workarounds.md#use-cache-across-feature-branches)
|
- [Use cache across feature branches](./tips-and-workarounds.md#use-cache-across-feature-branches)
|
||||||
- [Improving cache restore performance on Windows/Using cross-os caching](./tips-and-workarounds.md#improving-cache-restore-performance-on-windows-using-cross-os-caching)
|
- [Cross OS cache](./tips-and-workarounds.md#cross-os-cache)
|
||||||
- [Force deletion of caches overriding default cache eviction policy](./tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy)
|
- [Force deletion of caches overriding default cache eviction policy](./tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy)
|
||||||
|
|
||||||
#### Windows environment variables
|
#### Windows environment variables
|
||||||
|
15
RELEASES.md
15
RELEASES.md
@ -52,3 +52,18 @@
|
|||||||
|
|
||||||
### 3.2.0-beta.1
|
### 3.2.0-beta.1
|
||||||
- Added two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache.
|
- 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
|
||||||
|
- 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))
|
||||||
|
- Added support for fallback to gzip to restore old caches on windows.
|
||||||
|
- Added logs for cache version in case of a cache miss.
|
||||||
|
|
||||||
|
### 3.2.2
|
||||||
|
- Reverted the changes made in 3.2.1 to use gnu tar and zstd by default on windows.
|
||||||
|
|
||||||
|
### 3.2.3
|
||||||
|
- Support cross os caching on Windows as an opt-in feature.
|
||||||
|
- Fix issue with symlink restoration on Windows for cross-os caches.
|
@ -174,6 +174,26 @@ test("getInputAsInt throws if required and value missing", () => {
|
|||||||
).toThrowError();
|
).toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("getInputAsBool returns false if input not set", () => {
|
||||||
|
expect(actionUtils.getInputAsBool("undefined")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getInputAsBool returns value if input is valid", () => {
|
||||||
|
testUtils.setInput("foo", "true");
|
||||||
|
expect(actionUtils.getInputAsBool("foo")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getInputAsBool returns false if input is invalid or NaN", () => {
|
||||||
|
testUtils.setInput("foo", "bar");
|
||||||
|
expect(actionUtils.getInputAsBool("foo")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("getInputAsBool throws if required and value missing", () => {
|
||||||
|
expect(() =>
|
||||||
|
actionUtils.getInputAsBool("undefined2", { required: true })
|
||||||
|
).toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
test("isCacheFeatureAvailable for ac enabled", () => {
|
test("isCacheFeatureAvailable for ac enabled", () => {
|
||||||
jest.spyOn(cache, "isFeatureAvailable").mockImplementation(() => true);
|
jest.spyOn(cache, "isFeatureAvailable").mockImplementation(() => true);
|
||||||
|
|
||||||
|
@ -27,9 +27,17 @@ beforeAll(() => {
|
|||||||
return actualUtils.getInputAsArray(name, options);
|
return actualUtils.getInputAsArray(name, options);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
||||||
|
return actualUtils.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
process.env[Events.Key] = Events.Push;
|
process.env[Events.Key] = Events.Push;
|
||||||
process.env[RefKey] = "refs/heads/feature-branch";
|
process.env[RefKey] = "refs/heads/feature-branch";
|
||||||
|
|
||||||
@ -50,7 +58,8 @@ test("restore with no cache found", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -65,7 +74,7 @@ test("restore with no cache found", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(stateMock).toHaveBeenCalledTimes(1);
|
expect(stateMock).toHaveBeenCalledTimes(1);
|
||||||
@ -84,7 +93,8 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -99,7 +109,13 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(stateMock).toHaveBeenCalledTimes(1);
|
expect(stateMock).toHaveBeenCalledTimes(1);
|
||||||
@ -116,7 +132,8 @@ test("restore with cache found for key", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -132,7 +149,7 @@ test("restore with cache found for key", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_RESULT", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_RESULT", key);
|
||||||
@ -152,7 +169,8 @@ test("restore with cache found for restore key", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -168,7 +186,13 @@ test("restore with cache found for restore key", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_RESULT", restoreKey);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_RESULT", restoreKey);
|
||||||
|
@ -28,9 +28,17 @@ beforeAll(() => {
|
|||||||
return actualUtils.getInputAsArray(name, options);
|
return actualUtils.getInputAsArray(name, options);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
const actualUtils = jest.requireActual("../src/utils/actionUtils");
|
||||||
|
return actualUtils.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
process.env[Events.Key] = Events.Push;
|
process.env[Events.Key] = Events.Push;
|
||||||
process.env[RefKey] = "refs/heads/feature-branch";
|
process.env[RefKey] = "refs/heads/feature-branch";
|
||||||
|
|
||||||
@ -97,7 +105,8 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -113,7 +122,7 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
@ -152,13 +161,20 @@ test("restore with too many keys should fail", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys
|
restoreKeys,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
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 run(new StateProvider());
|
await run(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, restoreKeys);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
restoreKeys,
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
expect(failedMock).toHaveBeenCalledWith(
|
expect(failedMock).toHaveBeenCalledWith(
|
||||||
`Key Validation Error: Keys are limited to a maximum of 10.`
|
`Key Validation Error: Keys are limited to a maximum of 10.`
|
||||||
);
|
);
|
||||||
@ -169,13 +185,14 @@ test("restore with large key should fail", async () => {
|
|||||||
const key = "foo".repeat(512); // Over the 512 character limit
|
const key = "foo".repeat(512); // Over the 512 character limit
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
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 run(new StateProvider());
|
await run(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
expect(failedMock).toHaveBeenCalledWith(
|
expect(failedMock).toHaveBeenCalledWith(
|
||||||
`Key Validation Error: ${key} cannot be larger than 512 characters.`
|
`Key Validation Error: ${key} cannot be larger than 512 characters.`
|
||||||
);
|
);
|
||||||
@ -186,13 +203,14 @@ test("restore with invalid key should fail", async () => {
|
|||||||
const key = "comma,comma";
|
const key = "comma,comma";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
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 run(new StateProvider());
|
await run(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
expect(failedMock).toHaveBeenCalledWith(
|
expect(failedMock).toHaveBeenCalledWith(
|
||||||
`Key Validation Error: ${key} cannot contain commas.`
|
`Key Validation Error: ${key} cannot contain commas.`
|
||||||
);
|
);
|
||||||
@ -203,7 +221,8 @@ test("restore with no cache found", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -218,7 +237,7 @@ test("restore with no cache found", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
@ -235,7 +254,8 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -250,7 +270,13 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
@ -265,7 +291,8 @@ test("restore with cache found for key", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -281,7 +308,7 @@ test("restore with cache found for key", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
@ -298,7 +325,8 @@ test("restore with cache found for restore key", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -314,7 +342,13 @@ test("restore with cache found for restore key", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
expect(stateMock).toHaveBeenCalledWith("CACHE_KEY", key);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
|
@ -27,9 +27,18 @@ beforeAll(() => {
|
|||||||
return actualUtils.getInputAsArray(name, options);
|
return actualUtils.getInputAsArray(name, options);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
return jest
|
||||||
|
.requireActual("../src/utils/actionUtils")
|
||||||
|
.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
process.env[Events.Key] = Events.Push;
|
process.env[Events.Key] = Events.Push;
|
||||||
process.env[RefKey] = "refs/heads/feature-branch";
|
process.env[RefKey] = "refs/heads/feature-branch";
|
||||||
|
|
||||||
@ -50,7 +59,8 @@ test("restore with no cache found", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -65,7 +75,7 @@ test("restore with no cache found", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
||||||
expect(outputMock).toHaveBeenCalledTimes(1);
|
expect(outputMock).toHaveBeenCalledTimes(1);
|
||||||
@ -83,7 +93,8 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -98,7 +109,13 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
@ -113,7 +130,8 @@ test("restore with cache found for key", async () => {
|
|||||||
const key = "node-test";
|
const key = "node-test";
|
||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key
|
key,
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -128,7 +146,7 @@ test("restore with cache found for key", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, []);
|
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [], {}, false);
|
||||||
|
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-hit", "true");
|
expect(outputMock).toHaveBeenCalledWith("cache-hit", "true");
|
||||||
@ -147,7 +165,8 @@ test("restore with cache found for restore key", async () => {
|
|||||||
testUtils.setInputs({
|
testUtils.setInputs({
|
||||||
path: path,
|
path: path,
|
||||||
key,
|
key,
|
||||||
restoreKeys: [restoreKey]
|
restoreKeys: [restoreKey],
|
||||||
|
enableCrossOsArchive: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const infoMock = jest.spyOn(core, "info");
|
const infoMock = jest.spyOn(core, "info");
|
||||||
@ -162,7 +181,13 @@ test("restore with cache found for restore key", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith([path], key, [restoreKey]);
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
[path],
|
||||||
|
key,
|
||||||
|
[restoreKey],
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
expect(outputMock).toHaveBeenCalledWith("cache-primary-key", key);
|
||||||
expect(outputMock).toHaveBeenCalledWith("cache-hit", "false");
|
expect(outputMock).toHaveBeenCalledWith("cache-hit", "false");
|
||||||
|
@ -35,6 +35,14 @@ beforeAll(() => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
return jest
|
||||||
|
.requireActual("../src/utils/actionUtils")
|
||||||
|
.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
||||||
(key, cacheResult) => {
|
(key, cacheResult) => {
|
||||||
return jest
|
return jest
|
||||||
@ -95,9 +103,14 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey, {
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
[inputPath],
|
||||||
|
primaryKey,
|
||||||
|
{
|
||||||
uploadChunkSize: 4000000
|
uploadChunkSize: 4000000
|
||||||
});
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
@ -32,6 +32,14 @@ beforeAll(() => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
return jest
|
||||||
|
.requireActual("../src/utils/actionUtils")
|
||||||
|
.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
||||||
(key, cacheResult) => {
|
(key, cacheResult) => {
|
||||||
return jest
|
return jest
|
||||||
@ -47,6 +55,7 @@ beforeAll(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
process.env[Events.Key] = Events.Push;
|
process.env[Events.Key] = Events.Push;
|
||||||
process.env[RefKey] = "refs/heads/feature-branch";
|
process.env[RefKey] = "refs/heads/feature-branch";
|
||||||
|
|
||||||
@ -155,9 +164,14 @@ test("save on GHES with AC available", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey, {
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
[inputPath],
|
||||||
|
primaryKey,
|
||||||
|
{
|
||||||
uploadChunkSize: 4000000
|
uploadChunkSize: 4000000
|
||||||
});
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
@ -251,7 +265,8 @@ test("save with large cache outputs warning", async () => {
|
|||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
[inputPath],
|
[inputPath],
|
||||||
primaryKey,
|
primaryKey,
|
||||||
expect.anything()
|
expect.anything(),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
||||||
@ -297,7 +312,8 @@ test("save with reserve cache failure outputs warning", async () => {
|
|||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
[inputPath],
|
[inputPath],
|
||||||
primaryKey,
|
primaryKey,
|
||||||
expect.anything()
|
expect.anything(),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logWarningMock).toHaveBeenCalledWith(
|
||||||
@ -339,7 +355,8 @@ test("save with server error outputs warning", async () => {
|
|||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
[inputPath],
|
[inputPath],
|
||||||
primaryKey,
|
primaryKey,
|
||||||
expect.anything()
|
expect.anything(),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
expect(logWarningMock).toHaveBeenCalledTimes(1);
|
||||||
@ -378,9 +395,14 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
await run(new StateProvider());
|
await run(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey, {
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
[inputPath],
|
||||||
|
primaryKey,
|
||||||
|
{
|
||||||
uploadChunkSize: 4000000
|
uploadChunkSize: 4000000
|
||||||
});
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
@ -11,12 +11,12 @@ jest.mock("@actions/cache");
|
|||||||
jest.mock("../src/utils/actionUtils");
|
jest.mock("../src/utils/actionUtils");
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
|
jest.spyOn(core, "getInput").mockImplementation(name => {
|
||||||
return jest.requireActual("@actions/core").getInput(name, options);
|
return testUtils.getInput(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(core, "setOutput").mockImplementation((key, value) => {
|
jest.spyOn(core, "getState").mockImplementation(name => {
|
||||||
return jest.requireActual("@actions/core").getInput(key, value);
|
return jest.requireActual("@actions/core").getState(name);
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.spyOn(actionUtils, "getInputAsArray").mockImplementation(
|
jest.spyOn(actionUtils, "getInputAsArray").mockImplementation(
|
||||||
@ -35,6 +35,14 @@ beforeAll(() => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
jest.spyOn(actionUtils, "getInputAsBool").mockImplementation(
|
||||||
|
(name, options) => {
|
||||||
|
return jest
|
||||||
|
.requireActual("../src/utils/actionUtils")
|
||||||
|
.getInputAsBool(name, options);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
|
||||||
(key, cacheResult) => {
|
(key, cacheResult) => {
|
||||||
return jest
|
return jest
|
||||||
@ -85,9 +93,47 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith([inputPath], primaryKey, {
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
[inputPath],
|
||||||
|
primaryKey,
|
||||||
|
{
|
||||||
uploadChunkSize: 4000000
|
uploadChunkSize: 4000000
|
||||||
});
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("save failing logs the warning message", async () => {
|
||||||
|
const warningMock = jest.spyOn(core, "warning");
|
||||||
|
|
||||||
|
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
|
||||||
|
|
||||||
|
const inputPath = "node_modules";
|
||||||
|
testUtils.setInput(Inputs.Key, primaryKey);
|
||||||
|
testUtils.setInput(Inputs.Path, inputPath);
|
||||||
|
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
|
||||||
|
|
||||||
|
const cacheId = -1;
|
||||||
|
const saveCacheMock = jest
|
||||||
|
.spyOn(cache, "saveCache")
|
||||||
|
.mockImplementationOnce(() => {
|
||||||
|
return Promise.resolve(cacheId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await run();
|
||||||
|
|
||||||
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
[inputPath],
|
||||||
|
primaryKey,
|
||||||
|
{
|
||||||
|
uploadChunkSize: 4000000
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(warningMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warningMock).toHaveBeenCalledWith("Cache save failed.");
|
||||||
|
});
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, RefKey, State } from "../src/constants";
|
import { Events, Inputs, RefKey, State } from "../src/constants";
|
||||||
import {
|
import {
|
||||||
IStateProvider,
|
IStateProvider,
|
||||||
NullStateProvider,
|
NullStateProvider,
|
||||||
StateProvider
|
StateProvider
|
||||||
} from "../src/stateProvider";
|
} from "../src/stateProvider";
|
||||||
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
jest.mock("@actions/core");
|
jest.mock("@actions/core");
|
||||||
|
|
||||||
@ -25,16 +26,15 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("StateProvider saves states", async () => {
|
test("StateProvider saves states", async () => {
|
||||||
|
const states = new Map<string, string>();
|
||||||
const getStateMock = jest
|
const getStateMock = jest
|
||||||
.spyOn(core, "getState")
|
.spyOn(core, "getState")
|
||||||
.mockImplementation(name =>
|
.mockImplementation(key => states.get(key) || "");
|
||||||
jest.requireActual("@actions/core").getState(name)
|
|
||||||
);
|
|
||||||
|
|
||||||
const saveStateMock = jest
|
const saveStateMock = jest
|
||||||
.spyOn(core, "saveState")
|
.spyOn(core, "saveState")
|
||||||
.mockImplementation((key, value) => {
|
.mockImplementation((key, value) => {
|
||||||
return jest.requireActual("@actions/core").saveState(key, value);
|
states.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
const setOutputMock = jest
|
const setOutputMock = jest
|
||||||
@ -48,41 +48,54 @@ test("StateProvider saves states", async () => {
|
|||||||
const stateProvider: IStateProvider = new StateProvider();
|
const stateProvider: IStateProvider = new StateProvider();
|
||||||
stateProvider.setState("stateKey", "stateValue");
|
stateProvider.setState("stateKey", "stateValue");
|
||||||
stateProvider.setState(State.CacheMatchedKey, cacheMatchedKey);
|
stateProvider.setState(State.CacheMatchedKey, cacheMatchedKey);
|
||||||
stateProvider.getState("stateKey");
|
const stateValue = stateProvider.getState("stateKey");
|
||||||
stateProvider.getCacheState();
|
const cacheStateValue = stateProvider.getCacheState();
|
||||||
|
|
||||||
|
expect(stateValue).toBe("stateValue");
|
||||||
|
expect(cacheStateValue).toBe(cacheMatchedKey);
|
||||||
expect(getStateMock).toHaveBeenCalledTimes(2);
|
expect(getStateMock).toHaveBeenCalledTimes(2);
|
||||||
expect(saveStateMock).toHaveBeenCalledTimes(2);
|
expect(saveStateMock).toHaveBeenCalledTimes(2);
|
||||||
expect(setOutputMock).toHaveBeenCalledTimes(0);
|
expect(setOutputMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("NullStateProvider saves outputs", async () => {
|
test("NullStateProvider saves outputs", async () => {
|
||||||
|
const states = new Map<string, string>();
|
||||||
|
|
||||||
|
const getInputMock = jest
|
||||||
|
.spyOn(core, "getInput")
|
||||||
|
.mockImplementation(key => testUtils.getInput(key));
|
||||||
|
|
||||||
const getStateMock = jest
|
const getStateMock = jest
|
||||||
.spyOn(core, "getState")
|
.spyOn(core, "getState")
|
||||||
.mockImplementation(name =>
|
.mockImplementation(key => {
|
||||||
jest.requireActual("@actions/core").getState(name)
|
return jest.requireActual("@actions/core").getState(key);
|
||||||
);
|
});
|
||||||
|
|
||||||
const setOutputMock = jest
|
const setOutputMock = jest
|
||||||
.spyOn(core, "setOutput")
|
.spyOn(core, "setOutput")
|
||||||
.mockImplementation((key, value) => {
|
.mockImplementation((key, value) => {
|
||||||
return jest.requireActual("@actions/core").setOutput(key, value);
|
states.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
const saveStateMock = jest
|
const saveStateMock = jest
|
||||||
.spyOn(core, "saveState")
|
.spyOn(core, "saveState")
|
||||||
.mockImplementation((key, value) => {
|
.mockImplementation((key, value) => {
|
||||||
return jest.requireActual("@actions/core").saveState(key, value);
|
states.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
const cacheMatchedKey = "node-cache";
|
const cacheMatchedKey = "node-cache";
|
||||||
|
const cachePrimaryKey = "primary-key";
|
||||||
const nullStateProvider: IStateProvider = new NullStateProvider();
|
const nullStateProvider: IStateProvider = new NullStateProvider();
|
||||||
nullStateProvider.setState(State.CacheMatchedKey, "outputValue");
|
testUtils.setInput(Inputs.Key, cachePrimaryKey);
|
||||||
nullStateProvider.setState(State.CachePrimaryKey, cacheMatchedKey);
|
nullStateProvider.setState(State.CachePrimaryKey, cachePrimaryKey);
|
||||||
nullStateProvider.getState("outputKey");
|
nullStateProvider.setState(State.CacheMatchedKey, cacheMatchedKey);
|
||||||
nullStateProvider.getCacheState();
|
const output1 = nullStateProvider.getState(State.CachePrimaryKey);
|
||||||
|
const output2 = nullStateProvider.getCacheState();
|
||||||
|
|
||||||
expect(getStateMock).toHaveBeenCalledTimes(0);
|
expect(getStateMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(getInputMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(output1).toBe("primary-key");
|
||||||
|
expect(output2).toBe(undefined);
|
||||||
expect(setOutputMock).toHaveBeenCalledTimes(2);
|
expect(setOutputMock).toHaveBeenCalledTimes(2);
|
||||||
expect(saveStateMock).toHaveBeenCalledTimes(0);
|
expect(saveStateMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
@ -14,6 +14,10 @@ inputs:
|
|||||||
upload-chunk-size:
|
upload-chunk-size:
|
||||||
description: 'The chunk size used to split up large files during upload, in bytes'
|
description: 'The chunk size used to split up large files during upload, in bytes'
|
||||||
required: false
|
required: false
|
||||||
|
enableCrossOsArchive:
|
||||||
|
description: 'An optional boolean when enabled, allows windows runners to save or restore caches that can be restored or saved respectively on other platforms'
|
||||||
|
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'
|
||||||
|
108
dist/restore-only/index.js
vendored
108
dist/restore-only/index.js
vendored
@ -3383,7 +3383,6 @@ const crypto = __importStar(__webpack_require__(417));
|
|||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const url_1 = __webpack_require__(414);
|
const url_1 = __webpack_require__(414);
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
const downloadUtils_1 = __webpack_require__(251);
|
const downloadUtils_1 = __webpack_require__(251);
|
||||||
const options_1 = __webpack_require__(538);
|
const options_1 = __webpack_require__(538);
|
||||||
const requestUtils_1 = __webpack_require__(899);
|
const requestUtils_1 = __webpack_require__(899);
|
||||||
@ -3413,10 +3412,17 @@ function createHttpClient() {
|
|||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion(paths, compressionMethod) {
|
function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) {
|
||||||
const components = paths.concat(!compressionMethod || compressionMethod === constants_1.CompressionMethod.Gzip
|
const components = paths;
|
||||||
? []
|
// Add compression method to cache version to restore
|
||||||
: [compressionMethod]);
|
// compressed cache as per compression method
|
||||||
|
if (compressionMethod) {
|
||||||
|
components.push(compressionMethod);
|
||||||
|
}
|
||||||
|
// Only check for windows platforms if enableCrossOsArchive is false
|
||||||
|
if (process.platform === 'win32' && !enableCrossOsArchive) {
|
||||||
|
components.push('windows-only');
|
||||||
|
}
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
components.push(versionSalt);
|
components.push(versionSalt);
|
||||||
return crypto
|
return crypto
|
||||||
@ -3428,11 +3434,15 @@ exports.getCacheVersion = getCacheVersion;
|
|||||||
function getCacheEntry(keys, paths, options) {
|
function getCacheEntry(keys, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||||
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
if (response.statusCode === 204) {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
|
if (response.statusCode === 204) {
|
||||||
|
// List cache for primary key only if cache miss occurs
|
||||||
|
if (core.isDebug()) {
|
||||||
|
yield printCachesListForDiagnostics(keys[0], httpClient, version);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
||||||
@ -3451,6 +3461,22 @@ function getCacheEntry(keys, paths, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getCacheEntry = getCacheEntry;
|
exports.getCacheEntry = getCacheEntry;
|
||||||
|
function printCachesListForDiagnostics(key, httpClient, version) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const resource = `caches?key=${encodeURIComponent(key)}`;
|
||||||
|
const response = yield requestUtils_1.retryTypedResponse('listCache', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const cacheListResult = response.result;
|
||||||
|
const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.totalCount;
|
||||||
|
if (totalCount && totalCount > 0) {
|
||||||
|
core.debug(`No matching cache found for cache key '${key}', version '${version} and scope ${process.env['GITHUB_REF']}. There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \nOther caches with similar key:`);
|
||||||
|
for (const cacheEntry of (cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.artifactCaches) || []) {
|
||||||
|
core.debug(`Cache Key: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheKey}, Cache Version: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheVersion}, Cache Scope: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.scope}, Cache Created: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.creationTime}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function downloadCache(archiveLocation, archivePath, options) {
|
function downloadCache(archiveLocation, archivePath, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const archiveUrl = new url_1.URL(archiveLocation);
|
const archiveUrl = new url_1.URL(archiveLocation);
|
||||||
@ -3471,7 +3497,7 @@ exports.downloadCache = downloadCache;
|
|||||||
function reserveCache(key, paths, options) {
|
function reserveCache(key, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version,
|
version,
|
||||||
@ -4951,7 +4977,8 @@ var Inputs;
|
|||||||
Inputs["Key"] = "key";
|
Inputs["Key"] = "key";
|
||||||
Inputs["Path"] = "path";
|
Inputs["Path"] = "path";
|
||||||
Inputs["RestoreKeys"] = "restore-keys";
|
Inputs["RestoreKeys"] = "restore-keys";
|
||||||
Inputs["UploadChunkSize"] = "upload-chunk-size"; // Input for cache, save action
|
Inputs["UploadChunkSize"] = "upload-chunk-size";
|
||||||
|
Inputs["EnableCrossOsArchive"] = "enableCrossOsArchive"; // Input for cache, restore, save action
|
||||||
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
||||||
var Outputs;
|
var Outputs;
|
||||||
(function (Outputs) {
|
(function (Outputs) {
|
||||||
@ -9386,15 +9413,24 @@ exports.StateProvider = StateProvider;
|
|||||||
class NullStateProvider extends StateProviderBase {
|
class NullStateProvider extends StateProviderBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
this.stateToInputMap = new Map([
|
||||||
|
[constants_1.State.CachePrimaryKey, constants_1.Inputs.Key]
|
||||||
|
]);
|
||||||
this.stateToOutputMap = new Map([
|
this.stateToOutputMap = new Map([
|
||||||
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
||||||
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
||||||
]);
|
]);
|
||||||
this.setState = (key, value) => {
|
this.setState = (key, value) => {
|
||||||
|
if (this.stateToOutputMap.has(key)) {
|
||||||
core.setOutput(this.stateToOutputMap.get(key), value);
|
core.setOutput(this.stateToOutputMap.get(key), value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.getState = (key) => {
|
||||||
|
if (!this.stateToInputMap.has(key)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return core.getInput(this.stateToInputMap.get(key));
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.NullStateProvider = NullStateProvider;
|
exports.NullStateProvider = NullStateProvider;
|
||||||
@ -10047,7 +10083,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
exports.isCacheFeatureAvailable = exports.getInputAsBool = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
||||||
const cache = __importStar(__webpack_require__(692));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const constants_1 = __webpack_require__(196);
|
const constants_1 = __webpack_require__(196);
|
||||||
@ -10090,6 +10126,11 @@ function getInputAsInt(name, options) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
exports.getInputAsInt = getInputAsInt;
|
exports.getInputAsInt = getInputAsInt;
|
||||||
|
function getInputAsBool(name, options) {
|
||||||
|
const result = core.getInput(name, options);
|
||||||
|
return result.toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
exports.getInputAsBool = getInputAsBool;
|
||||||
function isCacheFeatureAvailable() {
|
function isCacheFeatureAvailable() {
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
@ -38197,12 +38238,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
|
const core_1 = __webpack_require__(470);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
const constants_1 = __webpack_require__(931);
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
core_1.exportVariable('MSYS', 'winsymlinks:nativestrict');
|
||||||
// Returns tar path and type: BSD or GNU
|
// Returns tar path and type: BSD or GNU
|
||||||
function getTarPath() {
|
function getTarPath() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -38329,7 +38372,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d --long=30 -o',
|
'zstd -d --long=30 --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38340,7 +38383,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d -o',
|
'zstd -d --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38366,7 +38409,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 --long=30 -o',
|
'zstd -T0 --long=30 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38377,7 +38420,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 -o',
|
'zstd -T0 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -47175,7 +47218,6 @@ const path = __importStar(__webpack_require__(622));
|
|||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const cacheHttpClient = __importStar(__webpack_require__(114));
|
const cacheHttpClient = __importStar(__webpack_require__(114));
|
||||||
const tar_1 = __webpack_require__(434);
|
const tar_1 = __webpack_require__(434);
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
class ValidationError extends Error {
|
class ValidationError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
@ -47222,9 +47264,10 @@ exports.isFeatureAvailable = isFeatureAvailable;
|
|||||||
* @param primaryKey an explicit key for restoring the cache
|
* @param primaryKey an explicit key for restoring the cache
|
||||||
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
||||||
* @param downloadOptions cache download options
|
* @param downloadOptions cache download options
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform
|
||||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||||
*/
|
*/
|
||||||
function restoreCache(paths, primaryKey, restoreKeys, options) {
|
function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
restoreKeys = restoreKeys || [];
|
restoreKeys = restoreKeys || [];
|
||||||
@ -47237,32 +47280,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
checkKey(key);
|
checkKey(key);
|
||||||
}
|
}
|
||||||
let cacheEntry;
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
let compressionMethod = yield utils.getCompressionMethod();
|
|
||||||
let archivePath = '';
|
let archivePath = '';
|
||||||
try {
|
try {
|
||||||
// path are needed to compute version
|
// path are needed to compute version
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||||
compressionMethod
|
compressionMethod,
|
||||||
|
enableCrossOsArchive
|
||||||
});
|
});
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||||
// This is to support the old cache entry created by gzip on windows.
|
|
||||||
if (process.platform === 'win32' &&
|
|
||||||
compressionMethod !== constants_1.CompressionMethod.Gzip) {
|
|
||||||
compressionMethod = constants_1.CompressionMethod.Gzip;
|
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
|
||||||
compressionMethod
|
|
||||||
});
|
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
core.debug("Couldn't find cache entry with zstd compression, falling back to gzip compression.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
// Download the cache from the cache entry
|
// Download the cache from the cache entry
|
||||||
@ -47304,10 +47333,11 @@ exports.restoreCache = restoreCache;
|
|||||||
*
|
*
|
||||||
* @param paths a list of file paths to be cached
|
* @param paths a list of file paths to be cached
|
||||||
* @param key an explicit key for restoring the cache
|
* @param key an explicit key for restoring the cache
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform
|
||||||
* @param options cache upload options
|
* @param options cache upload options
|
||||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||||
*/
|
*/
|
||||||
function saveCache(paths, key, options) {
|
function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||||
var _a, _b, _c, _d, _e;
|
var _a, _b, _c, _d, _e;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
@ -47338,6 +47368,7 @@ function saveCache(paths, key, options) {
|
|||||||
core.debug('Reserving Cache');
|
core.debug('Reserving Cache');
|
||||||
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
|
enableCrossOsArchive,
|
||||||
cacheSize: archiveFileSize
|
cacheSize: archiveFileSize
|
||||||
});
|
});
|
||||||
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
||||||
@ -50472,7 +50503,8 @@ function restoreImpl(stateProvider) {
|
|||||||
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys);
|
const enableCrossOsArchive = utils.getInputAsBool(constants_1.Inputs.EnableCrossOsArchive);
|
||||||
|
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys, {}, enableCrossOsArchive);
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
core.info(`Cache not found for input keys: ${[
|
core.info(`Cache not found for input keys: ${[
|
||||||
primaryKey,
|
primaryKey,
|
||||||
|
108
dist/restore/index.js
vendored
108
dist/restore/index.js
vendored
@ -3383,7 +3383,6 @@ const crypto = __importStar(__webpack_require__(417));
|
|||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const url_1 = __webpack_require__(414);
|
const url_1 = __webpack_require__(414);
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
const downloadUtils_1 = __webpack_require__(251);
|
const downloadUtils_1 = __webpack_require__(251);
|
||||||
const options_1 = __webpack_require__(538);
|
const options_1 = __webpack_require__(538);
|
||||||
const requestUtils_1 = __webpack_require__(899);
|
const requestUtils_1 = __webpack_require__(899);
|
||||||
@ -3413,10 +3412,17 @@ function createHttpClient() {
|
|||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion(paths, compressionMethod) {
|
function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) {
|
||||||
const components = paths.concat(!compressionMethod || compressionMethod === constants_1.CompressionMethod.Gzip
|
const components = paths;
|
||||||
? []
|
// Add compression method to cache version to restore
|
||||||
: [compressionMethod]);
|
// compressed cache as per compression method
|
||||||
|
if (compressionMethod) {
|
||||||
|
components.push(compressionMethod);
|
||||||
|
}
|
||||||
|
// Only check for windows platforms if enableCrossOsArchive is false
|
||||||
|
if (process.platform === 'win32' && !enableCrossOsArchive) {
|
||||||
|
components.push('windows-only');
|
||||||
|
}
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
components.push(versionSalt);
|
components.push(versionSalt);
|
||||||
return crypto
|
return crypto
|
||||||
@ -3428,11 +3434,15 @@ exports.getCacheVersion = getCacheVersion;
|
|||||||
function getCacheEntry(keys, paths, options) {
|
function getCacheEntry(keys, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||||
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
if (response.statusCode === 204) {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
|
if (response.statusCode === 204) {
|
||||||
|
// List cache for primary key only if cache miss occurs
|
||||||
|
if (core.isDebug()) {
|
||||||
|
yield printCachesListForDiagnostics(keys[0], httpClient, version);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
||||||
@ -3451,6 +3461,22 @@ function getCacheEntry(keys, paths, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getCacheEntry = getCacheEntry;
|
exports.getCacheEntry = getCacheEntry;
|
||||||
|
function printCachesListForDiagnostics(key, httpClient, version) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const resource = `caches?key=${encodeURIComponent(key)}`;
|
||||||
|
const response = yield requestUtils_1.retryTypedResponse('listCache', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const cacheListResult = response.result;
|
||||||
|
const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.totalCount;
|
||||||
|
if (totalCount && totalCount > 0) {
|
||||||
|
core.debug(`No matching cache found for cache key '${key}', version '${version} and scope ${process.env['GITHUB_REF']}. There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \nOther caches with similar key:`);
|
||||||
|
for (const cacheEntry of (cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.artifactCaches) || []) {
|
||||||
|
core.debug(`Cache Key: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheKey}, Cache Version: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheVersion}, Cache Scope: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.scope}, Cache Created: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.creationTime}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function downloadCache(archiveLocation, archivePath, options) {
|
function downloadCache(archiveLocation, archivePath, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const archiveUrl = new url_1.URL(archiveLocation);
|
const archiveUrl = new url_1.URL(archiveLocation);
|
||||||
@ -3471,7 +3497,7 @@ exports.downloadCache = downloadCache;
|
|||||||
function reserveCache(key, paths, options) {
|
function reserveCache(key, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version,
|
version,
|
||||||
@ -4951,7 +4977,8 @@ var Inputs;
|
|||||||
Inputs["Key"] = "key";
|
Inputs["Key"] = "key";
|
||||||
Inputs["Path"] = "path";
|
Inputs["Path"] = "path";
|
||||||
Inputs["RestoreKeys"] = "restore-keys";
|
Inputs["RestoreKeys"] = "restore-keys";
|
||||||
Inputs["UploadChunkSize"] = "upload-chunk-size"; // Input for cache, save action
|
Inputs["UploadChunkSize"] = "upload-chunk-size";
|
||||||
|
Inputs["EnableCrossOsArchive"] = "enableCrossOsArchive"; // Input for cache, restore, save action
|
||||||
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
||||||
var Outputs;
|
var Outputs;
|
||||||
(function (Outputs) {
|
(function (Outputs) {
|
||||||
@ -9386,15 +9413,24 @@ exports.StateProvider = StateProvider;
|
|||||||
class NullStateProvider extends StateProviderBase {
|
class NullStateProvider extends StateProviderBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
this.stateToInputMap = new Map([
|
||||||
|
[constants_1.State.CachePrimaryKey, constants_1.Inputs.Key]
|
||||||
|
]);
|
||||||
this.stateToOutputMap = new Map([
|
this.stateToOutputMap = new Map([
|
||||||
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
||||||
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
||||||
]);
|
]);
|
||||||
this.setState = (key, value) => {
|
this.setState = (key, value) => {
|
||||||
|
if (this.stateToOutputMap.has(key)) {
|
||||||
core.setOutput(this.stateToOutputMap.get(key), value);
|
core.setOutput(this.stateToOutputMap.get(key), value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.getState = (key) => {
|
||||||
|
if (!this.stateToInputMap.has(key)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return core.getInput(this.stateToInputMap.get(key));
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.NullStateProvider = NullStateProvider;
|
exports.NullStateProvider = NullStateProvider;
|
||||||
@ -38110,12 +38146,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
|
const core_1 = __webpack_require__(470);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
const constants_1 = __webpack_require__(931);
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
core_1.exportVariable('MSYS', 'winsymlinks:nativestrict');
|
||||||
// Returns tar path and type: BSD or GNU
|
// Returns tar path and type: BSD or GNU
|
||||||
function getTarPath() {
|
function getTarPath() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -38242,7 +38280,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d --long=30 -o',
|
'zstd -d --long=30 --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38253,7 +38291,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d -o',
|
'zstd -d --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38279,7 +38317,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 --long=30 -o',
|
'zstd -T0 --long=30 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38290,7 +38328,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 -o',
|
'zstd -T0 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38573,7 +38611,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
exports.isCacheFeatureAvailable = exports.getInputAsBool = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
||||||
const cache = __importStar(__webpack_require__(692));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const constants_1 = __webpack_require__(196);
|
const constants_1 = __webpack_require__(196);
|
||||||
@ -38616,6 +38654,11 @@ function getInputAsInt(name, options) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
exports.getInputAsInt = getInputAsInt;
|
exports.getInputAsInt = getInputAsInt;
|
||||||
|
function getInputAsBool(name, options) {
|
||||||
|
const result = core.getInput(name, options);
|
||||||
|
return result.toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
exports.getInputAsBool = getInputAsBool;
|
||||||
function isCacheFeatureAvailable() {
|
function isCacheFeatureAvailable() {
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
@ -47146,7 +47189,6 @@ const path = __importStar(__webpack_require__(622));
|
|||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const cacheHttpClient = __importStar(__webpack_require__(114));
|
const cacheHttpClient = __importStar(__webpack_require__(114));
|
||||||
const tar_1 = __webpack_require__(434);
|
const tar_1 = __webpack_require__(434);
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
class ValidationError extends Error {
|
class ValidationError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
@ -47193,9 +47235,10 @@ exports.isFeatureAvailable = isFeatureAvailable;
|
|||||||
* @param primaryKey an explicit key for restoring the cache
|
* @param primaryKey an explicit key for restoring the cache
|
||||||
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
||||||
* @param downloadOptions cache download options
|
* @param downloadOptions cache download options
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform
|
||||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||||
*/
|
*/
|
||||||
function restoreCache(paths, primaryKey, restoreKeys, options) {
|
function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
restoreKeys = restoreKeys || [];
|
restoreKeys = restoreKeys || [];
|
||||||
@ -47208,32 +47251,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
checkKey(key);
|
checkKey(key);
|
||||||
}
|
}
|
||||||
let cacheEntry;
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
let compressionMethod = yield utils.getCompressionMethod();
|
|
||||||
let archivePath = '';
|
let archivePath = '';
|
||||||
try {
|
try {
|
||||||
// path are needed to compute version
|
// path are needed to compute version
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||||
compressionMethod
|
compressionMethod,
|
||||||
|
enableCrossOsArchive
|
||||||
});
|
});
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||||
// This is to support the old cache entry created by gzip on windows.
|
|
||||||
if (process.platform === 'win32' &&
|
|
||||||
compressionMethod !== constants_1.CompressionMethod.Gzip) {
|
|
||||||
compressionMethod = constants_1.CompressionMethod.Gzip;
|
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
|
||||||
compressionMethod
|
|
||||||
});
|
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
core.debug("Couldn't find cache entry with zstd compression, falling back to gzip compression.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
// Download the cache from the cache entry
|
// Download the cache from the cache entry
|
||||||
@ -47275,10 +47304,11 @@ exports.restoreCache = restoreCache;
|
|||||||
*
|
*
|
||||||
* @param paths a list of file paths to be cached
|
* @param paths a list of file paths to be cached
|
||||||
* @param key an explicit key for restoring the cache
|
* @param key an explicit key for restoring the cache
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform
|
||||||
* @param options cache upload options
|
* @param options cache upload options
|
||||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||||
*/
|
*/
|
||||||
function saveCache(paths, key, options) {
|
function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||||
var _a, _b, _c, _d, _e;
|
var _a, _b, _c, _d, _e;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
@ -47309,6 +47339,7 @@ function saveCache(paths, key, options) {
|
|||||||
core.debug('Reserving Cache');
|
core.debug('Reserving Cache');
|
||||||
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
|
enableCrossOsArchive,
|
||||||
cacheSize: archiveFileSize
|
cacheSize: archiveFileSize
|
||||||
});
|
});
|
||||||
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
||||||
@ -50472,7 +50503,8 @@ function restoreImpl(stateProvider) {
|
|||||||
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys);
|
const enableCrossOsArchive = utils.getInputAsBool(constants_1.Inputs.EnableCrossOsArchive);
|
||||||
|
const cacheKey = yield cache.restoreCache(cachePaths, primaryKey, restoreKeys, {}, enableCrossOsArchive);
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
core.info(`Cache not found for input keys: ${[
|
core.info(`Cache not found for input keys: ${[
|
||||||
primaryKey,
|
primaryKey,
|
||||||
|
144
dist/save-only/index.js
vendored
144
dist/save-only/index.js
vendored
@ -1043,6 +1043,29 @@ class ExecState extends events.EventEmitter {
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
@ -1056,11 +1079,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(__webpack_require__(470));
|
||||||
const saveImpl_1 = __importDefault(__webpack_require__(471));
|
const saveImpl_1 = __importDefault(__webpack_require__(471));
|
||||||
const stateProvider_1 = __webpack_require__(309);
|
const stateProvider_1 = __webpack_require__(309);
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
yield (0, saveImpl_1.default)(new stateProvider_1.NullStateProvider());
|
const cacheId = yield (0, saveImpl_1.default)(new stateProvider_1.NullStateProvider());
|
||||||
|
if (cacheId === -1) {
|
||||||
|
core.warning(`Cache save failed.`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
run();
|
run();
|
||||||
@ -3412,7 +3439,6 @@ const crypto = __importStar(__webpack_require__(417));
|
|||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const url_1 = __webpack_require__(835);
|
const url_1 = __webpack_require__(835);
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
const downloadUtils_1 = __webpack_require__(251);
|
const downloadUtils_1 = __webpack_require__(251);
|
||||||
const options_1 = __webpack_require__(538);
|
const options_1 = __webpack_require__(538);
|
||||||
const requestUtils_1 = __webpack_require__(899);
|
const requestUtils_1 = __webpack_require__(899);
|
||||||
@ -3442,10 +3468,17 @@ function createHttpClient() {
|
|||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion(paths, compressionMethod) {
|
function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) {
|
||||||
const components = paths.concat(!compressionMethod || compressionMethod === constants_1.CompressionMethod.Gzip
|
const components = paths;
|
||||||
? []
|
// Add compression method to cache version to restore
|
||||||
: [compressionMethod]);
|
// compressed cache as per compression method
|
||||||
|
if (compressionMethod) {
|
||||||
|
components.push(compressionMethod);
|
||||||
|
}
|
||||||
|
// Only check for windows platforms if enableCrossOsArchive is false
|
||||||
|
if (process.platform === 'win32' && !enableCrossOsArchive) {
|
||||||
|
components.push('windows-only');
|
||||||
|
}
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
components.push(versionSalt);
|
components.push(versionSalt);
|
||||||
return crypto
|
return crypto
|
||||||
@ -3457,11 +3490,15 @@ exports.getCacheVersion = getCacheVersion;
|
|||||||
function getCacheEntry(keys, paths, options) {
|
function getCacheEntry(keys, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||||
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
if (response.statusCode === 204) {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
|
if (response.statusCode === 204) {
|
||||||
|
// List cache for primary key only if cache miss occurs
|
||||||
|
if (core.isDebug()) {
|
||||||
|
yield printCachesListForDiagnostics(keys[0], httpClient, version);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
||||||
@ -3480,6 +3517,22 @@ function getCacheEntry(keys, paths, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getCacheEntry = getCacheEntry;
|
exports.getCacheEntry = getCacheEntry;
|
||||||
|
function printCachesListForDiagnostics(key, httpClient, version) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const resource = `caches?key=${encodeURIComponent(key)}`;
|
||||||
|
const response = yield requestUtils_1.retryTypedResponse('listCache', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const cacheListResult = response.result;
|
||||||
|
const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.totalCount;
|
||||||
|
if (totalCount && totalCount > 0) {
|
||||||
|
core.debug(`No matching cache found for cache key '${key}', version '${version} and scope ${process.env['GITHUB_REF']}. There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \nOther caches with similar key:`);
|
||||||
|
for (const cacheEntry of (cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.artifactCaches) || []) {
|
||||||
|
core.debug(`Cache Key: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheKey}, Cache Version: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheVersion}, Cache Scope: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.scope}, Cache Created: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.creationTime}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function downloadCache(archiveLocation, archivePath, options) {
|
function downloadCache(archiveLocation, archivePath, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const archiveUrl = new url_1.URL(archiveLocation);
|
const archiveUrl = new url_1.URL(archiveLocation);
|
||||||
@ -3500,7 +3553,7 @@ exports.downloadCache = downloadCache;
|
|||||||
function reserveCache(key, paths, options) {
|
function reserveCache(key, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version,
|
version,
|
||||||
@ -4980,7 +5033,8 @@ var Inputs;
|
|||||||
Inputs["Key"] = "key";
|
Inputs["Key"] = "key";
|
||||||
Inputs["Path"] = "path";
|
Inputs["Path"] = "path";
|
||||||
Inputs["RestoreKeys"] = "restore-keys";
|
Inputs["RestoreKeys"] = "restore-keys";
|
||||||
Inputs["UploadChunkSize"] = "upload-chunk-size"; // Input for cache, save action
|
Inputs["UploadChunkSize"] = "upload-chunk-size";
|
||||||
|
Inputs["EnableCrossOsArchive"] = "enableCrossOsArchive"; // Input for cache, restore, save action
|
||||||
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
||||||
var Outputs;
|
var Outputs;
|
||||||
(function (Outputs) {
|
(function (Outputs) {
|
||||||
@ -9415,15 +9469,24 @@ exports.StateProvider = StateProvider;
|
|||||||
class NullStateProvider extends StateProviderBase {
|
class NullStateProvider extends StateProviderBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
this.stateToInputMap = new Map([
|
||||||
|
[constants_1.State.CachePrimaryKey, constants_1.Inputs.Key]
|
||||||
|
]);
|
||||||
this.stateToOutputMap = new Map([
|
this.stateToOutputMap = new Map([
|
||||||
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
||||||
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
||||||
]);
|
]);
|
||||||
this.setState = (key, value) => {
|
this.setState = (key, value) => {
|
||||||
|
if (this.stateToOutputMap.has(key)) {
|
||||||
core.setOutput(this.stateToOutputMap.get(key), value);
|
core.setOutput(this.stateToOutputMap.get(key), value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.getState = (key) => {
|
||||||
|
if (!this.stateToInputMap.has(key)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return core.getInput(this.stateToInputMap.get(key));
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.NullStateProvider = NullStateProvider;
|
exports.NullStateProvider = NullStateProvider;
|
||||||
@ -38134,12 +38197,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
|
const core_1 = __webpack_require__(470);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
const constants_1 = __webpack_require__(931);
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
core_1.exportVariable('MSYS', 'winsymlinks:nativestrict');
|
||||||
// Returns tar path and type: BSD or GNU
|
// Returns tar path and type: BSD or GNU
|
||||||
function getTarPath() {
|
function getTarPath() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -38266,7 +38331,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d --long=30 -o',
|
'zstd -d --long=30 --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38277,7 +38342,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d -o',
|
'zstd -d --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38303,7 +38368,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 --long=30 -o',
|
'zstd -T0 --long=30 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38314,7 +38379,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 -o',
|
'zstd -T0 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38597,7 +38662,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
exports.isCacheFeatureAvailable = exports.getInputAsBool = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
||||||
const cache = __importStar(__webpack_require__(692));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const constants_1 = __webpack_require__(196);
|
const constants_1 = __webpack_require__(196);
|
||||||
@ -38640,6 +38705,11 @@ function getInputAsInt(name, options) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
exports.getInputAsInt = getInputAsInt;
|
exports.getInputAsInt = getInputAsInt;
|
||||||
|
function getInputAsBool(name, options) {
|
||||||
|
const result = core.getInput(name, options);
|
||||||
|
return result.toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
exports.getInputAsBool = getInputAsBool;
|
||||||
function isCacheFeatureAvailable() {
|
function isCacheFeatureAvailable() {
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
@ -41092,6 +41162,7 @@ const utils = __importStar(__webpack_require__(443));
|
|||||||
process.on("uncaughtException", e => utils.logWarning(e.message));
|
process.on("uncaughtException", e => utils.logWarning(e.message));
|
||||||
function saveImpl(stateProvider) {
|
function saveImpl(stateProvider) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let cacheId = -1;
|
||||||
try {
|
try {
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
return;
|
return;
|
||||||
@ -41102,8 +41173,7 @@ function saveImpl(stateProvider) {
|
|||||||
}
|
}
|
||||||
// If restore has stored a primary key in state, reuse that
|
// If restore has stored a primary key in state, reuse that
|
||||||
// Else re-evaluate from inputs
|
// Else re-evaluate from inputs
|
||||||
const primaryKey = stateProvider.getState(constants_1.State.CachePrimaryKey) ||
|
const primaryKey = stateProvider.getState(constants_1.State.CachePrimaryKey);
|
||||||
core.getInput(constants_1.Inputs.Key);
|
|
||||||
if (!primaryKey) {
|
if (!primaryKey) {
|
||||||
utils.logWarning(`Key is not specified.`);
|
utils.logWarning(`Key is not specified.`);
|
||||||
return;
|
return;
|
||||||
@ -41118,9 +41188,8 @@ function saveImpl(stateProvider) {
|
|||||||
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
const cacheId = yield cache.saveCache(cachePaths, primaryKey, {
|
const enableCrossOsArchive = utils.getInputAsBool(constants_1.Inputs.EnableCrossOsArchive);
|
||||||
uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize)
|
cacheId = yield cache.saveCache(cachePaths, primaryKey, { uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize) }, enableCrossOsArchive);
|
||||||
});
|
|
||||||
if (cacheId != -1) {
|
if (cacheId != -1) {
|
||||||
core.info(`Cache saved with key: ${primaryKey}`);
|
core.info(`Cache saved with key: ${primaryKey}`);
|
||||||
}
|
}
|
||||||
@ -41128,6 +41197,7 @@ function saveImpl(stateProvider) {
|
|||||||
catch (error) {
|
catch (error) {
|
||||||
utils.logWarning(error.message);
|
utils.logWarning(error.message);
|
||||||
}
|
}
|
||||||
|
return cacheId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.default = saveImpl;
|
exports.default = saveImpl;
|
||||||
@ -47259,7 +47329,6 @@ const path = __importStar(__webpack_require__(622));
|
|||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const cacheHttpClient = __importStar(__webpack_require__(114));
|
const cacheHttpClient = __importStar(__webpack_require__(114));
|
||||||
const tar_1 = __webpack_require__(434);
|
const tar_1 = __webpack_require__(434);
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
class ValidationError extends Error {
|
class ValidationError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
@ -47306,9 +47375,10 @@ exports.isFeatureAvailable = isFeatureAvailable;
|
|||||||
* @param primaryKey an explicit key for restoring the cache
|
* @param primaryKey an explicit key for restoring the cache
|
||||||
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
||||||
* @param downloadOptions cache download options
|
* @param downloadOptions cache download options
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform
|
||||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||||
*/
|
*/
|
||||||
function restoreCache(paths, primaryKey, restoreKeys, options) {
|
function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
restoreKeys = restoreKeys || [];
|
restoreKeys = restoreKeys || [];
|
||||||
@ -47321,32 +47391,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
checkKey(key);
|
checkKey(key);
|
||||||
}
|
}
|
||||||
let cacheEntry;
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
let compressionMethod = yield utils.getCompressionMethod();
|
|
||||||
let archivePath = '';
|
let archivePath = '';
|
||||||
try {
|
try {
|
||||||
// path are needed to compute version
|
// path are needed to compute version
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||||
compressionMethod
|
compressionMethod,
|
||||||
|
enableCrossOsArchive
|
||||||
});
|
});
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||||
// This is to support the old cache entry created by gzip on windows.
|
|
||||||
if (process.platform === 'win32' &&
|
|
||||||
compressionMethod !== constants_1.CompressionMethod.Gzip) {
|
|
||||||
compressionMethod = constants_1.CompressionMethod.Gzip;
|
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
|
||||||
compressionMethod
|
|
||||||
});
|
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
core.debug("Couldn't find cache entry with zstd compression, falling back to gzip compression.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
// Download the cache from the cache entry
|
// Download the cache from the cache entry
|
||||||
@ -47388,10 +47444,11 @@ exports.restoreCache = restoreCache;
|
|||||||
*
|
*
|
||||||
* @param paths a list of file paths to be cached
|
* @param paths a list of file paths to be cached
|
||||||
* @param key an explicit key for restoring the cache
|
* @param key an explicit key for restoring the cache
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform
|
||||||
* @param options cache upload options
|
* @param options cache upload options
|
||||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||||
*/
|
*/
|
||||||
function saveCache(paths, key, options) {
|
function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||||
var _a, _b, _c, _d, _e;
|
var _a, _b, _c, _d, _e;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
@ -47422,6 +47479,7 @@ function saveCache(paths, key, options) {
|
|||||||
core.debug('Reserving Cache');
|
core.debug('Reserving Cache');
|
||||||
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
|
enableCrossOsArchive,
|
||||||
cacheSize: archiveFileSize
|
cacheSize: archiveFileSize
|
||||||
});
|
});
|
||||||
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
||||||
|
115
dist/save/index.js
vendored
115
dist/save/index.js
vendored
@ -3383,7 +3383,6 @@ const crypto = __importStar(__webpack_require__(417));
|
|||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
const url_1 = __webpack_require__(835);
|
const url_1 = __webpack_require__(835);
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
const downloadUtils_1 = __webpack_require__(251);
|
const downloadUtils_1 = __webpack_require__(251);
|
||||||
const options_1 = __webpack_require__(538);
|
const options_1 = __webpack_require__(538);
|
||||||
const requestUtils_1 = __webpack_require__(899);
|
const requestUtils_1 = __webpack_require__(899);
|
||||||
@ -3413,10 +3412,17 @@ function createHttpClient() {
|
|||||||
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
const bearerCredentialHandler = new auth_1.BearerCredentialHandler(token);
|
||||||
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
return new http_client_1.HttpClient('actions/cache', [bearerCredentialHandler], getRequestOptions());
|
||||||
}
|
}
|
||||||
function getCacheVersion(paths, compressionMethod) {
|
function getCacheVersion(paths, compressionMethod, enableCrossOsArchive = false) {
|
||||||
const components = paths.concat(!compressionMethod || compressionMethod === constants_1.CompressionMethod.Gzip
|
const components = paths;
|
||||||
? []
|
// Add compression method to cache version to restore
|
||||||
: [compressionMethod]);
|
// compressed cache as per compression method
|
||||||
|
if (compressionMethod) {
|
||||||
|
components.push(compressionMethod);
|
||||||
|
}
|
||||||
|
// Only check for windows platforms if enableCrossOsArchive is false
|
||||||
|
if (process.platform === 'win32' && !enableCrossOsArchive) {
|
||||||
|
components.push('windows-only');
|
||||||
|
}
|
||||||
// Add salt to cache version to support breaking changes in cache entry
|
// Add salt to cache version to support breaking changes in cache entry
|
||||||
components.push(versionSalt);
|
components.push(versionSalt);
|
||||||
return crypto
|
return crypto
|
||||||
@ -3428,11 +3434,15 @@ exports.getCacheVersion = getCacheVersion;
|
|||||||
function getCacheEntry(keys, paths, options) {
|
function getCacheEntry(keys, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
const resource = `cache?keys=${encodeURIComponent(keys.join(','))}&version=${version}`;
|
||||||
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
const response = yield requestUtils_1.retryTypedResponse('getCacheEntry', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
if (response.statusCode === 204) {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
|
if (response.statusCode === 204) {
|
||||||
|
// List cache for primary key only if cache miss occurs
|
||||||
|
if (core.isDebug()) {
|
||||||
|
yield printCachesListForDiagnostics(keys[0], httpClient, version);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
if (!requestUtils_1.isSuccessStatusCode(response.statusCode)) {
|
||||||
@ -3451,6 +3461,22 @@ function getCacheEntry(keys, paths, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getCacheEntry = getCacheEntry;
|
exports.getCacheEntry = getCacheEntry;
|
||||||
|
function printCachesListForDiagnostics(key, httpClient, version) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const resource = `caches?key=${encodeURIComponent(key)}`;
|
||||||
|
const response = yield requestUtils_1.retryTypedResponse('listCache', () => __awaiter(this, void 0, void 0, function* () { return httpClient.getJson(getCacheApiUrl(resource)); }));
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const cacheListResult = response.result;
|
||||||
|
const totalCount = cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.totalCount;
|
||||||
|
if (totalCount && totalCount > 0) {
|
||||||
|
core.debug(`No matching cache found for cache key '${key}', version '${version} and scope ${process.env['GITHUB_REF']}. There exist one or more cache(s) with similar key but they have different version or scope. See more info on cache matching here: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#matching-a-cache-key \nOther caches with similar key:`);
|
||||||
|
for (const cacheEntry of (cacheListResult === null || cacheListResult === void 0 ? void 0 : cacheListResult.artifactCaches) || []) {
|
||||||
|
core.debug(`Cache Key: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheKey}, Cache Version: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.cacheVersion}, Cache Scope: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.scope}, Cache Created: ${cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.creationTime}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function downloadCache(archiveLocation, archivePath, options) {
|
function downloadCache(archiveLocation, archivePath, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const archiveUrl = new url_1.URL(archiveLocation);
|
const archiveUrl = new url_1.URL(archiveLocation);
|
||||||
@ -3471,7 +3497,7 @@ exports.downloadCache = downloadCache;
|
|||||||
function reserveCache(key, paths, options) {
|
function reserveCache(key, paths, options) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const httpClient = createHttpClient();
|
const httpClient = createHttpClient();
|
||||||
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod);
|
const version = getCacheVersion(paths, options === null || options === void 0 ? void 0 : options.compressionMethod, options === null || options === void 0 ? void 0 : options.enableCrossOsArchive);
|
||||||
const reserveCacheRequest = {
|
const reserveCacheRequest = {
|
||||||
key,
|
key,
|
||||||
version,
|
version,
|
||||||
@ -4951,7 +4977,8 @@ var Inputs;
|
|||||||
Inputs["Key"] = "key";
|
Inputs["Key"] = "key";
|
||||||
Inputs["Path"] = "path";
|
Inputs["Path"] = "path";
|
||||||
Inputs["RestoreKeys"] = "restore-keys";
|
Inputs["RestoreKeys"] = "restore-keys";
|
||||||
Inputs["UploadChunkSize"] = "upload-chunk-size"; // Input for cache, save action
|
Inputs["UploadChunkSize"] = "upload-chunk-size";
|
||||||
|
Inputs["EnableCrossOsArchive"] = "enableCrossOsArchive"; // Input for cache, restore, save action
|
||||||
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
})(Inputs = exports.Inputs || (exports.Inputs = {}));
|
||||||
var Outputs;
|
var Outputs;
|
||||||
(function (Outputs) {
|
(function (Outputs) {
|
||||||
@ -9386,15 +9413,24 @@ exports.StateProvider = StateProvider;
|
|||||||
class NullStateProvider extends StateProviderBase {
|
class NullStateProvider extends StateProviderBase {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(...arguments);
|
super(...arguments);
|
||||||
|
this.stateToInputMap = new Map([
|
||||||
|
[constants_1.State.CachePrimaryKey, constants_1.Inputs.Key]
|
||||||
|
]);
|
||||||
this.stateToOutputMap = new Map([
|
this.stateToOutputMap = new Map([
|
||||||
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
[constants_1.State.CacheMatchedKey, constants_1.Outputs.CacheMatchedKey],
|
||||||
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
[constants_1.State.CachePrimaryKey, constants_1.Outputs.CachePrimaryKey]
|
||||||
]);
|
]);
|
||||||
this.setState = (key, value) => {
|
this.setState = (key, value) => {
|
||||||
|
if (this.stateToOutputMap.has(key)) {
|
||||||
core.setOutput(this.stateToOutputMap.get(key), value);
|
core.setOutput(this.stateToOutputMap.get(key), value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.getState = (key) => {
|
||||||
|
if (!this.stateToInputMap.has(key)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return core.getInput(this.stateToInputMap.get(key));
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
this.getState = (key) => "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.NullStateProvider = NullStateProvider;
|
exports.NullStateProvider = NullStateProvider;
|
||||||
@ -38105,12 +38141,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const exec_1 = __webpack_require__(986);
|
const exec_1 = __webpack_require__(986);
|
||||||
|
const core_1 = __webpack_require__(470);
|
||||||
const io = __importStar(__webpack_require__(1));
|
const io = __importStar(__webpack_require__(1));
|
||||||
const fs_1 = __webpack_require__(747);
|
const fs_1 = __webpack_require__(747);
|
||||||
const path = __importStar(__webpack_require__(622));
|
const path = __importStar(__webpack_require__(622));
|
||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const constants_1 = __webpack_require__(931);
|
const constants_1 = __webpack_require__(931);
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const IS_WINDOWS = process.platform === 'win32';
|
||||||
|
core_1.exportVariable('MSYS', 'winsymlinks:nativestrict');
|
||||||
// Returns tar path and type: BSD or GNU
|
// Returns tar path and type: BSD or GNU
|
||||||
function getTarPath() {
|
function getTarPath() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -38237,7 +38275,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d --long=30 -o',
|
'zstd -d --long=30 --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38248,7 +38286,7 @@ function getDecompressionProgram(tarPath, compressionMethod, archivePath) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -d -o',
|
'zstd -d --force -o',
|
||||||
constants_1.TarFilename,
|
constants_1.TarFilename,
|
||||||
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
archivePath.replace(new RegExp(`\\${path.sep}`, 'g'), '/')
|
||||||
]
|
]
|
||||||
@ -38274,7 +38312,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.Zstd:
|
case constants_1.CompressionMethod.Zstd:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 --long=30 -o',
|
'zstd -T0 --long=30 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38285,7 +38323,7 @@ function getCompressionProgram(tarPath, compressionMethod) {
|
|||||||
case constants_1.CompressionMethod.ZstdWithoutLong:
|
case constants_1.CompressionMethod.ZstdWithoutLong:
|
||||||
return BSD_TAR_ZSTD
|
return BSD_TAR_ZSTD
|
||||||
? [
|
? [
|
||||||
'zstd -T0 -o',
|
'zstd -T0 --force -o',
|
||||||
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
cacheFileName.replace(new RegExp(`\\${path.sep}`, 'g'), '/'),
|
||||||
constants_1.TarFilename
|
constants_1.TarFilename
|
||||||
]
|
]
|
||||||
@ -38568,7 +38606,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isCacheFeatureAvailable = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
exports.isCacheFeatureAvailable = exports.getInputAsBool = exports.getInputAsInt = exports.getInputAsArray = exports.isValidEvent = exports.logWarning = exports.isExactKeyMatch = exports.isGhes = void 0;
|
||||||
const cache = __importStar(__webpack_require__(692));
|
const cache = __importStar(__webpack_require__(692));
|
||||||
const core = __importStar(__webpack_require__(470));
|
const core = __importStar(__webpack_require__(470));
|
||||||
const constants_1 = __webpack_require__(196);
|
const constants_1 = __webpack_require__(196);
|
||||||
@ -38611,6 +38649,11 @@ function getInputAsInt(name, options) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
exports.getInputAsInt = getInputAsInt;
|
exports.getInputAsInt = getInputAsInt;
|
||||||
|
function getInputAsBool(name, options) {
|
||||||
|
const result = core.getInput(name, options);
|
||||||
|
return result.toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
exports.getInputAsBool = getInputAsBool;
|
||||||
function isCacheFeatureAvailable() {
|
function isCacheFeatureAvailable() {
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
@ -41063,6 +41106,7 @@ const utils = __importStar(__webpack_require__(443));
|
|||||||
process.on("uncaughtException", e => utils.logWarning(e.message));
|
process.on("uncaughtException", e => utils.logWarning(e.message));
|
||||||
function saveImpl(stateProvider) {
|
function saveImpl(stateProvider) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let cacheId = -1;
|
||||||
try {
|
try {
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
return;
|
return;
|
||||||
@ -41073,8 +41117,7 @@ function saveImpl(stateProvider) {
|
|||||||
}
|
}
|
||||||
// If restore has stored a primary key in state, reuse that
|
// If restore has stored a primary key in state, reuse that
|
||||||
// Else re-evaluate from inputs
|
// Else re-evaluate from inputs
|
||||||
const primaryKey = stateProvider.getState(constants_1.State.CachePrimaryKey) ||
|
const primaryKey = stateProvider.getState(constants_1.State.CachePrimaryKey);
|
||||||
core.getInput(constants_1.Inputs.Key);
|
|
||||||
if (!primaryKey) {
|
if (!primaryKey) {
|
||||||
utils.logWarning(`Key is not specified.`);
|
utils.logWarning(`Key is not specified.`);
|
||||||
return;
|
return;
|
||||||
@ -41089,9 +41132,8 @@ function saveImpl(stateProvider) {
|
|||||||
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
const cachePaths = utils.getInputAsArray(constants_1.Inputs.Path, {
|
||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
const cacheId = yield cache.saveCache(cachePaths, primaryKey, {
|
const enableCrossOsArchive = utils.getInputAsBool(constants_1.Inputs.EnableCrossOsArchive);
|
||||||
uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize)
|
cacheId = yield cache.saveCache(cachePaths, primaryKey, { uploadChunkSize: utils.getInputAsInt(constants_1.Inputs.UploadChunkSize) }, enableCrossOsArchive);
|
||||||
});
|
|
||||||
if (cacheId != -1) {
|
if (cacheId != -1) {
|
||||||
core.info(`Cache saved with key: ${primaryKey}`);
|
core.info(`Cache saved with key: ${primaryKey}`);
|
||||||
}
|
}
|
||||||
@ -41099,6 +41141,7 @@ function saveImpl(stateProvider) {
|
|||||||
catch (error) {
|
catch (error) {
|
||||||
utils.logWarning(error.message);
|
utils.logWarning(error.message);
|
||||||
}
|
}
|
||||||
|
return cacheId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.default = saveImpl;
|
exports.default = saveImpl;
|
||||||
@ -47259,7 +47302,6 @@ const path = __importStar(__webpack_require__(622));
|
|||||||
const utils = __importStar(__webpack_require__(15));
|
const utils = __importStar(__webpack_require__(15));
|
||||||
const cacheHttpClient = __importStar(__webpack_require__(114));
|
const cacheHttpClient = __importStar(__webpack_require__(114));
|
||||||
const tar_1 = __webpack_require__(434);
|
const tar_1 = __webpack_require__(434);
|
||||||
const constants_1 = __webpack_require__(931);
|
|
||||||
class ValidationError extends Error {
|
class ValidationError extends Error {
|
||||||
constructor(message) {
|
constructor(message) {
|
||||||
super(message);
|
super(message);
|
||||||
@ -47306,9 +47348,10 @@ exports.isFeatureAvailable = isFeatureAvailable;
|
|||||||
* @param primaryKey an explicit key for restoring the cache
|
* @param primaryKey an explicit key for restoring the cache
|
||||||
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
* @param restoreKeys an optional ordered list of keys to use for restoring the cache if no cache hit occurred for key
|
||||||
* @param downloadOptions cache download options
|
* @param downloadOptions cache download options
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to restore on windows any cache created on any platform
|
||||||
* @returns string returns the key for the cache hit, otherwise returns undefined
|
* @returns string returns the key for the cache hit, otherwise returns undefined
|
||||||
*/
|
*/
|
||||||
function restoreCache(paths, primaryKey, restoreKeys, options) {
|
function restoreCache(paths, primaryKey, restoreKeys, options, enableCrossOsArchive = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
restoreKeys = restoreKeys || [];
|
restoreKeys = restoreKeys || [];
|
||||||
@ -47321,32 +47364,18 @@ function restoreCache(paths, primaryKey, restoreKeys, options) {
|
|||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
checkKey(key);
|
checkKey(key);
|
||||||
}
|
}
|
||||||
let cacheEntry;
|
const compressionMethod = yield utils.getCompressionMethod();
|
||||||
let compressionMethod = yield utils.getCompressionMethod();
|
|
||||||
let archivePath = '';
|
let archivePath = '';
|
||||||
try {
|
try {
|
||||||
// path are needed to compute version
|
// path are needed to compute version
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
const cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
||||||
compressionMethod
|
compressionMethod,
|
||||||
|
enableCrossOsArchive
|
||||||
});
|
});
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
||||||
// This is to support the old cache entry created by gzip on windows.
|
|
||||||
if (process.platform === 'win32' &&
|
|
||||||
compressionMethod !== constants_1.CompressionMethod.Gzip) {
|
|
||||||
compressionMethod = constants_1.CompressionMethod.Gzip;
|
|
||||||
cacheEntry = yield cacheHttpClient.getCacheEntry(keys, paths, {
|
|
||||||
compressionMethod
|
|
||||||
});
|
|
||||||
if (!(cacheEntry === null || cacheEntry === void 0 ? void 0 : cacheEntry.archiveLocation)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
core.debug("Couldn't find cache entry with zstd compression, falling back to gzip compression.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Cache not found
|
// Cache not found
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
archivePath = path.join(yield utils.createTempDirectory(), utils.getCacheFileName(compressionMethod));
|
||||||
core.debug(`Archive Path: ${archivePath}`);
|
core.debug(`Archive Path: ${archivePath}`);
|
||||||
// Download the cache from the cache entry
|
// Download the cache from the cache entry
|
||||||
@ -47388,10 +47417,11 @@ exports.restoreCache = restoreCache;
|
|||||||
*
|
*
|
||||||
* @param paths a list of file paths to be cached
|
* @param paths a list of file paths to be cached
|
||||||
* @param key an explicit key for restoring the cache
|
* @param key an explicit key for restoring the cache
|
||||||
|
* @param enableCrossOsArchive an optional boolean enabled to save cache on windows which could be restored on any platform
|
||||||
* @param options cache upload options
|
* @param options cache upload options
|
||||||
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
* @returns number returns cacheId if the cache was saved successfully and throws an error if save fails
|
||||||
*/
|
*/
|
||||||
function saveCache(paths, key, options) {
|
function saveCache(paths, key, options, enableCrossOsArchive = false) {
|
||||||
var _a, _b, _c, _d, _e;
|
var _a, _b, _c, _d, _e;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
checkPaths(paths);
|
checkPaths(paths);
|
||||||
@ -47422,6 +47452,7 @@ function saveCache(paths, key, options) {
|
|||||||
core.debug('Reserving Cache');
|
core.debug('Reserving Cache');
|
||||||
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
const reserveCacheResponse = yield cacheHttpClient.reserveCache(key, paths, {
|
||||||
compressionMethod,
|
compressionMethod,
|
||||||
|
enableCrossOsArchive,
|
||||||
cacheSize: archiveFileSize
|
cacheSize: archiveFileSize
|
||||||
});
|
});
|
||||||
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
if ((_a = reserveCacheResponse === null || reserveCacheResponse === void 0 ? void 0 : reserveCacheResponse.result) === null || _a === void 0 ? void 0 : _a.cacheId) {
|
||||||
|
16
examples.md
16
examples.md
@ -38,6 +38,7 @@
|
|||||||
- [Swift, Objective-C - Carthage](#swift-objective-c---carthage)
|
- [Swift, Objective-C - Carthage](#swift-objective-c---carthage)
|
||||||
- [Swift, Objective-C - CocoaPods](#swift-objective-c---cocoapods)
|
- [Swift, Objective-C - CocoaPods](#swift-objective-c---cocoapods)
|
||||||
- [Swift - Swift Package Manager](#swift---swift-package-manager)
|
- [Swift - Swift Package Manager](#swift---swift-package-manager)
|
||||||
|
- [Swift - Mint](#swift---mint)
|
||||||
|
|
||||||
## C# - NuGet
|
## C# - NuGet
|
||||||
|
|
||||||
@ -641,3 +642,18 @@ whenever possible:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-spm-
|
${{ runner.os }}-spm-
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Swift - Mint
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
MINT_PATH: .mint/lib
|
||||||
|
MINT_LINK_PATH: .mint/bin
|
||||||
|
steps:
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: .mint
|
||||||
|
key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-mint-
|
||||||
|
```
|
||||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "cache",
|
"name": "cache",
|
||||||
"version": "3.2.0-beta.1",
|
"version": "3.2.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cache",
|
"name": "cache",
|
||||||
"version": "3.2.0-beta.1",
|
"version": "3.2.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "3.1.0-beta.3",
|
"@actions/cache": "^3.1.2",
|
||||||
"@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"
|
||||||
@ -36,9 +36,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/cache": {
|
"node_modules/@actions/cache": {
|
||||||
"version": "3.1.0-beta.3",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.1.0-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.1.2.tgz",
|
||||||
"integrity": "sha512-71S1vd0WKLbC2lAe04pCYqTLBjSa8gURtiqnVBCYAt8QVBjOfwa2D3ESf2m8K2xjUxman/Yimdp7CPJDyFnxZg==",
|
"integrity": "sha512-3XeKcXIonfIbqvW7gPm/VLOhv1RHQ1dtTgSBCH6OUhCgSTii9bEVgu0PIms7UbLnXeMCKFzECfpbud8fJEvBbQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.0.1",
|
"@actions/exec": "^1.0.1",
|
||||||
@ -9722,9 +9722,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": {
|
"@actions/cache": {
|
||||||
"version": "3.1.0-beta.3",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.1.0-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/cache/-/cache-3.1.2.tgz",
|
||||||
"integrity": "sha512-71S1vd0WKLbC2lAe04pCYqTLBjSa8gURtiqnVBCYAt8QVBjOfwa2D3ESf2m8K2xjUxman/Yimdp7CPJDyFnxZg==",
|
"integrity": "sha512-3XeKcXIonfIbqvW7gPm/VLOhv1RHQ1dtTgSBCH6OUhCgSTii9bEVgu0PIms7UbLnXeMCKFzECfpbud8fJEvBbQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.0.1",
|
"@actions/exec": "^1.0.1",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cache",
|
"name": "cache",
|
||||||
"version": "3.2.0-beta.1",
|
"version": "3.2.3",
|
||||||
"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.1.0-beta.3",
|
"@actions/cache": "^3.1.2",
|
||||||
"@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"
|
||||||
|
@ -120,7 +120,7 @@ steps:
|
|||||||
|
|
||||||
#### Reusing primary key and restored key in the save action
|
#### Reusing primary key and restored key in the save action
|
||||||
|
|
||||||
Usually you may want to use same `key` in both actions/cache/restore` and `actions/cache/save` action. To achieve this, use `outputs` from the restore action to reuse the same primary key (or the key of the cache that was restored).
|
Usually you may want to use same `key` in both `actions/cache/restore` and `actions/cache/save` action. To achieve this, use `outputs` from the restore action to reuse the same primary key (or the key of the cache that was restored).
|
||||||
|
|
||||||
#### Using restore action outputs to make save action behave just like the cache action
|
#### Using restore action outputs to make save action behave just like the cache action
|
||||||
|
|
||||||
|
@ -11,6 +11,10 @@ inputs:
|
|||||||
restore-keys:
|
restore-keys:
|
||||||
description: 'An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
|
description: 'An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
|
||||||
required: false
|
required: false
|
||||||
|
enableCrossOsArchive:
|
||||||
|
description: 'An optional boolean when enabled, allows windows runners to restore caches that were saved on other platforms'
|
||||||
|
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'
|
||||||
|
@ -54,7 +54,7 @@ Case 1: Where an user would want to reuse the key as it is
|
|||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v3
|
||||||
with:
|
with:
|
||||||
key: steps.restore-cache.output.key
|
key: ${{ steps.restore-cache.outputs.key }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Case 2: Where the user would want to re-evaluate the key
|
Case 2: Where the user would want to re-evaluate the key
|
||||||
|
@ -11,6 +11,10 @@ inputs:
|
|||||||
upload-chunk-size:
|
upload-chunk-size:
|
||||||
description: 'The chunk size used to split up large files during upload, in bytes'
|
description: 'The chunk size used to split up large files during upload, in bytes'
|
||||||
required: false
|
required: false
|
||||||
|
enableCrossOsArchive:
|
||||||
|
description: 'An optional boolean when enabled, allows windows runners to save caches that can be restored on other platforms'
|
||||||
|
default: 'false'
|
||||||
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: '../dist/save-only/index.js'
|
main: '../dist/save-only/index.js'
|
||||||
|
@ -2,7 +2,8 @@ export enum Inputs {
|
|||||||
Key = "key", // Input for cache, restore, save action
|
Key = "key", // Input for cache, restore, save action
|
||||||
Path = "path", // Input for cache, restore, save action
|
Path = "path", // Input for cache, restore, save action
|
||||||
RestoreKeys = "restore-keys", // Input for cache, restore action
|
RestoreKeys = "restore-keys", // Input for cache, restore action
|
||||||
UploadChunkSize = "upload-chunk-size" // Input for cache, save action
|
UploadChunkSize = "upload-chunk-size", // Input for cache, save action
|
||||||
|
EnableCrossOsArchive = "enableCrossOsArchive" // Input for cache, restore, save action
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Outputs {
|
export enum Outputs {
|
||||||
|
@ -31,11 +31,16 @@ async function restoreImpl(
|
|||||||
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
const cachePaths = utils.getInputAsArray(Inputs.Path, {
|
||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
|
const enableCrossOsArchive = utils.getInputAsBool(
|
||||||
|
Inputs.EnableCrossOsArchive
|
||||||
|
);
|
||||||
|
|
||||||
const cacheKey = await cache.restoreCache(
|
const cacheKey = await cache.restoreCache(
|
||||||
cachePaths,
|
cachePaths,
|
||||||
primaryKey,
|
primaryKey,
|
||||||
restoreKeys
|
restoreKeys,
|
||||||
|
{},
|
||||||
|
enableCrossOsArchive
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
|
@ -10,7 +10,8 @@ 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));
|
||||||
|
|
||||||
async function saveImpl(stateProvider: IStateProvider): Promise<void> {
|
async function saveImpl(stateProvider: IStateProvider): Promise<number | void> {
|
||||||
|
let cacheId = -1;
|
||||||
try {
|
try {
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
return;
|
return;
|
||||||
@ -27,9 +28,7 @@ async function saveImpl(stateProvider: IStateProvider): Promise<void> {
|
|||||||
|
|
||||||
// If restore has stored a primary key in state, reuse that
|
// If restore has stored a primary key in state, reuse that
|
||||||
// Else re-evaluate from inputs
|
// Else re-evaluate from inputs
|
||||||
const primaryKey =
|
const primaryKey = stateProvider.getState(State.CachePrimaryKey);
|
||||||
stateProvider.getState(State.CachePrimaryKey) ||
|
|
||||||
core.getInput(Inputs.Key);
|
|
||||||
|
|
||||||
if (!primaryKey) {
|
if (!primaryKey) {
|
||||||
utils.logWarning(`Key is not specified.`);
|
utils.logWarning(`Key is not specified.`);
|
||||||
@ -51,9 +50,16 @@ async function saveImpl(stateProvider: IStateProvider): Promise<void> {
|
|||||||
required: true
|
required: true
|
||||||
});
|
});
|
||||||
|
|
||||||
const cacheId = await cache.saveCache(cachePaths, primaryKey, {
|
const enableCrossOsArchive = utils.getInputAsBool(
|
||||||
uploadChunkSize: utils.getInputAsInt(Inputs.UploadChunkSize)
|
Inputs.EnableCrossOsArchive
|
||||||
});
|
);
|
||||||
|
|
||||||
|
cacheId = await cache.saveCache(
|
||||||
|
cachePaths,
|
||||||
|
primaryKey,
|
||||||
|
{ uploadChunkSize: utils.getInputAsInt(Inputs.UploadChunkSize) },
|
||||||
|
enableCrossOsArchive
|
||||||
|
);
|
||||||
|
|
||||||
if (cacheId != -1) {
|
if (cacheId != -1) {
|
||||||
core.info(`Cache saved with key: ${primaryKey}`);
|
core.info(`Cache saved with key: ${primaryKey}`);
|
||||||
@ -61,6 +67,7 @@ async function saveImpl(stateProvider: IStateProvider): Promise<void> {
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
utils.logWarning((error as Error).message);
|
utils.logWarning((error as Error).message);
|
||||||
}
|
}
|
||||||
|
return cacheId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default saveImpl;
|
export default saveImpl;
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import saveImpl from "./saveImpl";
|
import saveImpl from "./saveImpl";
|
||||||
import { NullStateProvider } from "./stateProvider";
|
import { NullStateProvider } from "./stateProvider";
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
await saveImpl(new NullStateProvider());
|
const cacheId = await saveImpl(new NullStateProvider());
|
||||||
|
if (cacheId === -1) {
|
||||||
|
core.warning(`Cache save failed.`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Outputs, State } from "./constants";
|
import { Inputs, Outputs, State } from "./constants";
|
||||||
|
|
||||||
export interface IStateProvider {
|
export interface IStateProvider {
|
||||||
setState(key: string, value: string): void;
|
setState(key: string, value: string): void;
|
||||||
@ -33,14 +33,25 @@ export class StateProvider extends StateProviderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class NullStateProvider extends StateProviderBase {
|
export class NullStateProvider extends StateProviderBase {
|
||||||
|
stateToInputMap = new Map<string, string>([
|
||||||
|
[State.CachePrimaryKey, Inputs.Key]
|
||||||
|
]);
|
||||||
|
|
||||||
stateToOutputMap = new Map<string, string>([
|
stateToOutputMap = new Map<string, string>([
|
||||||
[State.CacheMatchedKey, Outputs.CacheMatchedKey],
|
[State.CacheMatchedKey, Outputs.CacheMatchedKey],
|
||||||
[State.CachePrimaryKey, Outputs.CachePrimaryKey]
|
[State.CachePrimaryKey, Outputs.CachePrimaryKey]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
setState = (key: string, value: string) => {
|
setState = (key: string, value: string) => {
|
||||||
|
if (this.stateToOutputMap.has(key)) {
|
||||||
core.setOutput(this.stateToOutputMap.get(key) as string, value);
|
core.setOutput(this.stateToOutputMap.get(key) as string, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getState = (key: string) => {
|
||||||
|
if (!this.stateToInputMap.has(key)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return core.getInput(this.stateToInputMap.get(key) as string);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
getState = (key: string) => "";
|
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,14 @@ export function getInputAsInt(
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getInputAsBool(
|
||||||
|
name: string,
|
||||||
|
options?: core.InputOptions
|
||||||
|
): boolean {
|
||||||
|
const result = core.getInput(name, options);
|
||||||
|
return result.toLowerCase() === "true";
|
||||||
|
}
|
||||||
|
|
||||||
export function isCacheFeatureAvailable(): boolean {
|
export function isCacheFeatureAvailable(): boolean {
|
||||||
if (cache.isFeatureAvailable()) {
|
if (cache.isFeatureAvailable()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -9,10 +9,15 @@ export function setInput(name: string, value: string): void {
|
|||||||
process.env[getInputName(name)] = value;
|
process.env[getInputName(name)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getInput(name: string): string {
|
||||||
|
return process.env[getInputName(name)] as string;
|
||||||
|
}
|
||||||
|
|
||||||
interface CacheInput {
|
interface CacheInput {
|
||||||
path: string;
|
path: string;
|
||||||
key: string;
|
key: string;
|
||||||
restoreKeys?: string[];
|
restoreKeys?: string[];
|
||||||
|
enableCrossOsArchive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setInputs(input: CacheInput): void {
|
export function setInputs(input: CacheInput): void {
|
||||||
@ -20,6 +25,11 @@ export function setInputs(input: CacheInput): void {
|
|||||||
setInput(Inputs.Key, input.key);
|
setInput(Inputs.Key, input.key);
|
||||||
input.restoreKeys &&
|
input.restoreKeys &&
|
||||||
setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
|
setInput(Inputs.RestoreKeys, input.restoreKeys.join("\n"));
|
||||||
|
input.enableCrossOsArchive !== undefined &&
|
||||||
|
setInput(
|
||||||
|
Inputs.EnableCrossOsArchive,
|
||||||
|
input.enableCrossOsArchive.toString()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearInputs(): void {
|
export function clearInputs(): void {
|
||||||
@ -27,4 +37,5 @@ export function clearInputs(): void {
|
|||||||
delete process.env[getInputName(Inputs.Key)];
|
delete process.env[getInputName(Inputs.Key)];
|
||||||
delete process.env[getInputName(Inputs.RestoreKeys)];
|
delete process.env[getInputName(Inputs.RestoreKeys)];
|
||||||
delete process.env[getInputName(Inputs.UploadChunkSize)];
|
delete process.env[getInputName(Inputs.UploadChunkSize)];
|
||||||
|
delete process.env[getInputName(Inputs.EnableCrossOsArchive)];
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,10 @@ A cache today is immutable and cannot be updated. But some use cases require the
|
|||||||
## Use cache across feature branches
|
## Use cache across feature branches
|
||||||
Reusing cache across feature branches is not allowed today to provide cache [isolation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache). However if both feature branches are from the default branch, a good way to achieve this is to ensure that the default branch has a cache. This cache will then be consumable by both feature branches.
|
Reusing cache across feature branches is not allowed today to provide cache [isolation](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache). However if both feature branches are from the default branch, a good way to achieve this is to ensure that the default branch has a cache. This cache will then be consumable by both feature branches.
|
||||||
|
|
||||||
## Improving cache restore performance on Windows/Using cross-os caching
|
## Cross OS cache
|
||||||
Currently, cache restore is slow on Windows due to tar being inherently slow and the compression algorithm `gzip` in use. `zstd` is the default algorithm in use on linux and macos. It was disabled on Windows due to issues with bsd tar(libarchive), the tar implementation in use on Windows.
|
From `v3.2.3` cache is cross-os compatible when `enableCrossOsArchive` input is passed as true. This means that a cache created on `ubuntu-latest` or `mac-latest` can be used by `windows-latest` and vice versa, provided the workflow which runs on `windows-latest` have input `enableCrossOsArchive` as true. This is useful to cache dependencies which are independent of the runner platform. This will help reduce the consumption of the cache quota and help build for multiple platforms from the same cache. Things to keep in mind while using this feature:
|
||||||
|
- Only cache those files which are compatible across OSs.
|
||||||
To improve cache restore performance, we can re-enable `zstd` as the compression algorithm using the following workaround. Add the following step to your workflow before the cache step:
|
- Caching symlinks might cause issues while restoration as they work differently on different OSs.
|
||||||
|
|
||||||
```yaml
|
|
||||||
- if: ${{ runner.os == 'Windows' }}
|
|
||||||
name: Use GNU tar
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
echo "Adding GNU tar to PATH"
|
|
||||||
echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%"
|
|
||||||
```
|
|
||||||
|
|
||||||
The `cache` action will use GNU tar instead of bsd tar on Windows. This should work on all Github Hosted runners as it is. For self-hosted runners, please ensure you have GNU tar and `zstd` installed.
|
|
||||||
|
|
||||||
The above workaround is also needed if you wish to use cross-os caching since difference of compression algorithms will result in different cache versions for the same cache key. So the above workaround will ensure `zstd` is used for caching on all platforms thus resulting in the same cache version for the same cache key.
|
|
||||||
|
|
||||||
## Force deletion of caches overriding default cache eviction policy
|
## Force deletion of caches overriding default cache eviction policy
|
||||||
Caches have [branch scope restriction](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache) in place. This means that if caches for a specific branch are using a lot of storage quota, it may result into more frequently used caches from `default` branch getting thrashed. For example, if there are many pull requests happening on a repo and are creating caches, these cannot be used in default branch scope but will still occupy a lot of space till they get cleaned up by [eviction policy](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy). But sometime we want to clean them up on a faster cadence so as to ensure default branch is not thrashing. In order to achieve this, [gh-actions-cache cli](https://github.com/actions/gh-actions-cache/) can be used to delete caches for specific branches.
|
Caches have [branch scope restriction](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache) in place. This means that if caches for a specific branch are using a lot of storage quota, it may result into more frequently used caches from `default` branch getting thrashed. For example, if there are many pull requests happening on a repo and are creating caches, these cannot be used in default branch scope but will still occupy a lot of space till they get cleaned up by [eviction policy](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy). But sometime we want to clean them up on a faster cadence so as to ensure default branch is not thrashing. In order to achieve this, [gh-actions-cache cli](https://github.com/actions/gh-actions-cache/) can be used to delete caches for specific branches.
|
||||||
|
Reference in New Issue
Block a user