mirror of
https://github.com/actions/cache.git
synced 2024-12-01 06:12:25 +08:00
Compare commits
61 Commits
707ad40d6c
...
e60ad5c987
Author | SHA1 | Date | |
---|---|---|---|
|
e60ad5c987 | ||
|
9803087a86 | ||
|
e7e2547a88 | ||
|
71d826cc33 | ||
|
25942a73ac | ||
|
d73025053b | ||
|
8469c94c6a | ||
|
3624ceb22c | ||
|
2cdf405574 | ||
|
a11fb02296 | ||
|
cf7a75e7b9 | ||
|
c74ca4022c | ||
|
f8a7ab490b | ||
|
45b7be0774 | ||
|
81382a721f | ||
|
c4ee99a3bd | ||
|
57b8e405f0 | ||
|
40c3b67b29 | ||
|
e47d9f9ec8 | ||
|
4a28cbc054 | ||
|
bf9a7572fe | ||
|
0c45773b62 | ||
|
8a55f839aa | ||
|
3884cace14 | ||
|
e29dad3e36 | ||
|
ab5e6d0c87 | ||
|
89c7d86c71 | ||
|
d2c84da363 | ||
|
37e7d4eb16 | ||
|
a18323f504 | ||
|
104f95683b | ||
|
a2ed59d39b | ||
|
dc88ab52d7 | ||
|
1d78355196 | ||
|
c36458f13b | ||
|
13aacd865c | ||
|
53b35c5439 | ||
|
65b8989fab | ||
|
d0be34d544 | ||
|
66cf064d47 | ||
|
1326563738 | ||
|
e12d46a63a | ||
|
1baebfc3ba | ||
|
eb94f1a6bf | ||
|
e71876755e | ||
|
01229828ff | ||
|
3185ecfd61 | ||
|
25618a0a67 | ||
|
a0a285ffd4 | ||
|
b00bedba4a | ||
|
99d573b49d | ||
|
6f0a1fdd90 | ||
|
2001ca4114 | ||
|
0e9aed0d0d | ||
|
3b7dac1789 | ||
|
b1378c8403 | ||
|
704facf57e | ||
|
17e2888746 | ||
|
667d8fdfa2 | ||
|
f7ebb81a3f | ||
|
67b839edb6 |
2
.github/workflows/check-dist.yml
vendored
2
.github/workflows/check-dist.yml
vendored
@ -15,3 +15,5 @@ jobs:
|
|||||||
call-check-dist:
|
call-check-dist:
|
||||||
name: Check dist/
|
name: Check dist/
|
||||||
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
|
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
|
||||||
|
with:
|
||||||
|
node-version: "20.x"
|
||||||
|
20
.github/workflows/publish-immutable-actions.yml
vendored
Normal file
20
.github/workflows/publish-immutable-actions.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: 'Publish Immutable Action Version'
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checking out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Publish
|
||||||
|
id: publish
|
||||||
|
uses: actions/publish-immutable-action@0.0.3
|
28
.github/workflows/release-new-action-version.yml
vendored
Normal file
28
.github/workflows/release-new-action-version.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: Release new action version
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
TAG_NAME:
|
||||||
|
description: 'Tag name that the major tag will point to'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update_tag:
|
||||||
|
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
|
||||||
|
environment:
|
||||||
|
name: releaseNewActionVersion
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Update the ${{ env.TAG_NAME }} tag
|
||||||
|
id: update-major-tag
|
||||||
|
uses: actions/publish-action@v0.3.0
|
||||||
|
with:
|
||||||
|
source-tag: ${{ env.TAG_NAME }}
|
||||||
|
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
4
.github/workflows/workflow.yml
vendored
4
.github/workflows/workflow.yml
vendored
@ -21,10 +21,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Setup Node.js 16.x
|
- name: Setup Node.js 20.x
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 20.x
|
||||||
cache: npm
|
cache: npm
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- name: Prettier Format Check
|
- name: Prettier Format Check
|
||||||
|
BIN
.licenses/npm/@actions/cache.dep.yml
generated
BIN
.licenses/npm/@actions/cache.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/@actions/http-client.dep.yml
generated
BIN
.licenses/npm/@actions/http-client.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/@azure/core-http.dep.yml
generated
BIN
.licenses/npm/@azure/core-http.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/@azure/ms-rest-js.dep.yml
generated
BIN
.licenses/npm/@azure/ms-rest-js.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/ip-regex.dep.yml
generated
BIN
.licenses/npm/ip-regex.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/psl.dep.yml
generated
BIN
.licenses/npm/psl.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/punycode.dep.yml
generated
BIN
.licenses/npm/punycode.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/semver.dep.yml
generated
BIN
.licenses/npm/semver.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/tough-cookie.dep.yml
generated
BIN
.licenses/npm/tough-cookie.dep.yml
generated
Binary file not shown.
BIN
.licenses/npm/xml2js.dep.yml
generated
BIN
.licenses/npm/xml2js.dep.yml
generated
Binary file not shown.
41
README.md
41
README.md
@ -14,6 +14,10 @@ See ["Caching dependencies to speed up workflows"](https://docs.github.com/en/ac
|
|||||||
|
|
||||||
## What's New
|
## What's New
|
||||||
|
|
||||||
|
### v4
|
||||||
|
|
||||||
|
* Updated to node 20
|
||||||
|
|
||||||
### v3
|
### v3
|
||||||
|
|
||||||
* Added support for caching in GHES 3.5+.
|
* Added support for caching in GHES 3.5+.
|
||||||
@ -49,7 +53,7 @@ If you are using a `self-hosted` Windows runner, `GNU tar` and `zstd` are requir
|
|||||||
|
|
||||||
* `key` - An explicit key for a cache entry. See [creating a cache key](#creating-a-cache-key).
|
* `key` - An explicit key for a cache entry. See [creating a cache key](#creating-a-cache-key).
|
||||||
* `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.
|
||||||
* `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 multiline string listing the prefix-matched keys, that are used 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`
|
* `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`
|
||||||
* `fail-on-cache-miss` - Fail the workflow if cache entry is not found. Default: `false`
|
* `fail-on-cache-miss` - Fail the workflow if cache entry is not found. Default: `false`
|
||||||
* `lookup-only` - If true, only checks if cache entry exists and skips download. Does not change save cache behavior. Default: `false`
|
* `lookup-only` - If true, only checks if cache entry exists and skips download. Does not change save cache behavior. Default: `false`
|
||||||
@ -60,9 +64,9 @@ If you are using a `self-hosted` Windows runner, `GNU tar` and `zstd` are requir
|
|||||||
|
|
||||||
### Outputs
|
### Outputs
|
||||||
|
|
||||||
* `cache-hit` - A boolean value to indicate an exact match was found for the key.
|
* `cache-hit` - A string value to indicate an exact match was found for the key.
|
||||||
|
* If there's a cache hit, this will be 'true' or 'false' to indicate if there's an exact match for `key`.
|
||||||
> **Note** `cache-hit` will only be set to `true` when a cache hit occurs for the exact `key` match. For a partial key match via `restore-keys` or a cache miss, it will be set to `false`.
|
* If there's a cache miss, this will be an empty string.
|
||||||
|
|
||||||
See [Skipping steps based on cache-hit](#skipping-steps-based-on-cache-hit) for info on using this output
|
See [Skipping steps based on cache-hit](#skipping-steps-based-on-cache-hit) for info on using this output
|
||||||
|
|
||||||
@ -86,11 +90,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cache Primes
|
- name: Cache Primes
|
||||||
id: cache-primes
|
id: cache-primes
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: prime-numbers
|
path: prime-numbers
|
||||||
key: ${{ runner.os }}-primes
|
key: ${{ runner.os }}-primes
|
||||||
@ -117,11 +121,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Restore cached Primes
|
- name: Restore cached Primes
|
||||||
id: cache-primes-restore
|
id: cache-primes-restore
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -132,7 +136,7 @@ jobs:
|
|||||||
.
|
.
|
||||||
- name: Save Primes
|
- name: Save Primes
|
||||||
id: cache-primes-save
|
id: cache-primes-save
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -153,6 +157,7 @@ Every programming language and framework has its own way of caching.
|
|||||||
|
|
||||||
See [Examples](examples.md) for a list of `actions/cache` implementations for use with:
|
See [Examples](examples.md) for a list of `actions/cache` implementations for use with:
|
||||||
|
|
||||||
|
* [Bun](./examples.md#bun)
|
||||||
* [C# - NuGet](./examples.md#c---nuget)
|
* [C# - NuGet](./examples.md#c---nuget)
|
||||||
* [Clojure - Lein Deps](./examples.md#clojure---lein-deps)
|
* [Clojure - Lein Deps](./examples.md#clojure---lein-deps)
|
||||||
* [D - DUB](./examples.md#d---dub)
|
* [D - DUB](./examples.md#d---dub)
|
||||||
@ -186,7 +191,7 @@ A cache key can include any of the contexts, functions, literals, and operators
|
|||||||
For example, using the [`hashFiles`](https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles) function allows you to create a new cache when dependencies change.
|
For example, using the [`hashFiles`](https://docs.github.com/en/actions/learn-github-actions/expressions#hashfiles) function allows you to create a new cache when dependencies change.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -204,7 +209,7 @@ Additionally, you can use arbitrary command output in a cache key, such as a dat
|
|||||||
echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
|
echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/lockfiles') }}
|
key: ${{ runner.os }}-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/lockfiles') }}
|
||||||
@ -224,9 +229,9 @@ Example:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -254,11 +259,11 @@ jobs:
|
|||||||
build-linux:
|
build-linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cache Primes
|
- name: Cache Primes
|
||||||
id: cache-primes
|
id: cache-primes
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: prime-numbers
|
path: prime-numbers
|
||||||
key: primes
|
key: primes
|
||||||
@ -269,7 +274,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache Numbers
|
- name: Cache Numbers
|
||||||
id: cache-numbers
|
id: cache-numbers
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: numbers
|
path: numbers
|
||||||
key: primes
|
key: primes
|
||||||
@ -281,11 +286,11 @@ jobs:
|
|||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cache Primes
|
- name: Cache Primes
|
||||||
id: cache-primes
|
id: cache-primes
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: prime-numbers
|
path: prime-numbers
|
||||||
key: primes
|
key: primes
|
||||||
|
152
RELEASES.md
152
RELEASES.md
@ -1,77 +1,61 @@
|
|||||||
# Releases
|
# Releases
|
||||||
|
|
||||||
### 3.0.0
|
### 4.1.1
|
||||||
|
- Restore original behavior of `cache-hit` output - [#1467](https://github.com/actions/cache/pull/1467)
|
||||||
|
|
||||||
- Updated minimum runner version support from node 12 -> node 16
|
### 4.1.0
|
||||||
|
- Ensure `cache-hit` output is set when a cache is missed - [#1404](https://github.com/actions/cache/pull/1404)
|
||||||
|
- Deprecate `save-always` input - [#1452](https://github.com/actions/cache/pull/1452)
|
||||||
|
|
||||||
### 3.0.1
|
### 4.0.2
|
||||||
|
|
||||||
- Added support for caching from GHES 3.5.
|
- Fixed restore `fail-on-cache-miss` not working.
|
||||||
- Fixed download issue for files > 2GB during restore.
|
|
||||||
|
|
||||||
### 3.0.2
|
### 4.0.1
|
||||||
|
|
||||||
- Added support for dynamic cache size cap on GHES.
|
- Updated `isGhes` check
|
||||||
|
|
||||||
### 3.0.3
|
### 4.0.0
|
||||||
|
|
||||||
- Fixed avoiding empty cache save when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
|
- Updated minimum runner version support from node 12 -> node 20
|
||||||
|
|
||||||
### 3.0.4
|
### 3.3.3
|
||||||
|
|
||||||
- Fixed tar creation error while trying to create tar with path as `~/` home folder on `ubuntu-latest`. ([issue](https://github.com/actions/cache/issues/689))
|
- Updates @actions/cache to v3.2.3 to fix accidental mutated path arguments to `getCacheVersion` [actions/toolkit#1378](https://github.com/actions/toolkit/pull/1378)
|
||||||
|
- Additional audit fixes of npm package(s)
|
||||||
|
|
||||||
### 3.0.5
|
### 3.3.2
|
||||||
|
|
||||||
- Removed error handling by consuming actions/cache 3.0 toolkit, Now cache server error handling will be done by toolkit. ([PR](https://github.com/actions/cache/pull/834))
|
- Fixes bug with Azure SDK causing blob downloads to get stuck.
|
||||||
|
|
||||||
### 3.0.6
|
### 3.3.1
|
||||||
|
|
||||||
- Fixed [#809](https://github.com/actions/cache/issues/809) - zstd -d: no such file or directory error
|
- Reduced segment size to 128MB and segment timeout to 10 minutes to fail fast in case the cache download is stuck.
|
||||||
- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory
|
|
||||||
|
|
||||||
### 3.0.7
|
### 3.3.0
|
||||||
|
|
||||||
- Fixed [#810](https://github.com/actions/cache/issues/810) - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour.
|
- Added option to lookup cache without downloading it.
|
||||||
|
|
||||||
### 3.0.8
|
### 3.2.6
|
||||||
|
|
||||||
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
|
- Fix zstd not being used after zstd version upgrade to 1.5.4 on hosted runners.
|
||||||
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
|
|
||||||
|
|
||||||
### 3.0.9
|
### 3.2.5
|
||||||
|
|
||||||
- Enhanced the warning message for cache unavailablity in case of GHES.
|
- Added fix to prevent from setting MYSYS environment variable globally.
|
||||||
|
|
||||||
### 3.0.10
|
### 3.2.4
|
||||||
|
|
||||||
- Fix a bug with sorting inputs.
|
- Added option to fail job on cache miss.
|
||||||
- Update definition for restore-keys in README.md
|
|
||||||
|
|
||||||
### 3.0.11
|
### 3.2.3
|
||||||
|
|
||||||
- Update toolkit version to 3.0.5 to include `@actions/core@^1.10.0`
|
- Support cross os caching on Windows as an opt-in feature.
|
||||||
- Update `@actions/cache` to use updated `saveState` and `setOutput` functions from `@actions/core@^1.10.0`
|
- Fix issue with symlink restoration on Windows for cross-os caches.
|
||||||
|
|
||||||
### 3.1.0-beta.1
|
### 3.2.2
|
||||||
|
|
||||||
- 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))
|
- Reverted the changes made in 3.2.1 to use gnu tar and zstd by default on windows.
|
||||||
|
|
||||||
### 3.1.0-beta.2
|
|
||||||
|
|
||||||
- Added support for fallback to gzip to restore old caches on windows.
|
|
||||||
|
|
||||||
### 3.1.0-beta.3
|
|
||||||
|
|
||||||
- Bug fixes for bsdtar fallback if gnutar not available and gzip fallback if cache saved using old cache action on windows.
|
|
||||||
|
|
||||||
### 3.2.0-beta.1
|
|
||||||
|
|
||||||
- Added two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache.
|
|
||||||
|
|
||||||
### 3.2.0
|
|
||||||
|
|
||||||
- Released the two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache
|
|
||||||
|
|
||||||
### 3.2.1
|
### 3.2.1
|
||||||
|
|
||||||
@ -79,31 +63,75 @@
|
|||||||
- Added support for fallback to gzip to restore old caches on windows.
|
- Added support for fallback to gzip to restore old caches on windows.
|
||||||
- Added logs for cache version in case of a cache miss.
|
- Added logs for cache version in case of a cache miss.
|
||||||
|
|
||||||
### 3.2.2
|
### 3.2.0
|
||||||
|
|
||||||
- Reverted the changes made in 3.2.1 to use gnu tar and zstd by default on windows.
|
- Released the two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache
|
||||||
|
|
||||||
### 3.2.3
|
### 3.2.0-beta.1
|
||||||
|
|
||||||
- Support cross os caching on Windows as an opt-in feature.
|
- Added two new actions - [restore](restore/action.yml) and [save](save/action.yml) for granular control on cache.
|
||||||
- Fix issue with symlink restoration on Windows for cross-os caches.
|
|
||||||
|
|
||||||
### 3.2.4
|
### 3.1.0-beta.3
|
||||||
|
|
||||||
- Added option to fail job on cache miss.
|
- Bug fixes for bsdtar fallback if gnutar not available and gzip fallback if cache saved using old cache action on windows.
|
||||||
|
|
||||||
### 3.2.5
|
### 3.1.0-beta.2
|
||||||
|
|
||||||
- Added fix to prevent from setting MYSYS environment variable globally.
|
- Added support for fallback to gzip to restore old caches on windows.
|
||||||
|
|
||||||
### 3.2.6
|
### 3.1.0-beta.1
|
||||||
|
|
||||||
- Fix zstd not being used after zstd version upgrade to 1.5.4 on hosted runners.
|
- Update `@actions/cache` on windows to use gnu tar and zstd by default and fallback to bsdtar and zstd if gnu tar is not available. ([issue](https://github.com/actions/cache/issues/984))
|
||||||
|
|
||||||
### 3.3.0
|
### 3.0.11
|
||||||
|
|
||||||
- Added option to lookup cache without downloading it.
|
- Update toolkit version to 3.0.5 to include `@actions/core@^1.10.0`
|
||||||
|
- Update `@actions/cache` to use updated `saveState` and `setOutput` functions from `@actions/core@^1.10.0`
|
||||||
|
|
||||||
### 3.3.1
|
### 3.0.10
|
||||||
|
|
||||||
- Reduced segment size to 128MB and segment timeout to 10 minutes to fail fast in case the cache download is stuck.
|
- Fix a bug with sorting inputs.
|
||||||
|
- Update definition for restore-keys in README.md
|
||||||
|
|
||||||
|
### 3.0.9
|
||||||
|
|
||||||
|
- Enhanced the warning message for cache unavailablity in case of GHES.
|
||||||
|
|
||||||
|
### 3.0.8
|
||||||
|
|
||||||
|
- Fix zstd not working for windows on gnu tar in issues [#888](https://github.com/actions/cache/issues/888) and [#891](https://github.com/actions/cache/issues/891).
|
||||||
|
- Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable `SEGMENT_DOWNLOAD_TIMEOUT_MINS`. Default is 60 minutes.
|
||||||
|
|
||||||
|
### 3.0.7
|
||||||
|
|
||||||
|
- Fixed [#810](https://github.com/actions/cache/issues/810) - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour.
|
||||||
|
|
||||||
|
### 3.0.6
|
||||||
|
|
||||||
|
- Fixed [#809](https://github.com/actions/cache/issues/809) - zstd -d: no such file or directory error
|
||||||
|
- Fixed [#833](https://github.com/actions/cache/issues/833) - cache doesn't work with github workspace directory
|
||||||
|
|
||||||
|
### 3.0.5
|
||||||
|
|
||||||
|
- Removed error handling by consuming actions/cache 3.0 toolkit, Now cache server error handling will be done by toolkit. ([PR](https://github.com/actions/cache/pull/834))
|
||||||
|
|
||||||
|
### 3.0.4
|
||||||
|
|
||||||
|
- Fixed tar creation error while trying to create tar with path as `~/` home folder on `ubuntu-latest`. ([issue](https://github.com/actions/cache/issues/689))
|
||||||
|
|
||||||
|
### 3.0.3
|
||||||
|
|
||||||
|
- Fixed avoiding empty cache save when no files are available for caching. ([issue](https://github.com/actions/cache/issues/624))
|
||||||
|
|
||||||
|
### 3.0.2
|
||||||
|
|
||||||
|
- Added support for dynamic cache size cap on GHES.
|
||||||
|
|
||||||
|
### 3.0.1
|
||||||
|
|
||||||
|
- Added support for caching from GHES 3.5.
|
||||||
|
- Fixed download issue for files > 2GB during restore.
|
||||||
|
|
||||||
|
### 3.0.0
|
||||||
|
|
||||||
|
- Updated minimum runner version support from node 12 -> node 16
|
||||||
|
@ -8,17 +8,26 @@ import * as testUtils from "../src/utils/testUtils";
|
|||||||
jest.mock("@actions/core");
|
jest.mock("@actions/core");
|
||||||
jest.mock("@actions/cache");
|
jest.mock("@actions/cache");
|
||||||
|
|
||||||
|
let pristineEnv: NodeJS.ProcessEnv;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
pristineEnv = process.env;
|
||||||
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
|
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
|
||||||
return jest.requireActual("@actions/core").getInput(name, options);
|
return jest.requireActual("@actions/core").getInput(name, options);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
process.env = pristineEnv;
|
||||||
delete process.env[Events.Key];
|
delete process.env[Events.Key];
|
||||||
delete process.env[RefKey];
|
delete process.env[RefKey];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
process.env = pristineEnv;
|
||||||
|
});
|
||||||
|
|
||||||
test("isGhes returns true if server url is not github.com", () => {
|
test("isGhes returns true if server url is not github.com", () => {
|
||||||
try {
|
try {
|
||||||
process.env["GITHUB_SERVER_URL"] = "http://example.com";
|
process.env["GITHUB_SERVER_URL"] = "http://example.com";
|
||||||
@ -231,3 +240,28 @@ test("isCacheFeatureAvailable for ac disabled on dotcom", () => {
|
|||||||
delete process.env["GITHUB_SERVER_URL"];
|
delete process.env["GITHUB_SERVER_URL"];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("isGhes returns false when the GITHUB_SERVER_URL environment variable is not defined", async () => {
|
||||||
|
delete process.env["GITHUB_SERVER_URL"];
|
||||||
|
expect(actionUtils.isGhes()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isGhes returns false when the GITHUB_SERVER_URL environment variable is set to github.com", async () => {
|
||||||
|
process.env["GITHUB_SERVER_URL"] = "https://github.com";
|
||||||
|
expect(actionUtils.isGhes()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isGhes returns false when the GITHUB_SERVER_URL environment variable is set to a GitHub Enterprise Cloud-style URL", async () => {
|
||||||
|
process.env["GITHUB_SERVER_URL"] = "https://contoso.ghe.com";
|
||||||
|
expect(actionUtils.isGhes()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isGhes returns false when the GITHUB_SERVER_URL environment variable has a .localhost suffix", async () => {
|
||||||
|
process.env["GITHUB_SERVER_URL"] = "https://mock-github.localhost";
|
||||||
|
expect(actionUtils.isGhes()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("isGhes returns true when the GITHUB_SERVER_URL environment variable is set to some other URL", async () => {
|
||||||
|
process.env["GITHUB_SERVER_URL"] = "https://src.onpremise.fabrikam.com";
|
||||||
|
expect(actionUtils.isGhes()).toBeTruthy();
|
||||||
|
});
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, RefKey } from "../src/constants";
|
import { Events, RefKey } from "../src/constants";
|
||||||
import run from "../src/restore";
|
import { restoreRun } from "../src/restoreImpl";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ test("restore with no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -114,7 +114,7 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -156,7 +156,7 @@ test("restore with cache found for key", async () => {
|
|||||||
return Promise.resolve(key);
|
return Promise.resolve(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -201,7 +201,7 @@ test("restore with cache found for restore key", async () => {
|
|||||||
return Promise.resolve(restoreKey);
|
return Promise.resolve(restoreKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -246,7 +246,7 @@ test("Fail restore when fail on cache miss is enabled and primary + restore keys
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -289,7 +289,7 @@ test("restore when fail on cache miss is enabled and primary key doesn't match r
|
|||||||
return Promise.resolve(restoreKey);
|
return Promise.resolve(restoreKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -335,7 +335,7 @@ test("restore with fail on cache miss disabled and no cache found", async () =>
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, RefKey } from "../src/constants";
|
import { Events, Inputs, RefKey } from "../src/constants";
|
||||||
import run from "../src/restoreImpl";
|
import { restoreImpl } from "../src/restoreImpl";
|
||||||
import { StateProvider } from "../src/stateProvider";
|
import { StateProvider } from "../src/stateProvider";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
@ -60,7 +60,7 @@ test("restore with invalid event outputs warning", async () => {
|
|||||||
const invalidEvent = "commit_comment";
|
const invalidEvent = "commit_comment";
|
||||||
process.env[Events.Key] = invalidEvent;
|
process.env[Events.Key] = invalidEvent;
|
||||||
delete process.env[RefKey];
|
delete process.env[RefKey];
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logWarningMock).toHaveBeenCalledWith(
|
||||||
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
|
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
|
||||||
);
|
);
|
||||||
@ -76,7 +76,7 @@ test("restore without AC available should no-op", async () => {
|
|||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
@ -92,7 +92,7 @@ test("restore on GHES without AC available should no-op", async () => {
|
|||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
const setCacheHitOutputMock = jest.spyOn(core, "setOutput");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
expect(setCacheHitOutputMock).toHaveBeenCalledTimes(1);
|
||||||
@ -119,7 +119,7 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
return Promise.resolve(key);
|
return Promise.resolve(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -143,7 +143,7 @@ test("restore on GHES with AC available ", async () => {
|
|||||||
test("restore with no path should fail", async () => {
|
test("restore with no path should fail", async () => {
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
||||||
// this input isn't necessary for restore b/c tarball contains entries relative to workspace
|
// this input isn't necessary for restore b/c tarball contains entries relative to workspace
|
||||||
expect(failedMock).not.toHaveBeenCalledWith(
|
expect(failedMock).not.toHaveBeenCalledWith(
|
||||||
@ -155,7 +155,7 @@ test("restore with no key", async () => {
|
|||||||
testUtils.setInput(Inputs.Path, "node_modules");
|
testUtils.setInput(Inputs.Path, "node_modules");
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(failedMock).toHaveBeenCalledWith(
|
expect(failedMock).toHaveBeenCalledWith(
|
||||||
"Input required and not supplied: key"
|
"Input required and not supplied: key"
|
||||||
@ -174,7 +174,7 @@ test("restore with too many keys should fail", async () => {
|
|||||||
});
|
});
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
[path],
|
[path],
|
||||||
@ -200,7 +200,7 @@ test("restore with large key should fail", async () => {
|
|||||||
});
|
});
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
[path],
|
[path],
|
||||||
@ -226,7 +226,7 @@ test("restore with invalid key should fail", async () => {
|
|||||||
});
|
});
|
||||||
const failedMock = jest.spyOn(core, "setFailed");
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
[path],
|
[path],
|
||||||
@ -260,7 +260,7 @@ test("restore with no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -301,7 +301,7 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -341,7 +341,7 @@ test("restore with cache found for key", async () => {
|
|||||||
return Promise.resolve(key);
|
return Promise.resolve(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -383,7 +383,7 @@ test("restore with cache found for restore key", async () => {
|
|||||||
return Promise.resolve(restoreKey);
|
return Promise.resolve(restoreKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -424,7 +424,7 @@ test("restore with lookup-only set", async () => {
|
|||||||
return Promise.resolve(key);
|
return Promise.resolve(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await restoreImpl(new StateProvider());
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -449,3 +449,19 @@ test("restore with lookup-only set", async () => {
|
|||||||
);
|
);
|
||||||
expect(failedMock).toHaveBeenCalledTimes(0);
|
expect(failedMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("restore failure with earlyExit should call process exit", async () => {
|
||||||
|
testUtils.setInput(Inputs.Path, "node_modules");
|
||||||
|
const failedMock = jest.spyOn(core, "setFailed");
|
||||||
|
const restoreCacheMock = jest.spyOn(cache, "restoreCache");
|
||||||
|
const processExitMock = jest.spyOn(process, "exit").mockImplementation();
|
||||||
|
|
||||||
|
// call restoreImpl with `earlyExit` set to true
|
||||||
|
await restoreImpl(new StateProvider(), true);
|
||||||
|
|
||||||
|
expect(restoreCacheMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(failedMock).toHaveBeenCalledWith(
|
||||||
|
"Input required and not supplied: key"
|
||||||
|
);
|
||||||
|
expect(processExitMock).toHaveBeenCalledWith(1);
|
||||||
|
});
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, RefKey } from "../src/constants";
|
import { Events, RefKey } from "../src/constants";
|
||||||
import run from "../src/restoreOnly";
|
import { restoreOnlyRun } from "../src/restoreImpl";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ test("restore with no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreOnlyRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -114,7 +114,7 @@ test("restore with restore keys and no cache found", async () => {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreOnlyRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -153,7 +153,7 @@ test("restore with cache found for key", async () => {
|
|||||||
return Promise.resolve(key);
|
return Promise.resolve(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreOnlyRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
@ -196,7 +196,7 @@ test("restore with cache found for restore key", async () => {
|
|||||||
return Promise.resolve(restoreKey);
|
return Promise.resolve(restoreKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await restoreOnlyRun();
|
||||||
|
|
||||||
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
expect(restoreCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(restoreCacheMock).toHaveBeenCalledWith(
|
expect(restoreCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, RefKey } from "../src/constants";
|
import { Events, Inputs, RefKey } from "../src/constants";
|
||||||
import run from "../src/save";
|
import { saveRun } from "../src/saveImpl";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
return Promise.resolve(cacheId);
|
return Promise.resolve(cacheId);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await saveRun();
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, RefKey } from "../src/constants";
|
import { Events, Inputs, RefKey } from "../src/constants";
|
||||||
import run from "../src/saveImpl";
|
import { saveImpl } from "../src/saveImpl";
|
||||||
import { StateProvider } from "../src/stateProvider";
|
import { StateProvider } from "../src/stateProvider";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
@ -77,7 +77,7 @@ test("save with invalid event outputs warning", async () => {
|
|||||||
const invalidEvent = "commit_comment";
|
const invalidEvent = "commit_comment";
|
||||||
process.env[Events.Key] = invalidEvent;
|
process.env[Events.Key] = invalidEvent;
|
||||||
delete process.env[RefKey];
|
delete process.env[RefKey];
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logWarningMock).toHaveBeenCalledWith(
|
||||||
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
|
`Event Validation Error: The event type ${invalidEvent} is not supported because it's not tied to a branch or tag ref.`
|
||||||
);
|
);
|
||||||
@ -100,7 +100,7 @@ test("save with no primary key in state outputs warning", async () => {
|
|||||||
});
|
});
|
||||||
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(`Key is not specified.`);
|
expect(logWarningMock).toHaveBeenCalledWith(`Key is not specified.`);
|
||||||
@ -115,7 +115,7 @@ test("save without AC available should no-op", async () => {
|
|||||||
|
|
||||||
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
@ -128,7 +128,7 @@ test("save on ghes without AC available should no-op", async () => {
|
|||||||
|
|
||||||
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
@ -161,7 +161,7 @@ test("save on GHES with AC available", async () => {
|
|||||||
return Promise.resolve(cacheId);
|
return Promise.resolve(cacheId);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
@ -194,7 +194,7 @@ test("save with exact match returns early", async () => {
|
|||||||
});
|
});
|
||||||
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(infoMock).toHaveBeenCalledWith(
|
expect(infoMock).toHaveBeenCalledWith(
|
||||||
@ -221,7 +221,7 @@ test("save with missing input outputs warning", async () => {
|
|||||||
});
|
});
|
||||||
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
const saveCacheMock = jest.spyOn(cache, "saveCache");
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
expect(saveCacheMock).toHaveBeenCalledTimes(0);
|
||||||
expect(logWarningMock).toHaveBeenCalledWith(
|
expect(logWarningMock).toHaveBeenCalledWith(
|
||||||
@ -259,7 +259,7 @@ test("save with large cache outputs warning", async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
@ -306,7 +306,7 @@ test("save with reserve cache failure outputs warning", async () => {
|
|||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
@ -349,7 +349,7 @@ test("save with server error outputs warning", async () => {
|
|||||||
throw new Error("HTTP Error Occurred");
|
throw new Error("HTTP Error Occurred");
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
@ -392,7 +392,7 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
return Promise.resolve(cacheId);
|
return Promise.resolve(cacheId);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run(new StateProvider());
|
await saveImpl(new StateProvider());
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
@ -2,7 +2,7 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, RefKey } from "../src/constants";
|
import { Events, Inputs, RefKey } from "../src/constants";
|
||||||
import run from "../src/saveOnly";
|
import { saveOnlyRun } from "../src/saveImpl";
|
||||||
import * as actionUtils from "../src/utils/actionUtils";
|
import * as actionUtils from "../src/utils/actionUtils";
|
||||||
import * as testUtils from "../src/utils/testUtils";
|
import * as testUtils from "../src/utils/testUtils";
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ test("save with valid inputs uploads a cache", async () => {
|
|||||||
return Promise.resolve(cacheId);
|
return Promise.resolve(cacheId);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await saveOnlyRun();
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
@ -122,7 +122,7 @@ test("save failing logs the warning message", async () => {
|
|||||||
return Promise.resolve(cacheId);
|
return Promise.resolve(cacheId);
|
||||||
});
|
});
|
||||||
|
|
||||||
await run();
|
await saveOnlyRun();
|
||||||
|
|
||||||
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
expect(saveCacheMock).toHaveBeenCalledTimes(1);
|
||||||
expect(saveCacheMock).toHaveBeenCalledWith(
|
expect(saveCacheMock).toHaveBeenCalledWith(
|
||||||
|
14
action.yml
14
action.yml
@ -9,7 +9,7 @@ inputs:
|
|||||||
description: 'An explicit key for restoring and saving the cache'
|
description: 'An explicit key for restoring and saving the cache'
|
||||||
required: true
|
required: true
|
||||||
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 multiline string listing the prefix-matched keys, that are used for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
|
||||||
required: false
|
required: false
|
||||||
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'
|
||||||
@ -26,14 +26,22 @@ inputs:
|
|||||||
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
description: 'Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache'
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
save-always:
|
||||||
|
description: 'Run the post step to save the cache even if another step before fails'
|
||||||
|
default: 'false'
|
||||||
|
required: false
|
||||||
|
deprecationMessage: |
|
||||||
|
save-always does not work as intended and will be removed in a future release.
|
||||||
|
A separate `actions/cache/restore` step should be used instead.
|
||||||
|
See https://github.com/actions/cache/tree/main/save#always-save-cache for more details.
|
||||||
outputs:
|
outputs:
|
||||||
cache-hit:
|
cache-hit:
|
||||||
description: 'A boolean value to indicate an exact match was found for the primary key'
|
description: 'A boolean value to indicate an exact match was found for the primary key'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'dist/restore/index.js'
|
main: 'dist/restore/index.js'
|
||||||
post: 'dist/save/index.js'
|
post: 'dist/save/index.js'
|
||||||
post-if: success()
|
post-if: "success()"
|
||||||
branding:
|
branding:
|
||||||
icon: 'archive'
|
icon: 'archive'
|
||||||
color: 'gray-dark'
|
color: 'gray-dark'
|
||||||
|
@ -12,7 +12,7 @@ This document lists some of the strategies (and example workflows if possible) w
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ some-metadata }}-cache
|
key: ${{ some-metadata }}-cache
|
||||||
```
|
```
|
||||||
@ -24,7 +24,7 @@ In your workflows, you can use different strategies to name your key depending o
|
|||||||
One of the most common use case is to use hash for lockfile as key. This way, same cache will be restored for a lockfile until there's a change in dependencies listed in lockfile.
|
One of the most common use case is to use hash for lockfile as key. This way, same cache will be restored for a lockfile until there's a change in dependencies listed in lockfile.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -37,7 +37,7 @@ One of the most common use case is to use hash for lockfile as key. This way, sa
|
|||||||
If cache is not found matching the primary key, restore keys can be used to download the closest matching cache that was recently created. This ensures that the build/install step will need to additionally fetch just a handful of newer dependencies, and hence saving build time.
|
If cache is not found matching the primary key, restore keys can be used to download the closest matching cache that was recently created. This ensures that the build/install step will need to additionally fetch just a handful of newer dependencies, and hence saving build time.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -54,7 +54,7 @@ The restore keys can be provided as a complete name, or a prefix, read more [her
|
|||||||
In case of workflows with matrix running for multiple Operating Systems, the caches can be stored separately for each of them. This can be used in combination with hashfiles in case multiple caches are being generated per OS.
|
In case of workflows with matrix running for multiple Operating Systems, the caches can be stored separately for each of them. This can be used in combination with hashfiles in case multiple caches are being generated per OS.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -73,7 +73,7 @@ Caches scoped to the particular workflow run id or run attempt can be stored and
|
|||||||
On similar lines, commit sha can be used to create a very specialized and short lived cache.
|
On similar lines, commit sha can be used to create a very specialized and short lived cache.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -81,12 +81,12 @@ On similar lines, commit sha can be used to create a very specialized and short
|
|||||||
key: cache-${{ github.sha }}
|
key: cache-${{ github.sha }}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using multiple factors while forming a key depening on the need
|
### Using multiple factors while forming a key depending on the need
|
||||||
|
|
||||||
Cache key can be formed by combination of more than one metadata, evaluated info.
|
Cache key can be formed by combination of more than one metadata, evaluated info.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -146,9 +146,9 @@ In case you are using a centralized job to create and save your cache that can b
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -171,9 +171,9 @@ You can use the output of this action to exit the workflow on cache miss. This w
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -194,7 +194,7 @@ steps:
|
|||||||
If you want to avoid re-computing the cache key again in `save` action, the outputs from `restore` action can be used as input to the `save` action.
|
If you want to avoid re-computing the cache key again in `save` action, the outputs from `restore` action can be used as input to the `save` action.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: restore-cache
|
id: restore-cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@ -204,7 +204,7 @@ If you want to avoid re-computing the cache key again in `save` action, the outp
|
|||||||
.
|
.
|
||||||
.
|
.
|
||||||
.
|
.
|
||||||
- uses: actions/cache/save@v3
|
- uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
path/to/dependencies
|
path/to/dependencies
|
||||||
@ -219,7 +219,7 @@ On the other hand, the key can also be explicitly re-computed while executing th
|
|||||||
Let's say we have a restore step that computes key at runtime
|
Let's say we have a restore step that computes key at runtime
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: restore-cache
|
id: restore-cache
|
||||||
with:
|
with:
|
||||||
key: cache-${{ hashFiles('**/lockfiles') }}
|
key: cache-${{ hashFiles('**/lockfiles') }}
|
||||||
@ -228,7 +228,7 @@ with:
|
|||||||
Case 1: Where an user would want to reuse the key as it is
|
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@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||||
```
|
```
|
||||||
@ -236,31 +236,14 @@ with:
|
|||||||
Case 2: Where the user would want to re-evaluate the key
|
Case 2: Where the user would want to re-evaluate the key
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
key: npm-cache-${{hashfiles(package-lock.json)}}
|
key: npm-cache-${{hashfiles(package-lock.json)}}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Saving cache even if the build fails
|
### Saving cache even if the build fails
|
||||||
|
|
||||||
There can be cases where a cache should be saved even if the build job fails. For example, a job can fail due to flaky tests but the caches can still be re-used. You can use `actions/cache/save` action to save the cache by using `if: always()` condition.
|
See [Always save cache](./save/README.md#always-save-cache).
|
||||||
|
|
||||||
Similarly, `actions/cache/save` action can be conditionally used based on the output of the previous steps. This way you get more control on when to save the cache.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
.
|
|
||||||
. // restore if need be
|
|
||||||
.
|
|
||||||
- name: Build
|
|
||||||
run: /build.sh
|
|
||||||
- uses: actions/cache/save@v3
|
|
||||||
if: always() // or any other condition to invoke the save action
|
|
||||||
with:
|
|
||||||
path: path/to/dependencies
|
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Saving cache once and reusing in multiple workflows
|
### Saving cache once and reusing in multiple workflows
|
||||||
|
|
||||||
@ -270,12 +253,12 @@ In case of multi-module projects, where the built artifact of one project needs
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./build-parent-module.sh
|
run: ./build-parent-module.sh
|
||||||
|
|
||||||
- uses: actions/cache/save@v3
|
- uses: actions/cache/save@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -286,9 +269,9 @@ steps:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
|
56567
dist/restore-only/index.js
vendored
56567
dist/restore-only/index.js
vendored
File diff suppressed because one or more lines are too long
56591
dist/restore/index.js
vendored
56591
dist/restore/index.js
vendored
File diff suppressed because one or more lines are too long
56499
dist/save-only/index.js
vendored
56499
dist/save-only/index.js
vendored
File diff suppressed because one or more lines are too long
56470
dist/save/index.js
vendored
56470
dist/save/index.js
vendored
File diff suppressed because one or more lines are too long
108
examples.md
108
examples.md
@ -1,5 +1,6 @@
|
|||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
- [Bun](#bun)
|
||||||
- [C# - NuGet](#c---nuget)
|
- [C# - NuGet](#c---nuget)
|
||||||
- [Clojure - Lein Deps](#clojure---lein-deps)
|
- [Clojure - Lein Deps](#clojure---lein-deps)
|
||||||
- [D - DUB](#d---dub)
|
- [D - DUB](#d---dub)
|
||||||
@ -41,12 +42,32 @@
|
|||||||
- [Swift - Mint](#swift---mint)
|
- [Swift - Mint](#swift---mint)
|
||||||
- [* - Bazel](#---bazel)
|
- [* - Bazel](#---bazel)
|
||||||
|
|
||||||
|
## Bun
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.bun/install/cache
|
||||||
|
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~\.bun
|
||||||
|
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
|
||||||
|
```
|
||||||
|
|
||||||
## C# - NuGet
|
## C# - NuGet
|
||||||
|
|
||||||
Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/package-references-in-project-files#locking-dependencies):
|
Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/package-references-in-project-files#locking-dependencies):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.nuget/packages
|
path: ~/.nuget/packages
|
||||||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
||||||
@ -55,10 +76,10 @@ Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/packa
|
|||||||
```
|
```
|
||||||
|
|
||||||
Depending on the environment, huge packages might be pre-installed in the global cache folder.
|
Depending on the environment, huge packages might be pre-installed in the global cache folder.
|
||||||
With `actions/cache@v3` you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/main/packages/glob#exclude-patterns)
|
With `actions/cache@v4` you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/main/packages/glob#exclude-patterns)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.nuget/packages
|
~/.nuget/packages
|
||||||
@ -75,7 +96,7 @@ Or you could move the cache folder like below.
|
|||||||
env:
|
env:
|
||||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/.nuget/packages
|
path: ${{ github.workspace }}/.nuget/packages
|
||||||
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
||||||
@ -87,7 +108,7 @@ steps:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache lein project dependencies
|
- name: Cache lein project dependencies
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.m2/repository
|
path: ~/.m2/repository
|
||||||
key: ${{ runner.os }}-clojure-${{ hashFiles('**/project.clj') }}
|
key: ${{ runner.os }}-clojure-${{ hashFiles('**/project.clj') }}
|
||||||
@ -101,7 +122,7 @@ steps:
|
|||||||
### POSIX
|
### POSIX
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.dub
|
path: ~/.dub
|
||||||
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
|
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
|
||||||
@ -112,7 +133,7 @@ steps:
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~\AppData\Local\dub
|
path: ~\AppData\Local\dub
|
||||||
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
|
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.selections.json') }}
|
||||||
@ -125,7 +146,7 @@ steps:
|
|||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.deno
|
~/.deno
|
||||||
@ -136,7 +157,7 @@ steps:
|
|||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.deno
|
~/.deno
|
||||||
@ -147,7 +168,7 @@ steps:
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~\.deno
|
~\.deno
|
||||||
@ -158,7 +179,7 @@ steps:
|
|||||||
## Elixir - Mix
|
## Elixir - Mix
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
deps
|
deps
|
||||||
@ -185,7 +206,7 @@ steps:
|
|||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
@ -198,7 +219,7 @@ steps:
|
|||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/Library/Caches/go-build
|
~/Library/Caches/go-build
|
||||||
@ -211,7 +232,7 @@ steps:
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~\AppData\Local\go-build
|
~\AppData\Local\go-build
|
||||||
@ -227,7 +248,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache ~/.cabal/packages, ~/.cabal/store and dist-newstyle
|
- name: Cache ~/.cabal/packages, ~/.cabal/store and dist-newstyle
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cabal/packages
|
~/.cabal/packages
|
||||||
@ -242,14 +263,14 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
### Linux or macOS
|
### Linux or macOS
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
name: Cache ~/.stack
|
name: Cache ~/.stack
|
||||||
with:
|
with:
|
||||||
path: ~/.stack
|
path: ~/.stack
|
||||||
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
|
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-stack-global-
|
${{ runner.os }}-stack-global-
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
name: Cache .stack-work
|
name: Cache .stack-work
|
||||||
with:
|
with:
|
||||||
path: .stack-work
|
path: .stack-work
|
||||||
@ -261,7 +282,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
name: Cache %APPDATA%\stack %LOCALAPPDATA%\Programs\stack
|
name: Cache %APPDATA%\stack %LOCALAPPDATA%\Programs\stack
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@ -270,7 +291,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
|
key: ${{ runner.os }}-stack-global-${{ hashFiles('stack.yaml') }}-${{ hashFiles('package.yaml') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-stack-global-
|
${{ runner.os }}-stack-global-
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
name: Cache .stack-work
|
name: Cache .stack-work
|
||||||
with:
|
with:
|
||||||
path: .stack-work
|
path: .stack-work
|
||||||
@ -284,7 +305,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
> **Note** Ensure no Gradle daemons are running anymore when your workflow completes. Creating the cache package might fail due to locks being held by Gradle. Refer to the [Gradle Daemon documentation](https://docs.gradle.org/current/userguide/gradle_daemon.html) on how to disable or stop the Gradle Daemons.
|
> **Note** Ensure no Gradle daemons are running anymore when your workflow completes. Creating the cache package might fail due to locks being held by Gradle. Refer to the [Gradle Daemon documentation](https://docs.gradle.org/current/userguide/gradle_daemon.html) on how to disable or stop the Gradle Daemons.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches
|
~/.gradle/caches
|
||||||
@ -298,7 +319,7 @@ We cache the elements of the Cabal store separately, as the entirety of `~/.caba
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache local Maven repository
|
- name: Cache local Maven repository
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.m2/repository
|
path: ~/.m2/repository
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||||
@ -334,7 +355,7 @@ After [deprecation](https://github.blog/changelog/2022-10-11-github-actions-depr
|
|||||||
`Get npm cache directory` step can then be used with `actions/cache` as shown below
|
`Get npm cache directory` step can then be used with `actions/cache` as shown below
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
|
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.npm-cache-dir.outputs.dir }}
|
path: ${{ steps.npm-cache-dir.outputs.dir }}
|
||||||
@ -347,7 +368,7 @@ After [deprecation](https://github.blog/changelog/2022-10-11-github-actions-depr
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: restore lerna
|
- name: restore lerna
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: '**/node_modules'
|
path: '**/node_modules'
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
||||||
@ -361,7 +382,7 @@ The yarn cache directory will depend on your operating system and version of `ya
|
|||||||
id: yarn-cache-dir-path
|
id: yarn-cache-dir-path
|
||||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
@ -379,7 +400,7 @@ The yarn 2 cache directory will depend on your config. See https://yarnpkg.com/c
|
|||||||
id: yarn-cache-dir-path
|
id: yarn-cache-dir-path
|
||||||
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
run: echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
@ -394,7 +415,7 @@ Esy allows you to export built dependencies and import pre-built dependencies.
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Restore Cache
|
- name: Restore Cache
|
||||||
id: restore-cache
|
id: restore-cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: _export
|
path: _export
|
||||||
key: ${{ runner.os }}-esy-${{ hashFiles('esy.lock/index.json') }}
|
key: ${{ runner.os }}-esy-${{ hashFiles('esy.lock/index.json') }}
|
||||||
@ -423,7 +444,7 @@ Esy allows you to export built dependencies and import pre-built dependencies.
|
|||||||
id: composer-cache
|
id: composer-cache
|
||||||
run: |
|
run: |
|
||||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
path: ${{ steps.composer-cache.outputs.dir }}
|
||||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||||
@ -444,7 +465,7 @@ Locations:
|
|||||||
### Simple example
|
### Simple example
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
path: ~/.cache/pip
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
@ -457,7 +478,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
|
|||||||
### Multiple OS's in a workflow
|
### Multiple OS's in a workflow
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
if: startsWith(runner.os, 'Linux')
|
if: startsWith(runner.os, 'Linux')
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
path: ~/.cache/pip
|
||||||
@ -465,7 +486,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-pip-
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
if: startsWith(runner.os, 'macOS')
|
if: startsWith(runner.os, 'macOS')
|
||||||
with:
|
with:
|
||||||
path: ~/Library/Caches/pip
|
path: ~/Library/Caches/pip
|
||||||
@ -473,7 +494,7 @@ Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-pip-
|
${{ runner.os }}-pip-
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
if: startsWith(runner.os, 'Windows')
|
if: startsWith(runner.os, 'Windows')
|
||||||
with:
|
with:
|
||||||
path: ~\AppData\Local\pip\Cache
|
path: ~\AppData\Local\pip\Cache
|
||||||
@ -499,7 +520,7 @@ jobs:
|
|||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
path: ~\AppData\Local\pip\Cache
|
path: ~\AppData\Local\pip\Cache
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ matrix.path }}
|
path: ${{ matrix.path }}
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
@ -513,11 +534,12 @@ jobs:
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Get pip cache dir
|
- name: Get pip cache dir
|
||||||
id: pip-cache
|
id: pip-cache
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
|
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: pip cache
|
- name: pip cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.pip-cache.outputs.dir }}
|
path: ${{ steps.pip-cache.outputs.dir }}
|
||||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
@ -535,7 +557,7 @@ jobs:
|
|||||||
|
|
||||||
⋮
|
⋮
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.local/share/virtualenvs
|
path: ~/.local/share/virtualenvs
|
||||||
key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
|
key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
|
||||||
@ -562,7 +584,7 @@ For renv, the cache directory will vary by OS. The `RENV_PATHS_ROOT` environment
|
|||||||
cat("##[set-output name=r-version;]", R.Version()$version.string, sep = "")
|
cat("##[set-output name=r-version;]", R.Version()$version.string, sep = "")
|
||||||
shell: Rscript {0}
|
shell: Rscript {0}
|
||||||
- name: Restore Renv package cache
|
- name: Restore Renv package cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ env.RENV_PATHS_ROOT }}
|
path: ${{ env.RENV_PATHS_ROOT }}
|
||||||
key: ${{ steps.get-version.outputs.os-version }}-${{ steps.get-version.outputs.r-version }}-${{ inputs.cache-version }}-${{ hashFiles('renv.lock') }}
|
key: ${{ steps.get-version.outputs.os-version }}-${{ steps.get-version.outputs.r-version }}-${{ inputs.cache-version }}-${{ hashFiles('renv.lock') }}
|
||||||
@ -588,7 +610,7 @@ whenever possible:
|
|||||||
## Rust - Cargo
|
## Rust - Cargo
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/bin/
|
~/.cargo/bin/
|
||||||
@ -603,7 +625,7 @@ whenever possible:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache SBT
|
- name: Cache SBT
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.ivy2/cache
|
~/.ivy2/cache
|
||||||
@ -614,7 +636,7 @@ whenever possible:
|
|||||||
## Swift, Objective-C - Carthage
|
## Swift, Objective-C - Carthage
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: Carthage
|
path: Carthage
|
||||||
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
|
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
|
||||||
@ -625,7 +647,7 @@ whenever possible:
|
|||||||
## Swift, Objective-C - CocoaPods
|
## Swift, Objective-C - CocoaPods
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: Pods
|
path: Pods
|
||||||
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
||||||
@ -636,7 +658,7 @@ whenever possible:
|
|||||||
## Swift - Swift Package Manager
|
## Swift - Swift Package Manager
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .build
|
path: .build
|
||||||
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
|
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
|
||||||
@ -651,7 +673,7 @@ env:
|
|||||||
MINT_PATH: .mint/lib
|
MINT_PATH: .mint/lib
|
||||||
MINT_LINK_PATH: .mint/bin
|
MINT_LINK_PATH: .mint/bin
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .mint
|
path: .mint
|
||||||
key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
|
key: ${{ runner.os }}-mint-${{ hashFiles('**/Mintfile') }}
|
||||||
@ -667,7 +689,7 @@ steps:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache Bazel
|
- name: Cache Bazel
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/bazel
|
~/.cache/bazel
|
||||||
@ -681,7 +703,7 @@ steps:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Cache Bazel
|
- name: Cache Bazel
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
/private/var/tmp/_bazel_runner/
|
/private/var/tmp/_bazel_runner/
|
||||||
|
1189
package-lock.json
generated
1189
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cache",
|
"name": "cache",
|
||||||
"version": "3.3.1",
|
"version": "4.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Cache dependencies and build outputs",
|
"description": "Cache dependencies and build outputs",
|
||||||
"main": "dist/restore/index.js",
|
"main": "dist/restore/index.js",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
"author": "GitHub",
|
"author": "GitHub",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/cache": "^3.2.1",
|
"@actions/cache": "^3.2.3",
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^1.1.2"
|
"@actions/io": "^1.1.2"
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"@types/node": "^16.18.3",
|
"@types/node": "^16.18.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "^5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
"@zeit/ncc": "^0.20.5",
|
"@vercel/ncc": "^0.38.1",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
|
@ -35,9 +35,9 @@ If you are using separate jobs to create and save your cache(s) to be reused by
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -64,12 +64,12 @@ In case of multi-module projects, where the built artifact of one project needs
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: /build-parent-module.sh
|
run: /build-parent-module.sh
|
||||||
|
|
||||||
- uses: actions/cache/save@v3
|
- uses: actions/cache/save@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -80,9 +80,9 @@ steps:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -107,9 +107,9 @@ To fail if there is no cache hit for the primary key, leave `restore-keys` empty
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/cache/restore@v3
|
- uses: actions/cache/restore@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
|
@ -9,7 +9,7 @@ inputs:
|
|||||||
description: 'An explicit key for restoring the cache'
|
description: 'An explicit key for restoring the cache'
|
||||||
required: true
|
required: true
|
||||||
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 multiline string listing the prefix-matched keys, that are used for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.'
|
||||||
required: false
|
required: false
|
||||||
enableCrossOsArchive:
|
enableCrossOsArchive:
|
||||||
description: 'An optional boolean when enabled, allows windows runners to restore caches that were saved on other platforms'
|
description: 'An optional boolean when enabled, allows windows runners to restore caches that were saved on other platforms'
|
||||||
@ -31,7 +31,7 @@ outputs:
|
|||||||
cache-matched-key:
|
cache-matched-key:
|
||||||
description: 'Key of the cache that was restored, it could either be the primary key on cache-hit or a partial/complete match of one of the restore keys'
|
description: 'Key of the cache that was restored, it could either be the primary key on cache-hit or a partial/complete match of one of the restore keys'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: '../dist/restore-only/index.js'
|
main: '../dist/restore-only/index.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'archive'
|
icon: 'archive'
|
||||||
|
@ -23,7 +23,7 @@ If you are using separate jobs for generating common artifacts and sharing them
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: /install.sh
|
run: /install.sh
|
||||||
@ -31,7 +31,7 @@ steps:
|
|||||||
- name: Build artifacts
|
- name: Build artifacts
|
||||||
run: /build.sh
|
run: /build.sh
|
||||||
|
|
||||||
- uses: actions/cache/save@v3
|
- uses: actions/cache/save@v4
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
path: path/to/dependencies
|
||||||
@ -47,7 +47,7 @@ Let's say we have a restore step that computes a key at runtime.
|
|||||||
#### Restore a cache
|
#### Restore a cache
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: restore-cache
|
id: restore-cache
|
||||||
with:
|
with:
|
||||||
key: cache-${{ hashFiles('**/lockfiles') }}
|
key: cache-${{ hashFiles('**/lockfiles') }}
|
||||||
@ -55,7 +55,7 @@ with:
|
|||||||
|
|
||||||
#### Case 1 - Where a user would want to reuse the key as it is
|
#### Case 1 - Where a user would want to reuse the key as it is
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||||
```
|
```
|
||||||
@ -63,26 +63,52 @@ with:
|
|||||||
#### Case 2 - Where the user would want to re-evaluate the key
|
#### Case 2 - Where the user would want to re-evaluate the key
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
with:
|
with:
|
||||||
key: npm-cache-${{hashfiles(package-lock.json)}}
|
key: npm-cache-${{hashfiles(package-lock.json)}}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Always save cache
|
### Always save cache
|
||||||
|
|
||||||
There are instances where some flaky test cases would fail the entire workflow and users would get frustrated because the builds would run for hours and the cache couldn't be saved as the workflow failed in between. For such use-cases, users now have the ability to use the `actions/cache/save` action to save the cache by using an `if: always()` condition. This way the cache will always be saved if generated, or a warning will be generated that nothing is found on the cache path. Users can also use the `if` condition to only execute the `actions/cache/save` action depending on the output of previous steps. This way they get more control of when to save the cache.
|
There are instances where some flaky test cases would fail the entire workflow and users would get frustrated because the builds would run for hours and the cache couldn't be saved as the workflow failed in between.
|
||||||
|
For such use-cases, users now have the ability to use the `actions/cache/save` action to save the cache by using an [`always()`](https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/expressions#always) condition.
|
||||||
|
This way the cache will always be saved if generated, or a warning will be generated that nothing is found on the cache path. Users can also use the `if` condition to only execute the `actions/cache/save` action depending on the output of previous steps. This way they get more control of when to save the cache.
|
||||||
|
|
||||||
|
To avoid saving a cache that already exists, the `cache-hit` output from a restore step should be checked.
|
||||||
|
|
||||||
|
The `cache-primary-key` output from the restore step should also be used to ensure
|
||||||
|
the cache key does not change during the build if it's calculated based on file contents.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
name: Always Caching Primes
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
.
|
|
||||||
. // restore if need be
|
- name: Restore cached Primes
|
||||||
.
|
id: cache-primes-restore
|
||||||
- name: Build
|
uses: actions/cache/restore@v4
|
||||||
run: /build.sh
|
|
||||||
- uses: actions/cache/save@v3
|
|
||||||
if: always() // or any other condition to invoke the save action
|
|
||||||
with:
|
with:
|
||||||
path: path/to/dependencies
|
key: ${{ runner.os }}-primes
|
||||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
path: |
|
||||||
|
path/to/dependencies
|
||||||
|
some/other/dependencies
|
||||||
|
|
||||||
|
# Intermediate workflow steps
|
||||||
|
|
||||||
|
- name: Always Save Primes
|
||||||
|
id: cache-primes-save
|
||||||
|
if: always() && steps.cache-primes-restore.outputs.cache-hit != 'true'
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
with:
|
||||||
|
key: ${{ steps.cache-primes-restore.outputs.cache-primary-key }}
|
||||||
|
path: |
|
||||||
|
path/to/dependencies
|
||||||
|
some/other/dependencies
|
||||||
```
|
```
|
||||||
|
@ -16,7 +16,7 @@ inputs:
|
|||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: '../dist/save-only/index.js'
|
main: '../dist/save-only/index.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'archive'
|
icon: 'archive'
|
||||||
|
@ -1,10 +1,3 @@
|
|||||||
import restoreImpl from "./restoreImpl";
|
import { restoreRun } from "./restoreImpl";
|
||||||
import { StateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
restoreRun(true);
|
||||||
await restoreImpl(new StateProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
||||||
|
@ -2,11 +2,16 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, Outputs, State } from "./constants";
|
import { Events, Inputs, Outputs, State } from "./constants";
|
||||||
import { IStateProvider } from "./stateProvider";
|
import {
|
||||||
|
IStateProvider,
|
||||||
|
NullStateProvider,
|
||||||
|
StateProvider
|
||||||
|
} from "./stateProvider";
|
||||||
import * as utils from "./utils/actionUtils";
|
import * as utils from "./utils/actionUtils";
|
||||||
|
|
||||||
async function restoreImpl(
|
export async function restoreImpl(
|
||||||
stateProvider: IStateProvider
|
stateProvider: IStateProvider,
|
||||||
|
earlyExit?: boolean | undefined
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
try {
|
try {
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
@ -46,6 +51,9 @@ async function restoreImpl(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!cacheKey) {
|
if (!cacheKey) {
|
||||||
|
// `cache-hit` is intentionally not set to `false` here to preserve existing behavior
|
||||||
|
// See https://github.com/actions/cache/issues/1466
|
||||||
|
|
||||||
if (failOnCacheMiss) {
|
if (failOnCacheMiss) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to restore cache entry. Exiting as fail-on-cache-miss is set. Input key: ${primaryKey}`
|
`Failed to restore cache entry. Exiting as fail-on-cache-miss is set. Input key: ${primaryKey}`
|
||||||
@ -57,7 +65,6 @@ async function restoreImpl(
|
|||||||
...restoreKeys
|
...restoreKeys
|
||||||
].join(", ")}`
|
].join(", ")}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +86,36 @@ async function restoreImpl(
|
|||||||
return cacheKey;
|
return cacheKey;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
core.setFailed((error as Error).message);
|
core.setFailed((error as Error).message);
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default restoreImpl;
|
async function run(
|
||||||
|
stateProvider: IStateProvider,
|
||||||
|
earlyExit: boolean | undefined
|
||||||
|
): Promise<void> {
|
||||||
|
await restoreImpl(stateProvider, earlyExit);
|
||||||
|
|
||||||
|
// node will stay alive if any promises are not resolved,
|
||||||
|
// which is a possibility if HTTP requests are dangling
|
||||||
|
// due to retries or timeouts. We know that if we got here
|
||||||
|
// that all promises that we care about have successfully
|
||||||
|
// resolved, so simply exit with success.
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function restoreOnlyRun(
|
||||||
|
earlyExit?: boolean | undefined
|
||||||
|
): Promise<void> {
|
||||||
|
await run(new NullStateProvider(), earlyExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function restoreRun(
|
||||||
|
earlyExit?: boolean | undefined
|
||||||
|
): Promise<void> {
|
||||||
|
await run(new StateProvider(), earlyExit);
|
||||||
|
}
|
||||||
|
@ -1,10 +1,3 @@
|
|||||||
import restoreImpl from "./restoreImpl";
|
import { restoreOnlyRun } from "./restoreImpl";
|
||||||
import { NullStateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
restoreOnlyRun(true);
|
||||||
await restoreImpl(new NullStateProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
||||||
|
11
src/save.ts
11
src/save.ts
@ -1,10 +1,3 @@
|
|||||||
import saveImpl from "./saveImpl";
|
import { saveRun } from "./saveImpl";
|
||||||
import { StateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
saveRun(true);
|
||||||
await saveImpl(new StateProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
||||||
|
@ -2,7 +2,11 @@ import * as cache from "@actions/cache";
|
|||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { Events, Inputs, State } from "./constants";
|
import { Events, Inputs, State } from "./constants";
|
||||||
import { IStateProvider } from "./stateProvider";
|
import {
|
||||||
|
IStateProvider,
|
||||||
|
NullStateProvider,
|
||||||
|
StateProvider
|
||||||
|
} from "./stateProvider";
|
||||||
import * as utils from "./utils/actionUtils";
|
import * as utils from "./utils/actionUtils";
|
||||||
|
|
||||||
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
// Catch and log any unhandled exceptions. These exceptions can leak out of the uploadChunk method in
|
||||||
@ -10,7 +14,9 @@ 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<number | void> {
|
export async function saveImpl(
|
||||||
|
stateProvider: IStateProvider
|
||||||
|
): Promise<number | void> {
|
||||||
let cacheId = -1;
|
let cacheId = -1;
|
||||||
try {
|
try {
|
||||||
if (!utils.isCacheFeatureAvailable()) {
|
if (!utils.isCacheFeatureAvailable()) {
|
||||||
@ -72,4 +78,47 @@ async function saveImpl(stateProvider: IStateProvider): Promise<number | void> {
|
|||||||
return cacheId;
|
return cacheId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default saveImpl;
|
export async function saveOnlyRun(
|
||||||
|
earlyExit?: boolean | undefined
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const cacheId = await saveImpl(new NullStateProvider());
|
||||||
|
if (cacheId === -1) {
|
||||||
|
core.warning(`Cache save failed.`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// node will stay alive if any promises are not resolved,
|
||||||
|
// which is a possibility if HTTP requests are dangling
|
||||||
|
// due to retries or timeouts. We know that if we got here
|
||||||
|
// that all promises that we care about have successfully
|
||||||
|
// resolved, so simply exit with success.
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveRun(earlyExit?: boolean | undefined): Promise<void> {
|
||||||
|
try {
|
||||||
|
await saveImpl(new StateProvider());
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// node will stay alive if any promises are not resolved,
|
||||||
|
// which is a possibility if HTTP requests are dangling
|
||||||
|
// due to retries or timeouts. We know that if we got here
|
||||||
|
// that all promises that we care about have successfully
|
||||||
|
// resolved, so simply exit with success.
|
||||||
|
if (earlyExit) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
import * as core from "@actions/core";
|
import { saveOnlyRun } from "./saveImpl";
|
||||||
|
|
||||||
import saveImpl from "./saveImpl";
|
saveOnlyRun(true);
|
||||||
import { NullStateProvider } from "./stateProvider";
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
const cacheId = await saveImpl(new NullStateProvider());
|
|
||||||
if (cacheId === -1) {
|
|
||||||
core.warning(`Cache save failed.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
|
|
||||||
export default run;
|
|
||||||
|
@ -7,7 +7,13 @@ export function isGhes(): boolean {
|
|||||||
const ghUrl = new URL(
|
const ghUrl = new URL(
|
||||||
process.env["GITHUB_SERVER_URL"] || "https://github.com"
|
process.env["GITHUB_SERVER_URL"] || "https://github.com"
|
||||||
);
|
);
|
||||||
return ghUrl.hostname.toUpperCase() !== "GITHUB.COM";
|
|
||||||
|
const hostname = ghUrl.hostname.trimEnd().toUpperCase();
|
||||||
|
const isGitHubHost = hostname === "GITHUB.COM";
|
||||||
|
const isGitHubEnterpriseCloudHost = hostname.endsWith(".GHE.COM");
|
||||||
|
const isLocalHost = hostname.endsWith(".LOCALHOST");
|
||||||
|
|
||||||
|
return !isGitHubHost && !isGitHubEnterpriseCloudHost && !isLocalHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isExactKeyMatch(key: string, cacheKey?: string): boolean {
|
export function isExactKeyMatch(key: string, cacheKey?: string): boolean {
|
||||||
|
@ -12,7 +12,7 @@ A cache today is immutable and cannot be updated. But some use cases require the
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: update cache on every commit
|
- name: update cache on every commit
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: prime-numbers
|
path: prime-numbers
|
||||||
key: primes-${{ runner.os }}-${{ github.run_id }} # Can use time based key as well
|
key: primes-${{ runner.os }}-${{ github.run_id }} # Can use time based key as well
|
||||||
@ -61,7 +61,7 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
run: |
|
run: |
|
||||||
|
Loading…
Reference in New Issue
Block a user