mirror of
https://github.com/actions/cache.git
synced 2024-11-13 01:24:04 +01:00
25c295a81d
This example could be used by projects that build Rust end product crates on an OS matrix, but share the cargo cache. To avoid fetching the dependencies from the network in each matrix job in case of a cache miss, a dedicated job pre-populates the cache on Linux, to be reused by the jobs in the matrix. Also demonstrate separate proximate caching of the registry index.
582 lines
15 KiB
Markdown
582 lines
15 KiB
Markdown
# Examples
|
|
|
|
- [Examples](#examples)
|
|
- [C# - NuGet](#c---nuget)
|
|
- [D - DUB](#d---dub)
|
|
- [Elixir - Mix](#elixir---mix)
|
|
- [Go - Modules](#go---modules)
|
|
- [Haskell - Cabal](#haskell---cabal)
|
|
- [Java - Gradle](#java---gradle)
|
|
- [Java - Maven](#java---maven)
|
|
- [Node - npm](#node---npm)
|
|
- [macOS and Ubuntu](#macos-and-ubuntu)
|
|
- [Windows](#windows)
|
|
- [Using multiple systems and `npm config`](#using-multiple-systems-and-npm-config)
|
|
- [Node - Lerna](#node---lerna)
|
|
- [Node - Yarn](#node---yarn)
|
|
- [OCaml/Reason - esy](#ocamlreason---esy)
|
|
- [PHP - Composer](#php---composer)
|
|
- [Python - pip](#python---pip)
|
|
- [Simple example](#simple-example)
|
|
- [Multiple OS's in a workflow](#multiple-oss-in-a-workflow)
|
|
- [Using pip to get cache location](#using-pip-to-get-cache-location)
|
|
- [Using a script to get cache location](#using-a-script-to-get-cache-location)
|
|
- [R - renv](#r---renv)
|
|
- [Simple example](#simple-example-1)
|
|
- [Multiple OS's in a workflow](#multiple-oss-in-a-workflow-1)
|
|
- [Ruby - Bundler](#ruby---bundler)
|
|
- [Rust - Cargo](#rust---cargo)
|
|
- [Scala - SBT](#scala---sbt)
|
|
- [Swift, Objective-C - Carthage](#swift-objective-c---carthage)
|
|
- [Swift, Objective-C - CocoaPods](#swift-objective-c---cocoapods)
|
|
- [Swift - Swift Package Manager](#swift---swift-package-manager)
|
|
|
|
## C# - NuGet
|
|
Using [NuGet lock files](https://docs.microsoft.com/nuget/consume-packages/package-references-in-project-files#locking-dependencies):
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.nuget/packages
|
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-nuget-
|
|
```
|
|
|
|
Depending on the environment, huge packages might be pre-installed in the global cache folder.
|
|
With `actions/cache@v2` you can now exclude unwanted packages with [exclude pattern](https://github.com/actions/toolkit/tree/master/packages/glob#exclude-patterns)
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
~/.nuget/packages
|
|
!~/.nuget/packages/unwanted
|
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-nuget-
|
|
```
|
|
|
|
Or you could move the cache folder like below.
|
|
>Note: This workflow does not work for projects that require files to be placed in user profile package folder
|
|
```yaml
|
|
env:
|
|
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
|
steps:
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ${{ github.workspace }}/.nuget/packages
|
|
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-nuget-
|
|
```
|
|
|
|
## D - DUB
|
|
|
|
### POSIX
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.dub
|
|
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-dub-
|
|
```
|
|
|
|
### Windows
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~\AppData\Local\dub
|
|
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-dub-
|
|
```
|
|
|
|
## Elixir - Mix
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: deps
|
|
key: ${{ runner.os }}-mix-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
|
|
restore-keys: |
|
|
${{ runner.os }}-mix-
|
|
```
|
|
|
|
## Go - Modules
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-go-
|
|
```
|
|
|
|
## Haskell - Cabal
|
|
|
|
We cache the elements of the Cabal store separately, as the entirety of `~/.cabal` can grow very large for projects with many dependencies.
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
name: Cache ~/.cabal/packages, ~/.cabal/store and dist-newstyle
|
|
with:
|
|
path: |
|
|
~/.cabal/packages
|
|
~/.cabal/store
|
|
dist-newstyle
|
|
key: ${{ runner.os }}-${{ matrix.ghc }}
|
|
```
|
|
|
|
## Java - Gradle
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.gradle/caches
|
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-gradle-
|
|
```
|
|
|
|
## Java - Maven
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.m2/repository
|
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-maven-
|
|
```
|
|
|
|
## Node - npm
|
|
|
|
For npm, cache files are stored in `~/.npm` on Posix, or `%AppData%/npm-cache` on Windows. See https://docs.npmjs.com/cli/cache#cache
|
|
|
|
If using `npm config` to retrieve the cache directory, ensure you run [actions/setup-node](https://github.com/actions/setup-node) first to ensure your `npm` version is correct.
|
|
|
|
>Note: It is not recommended to cache `node_modules`, as it can break across Node versions and won't work with `npm ci`
|
|
|
|
### macOS and Ubuntu
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.npm
|
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-
|
|
```
|
|
|
|
### Windows
|
|
|
|
```yaml
|
|
- name: Get npm cache directory
|
|
id: npm-cache
|
|
run: |
|
|
echo "::set-output name=dir::$(npm config get cache)"
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ${{ steps.npm-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-
|
|
```
|
|
|
|
### Using multiple systems and `npm config`
|
|
|
|
```yaml
|
|
- name: Get npm cache directory
|
|
id: npm-cache
|
|
run: |
|
|
echo "::set-output name=dir::$(npm config get cache)"
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ${{ steps.npm-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-node-
|
|
```
|
|
|
|
## Node - Lerna
|
|
|
|
```yaml
|
|
- name: restore lerna
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
node_modules
|
|
*/*/node_modules
|
|
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
|
|
```
|
|
|
|
## Node - Yarn
|
|
The yarn cache directory will depend on your operating system and version of `yarn`. See https://yarnpkg.com/lang/en/docs/cli/cache/ for more info.
|
|
|
|
```yaml
|
|
- name: Get yarn cache directory path
|
|
id: yarn-cache-dir-path
|
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
|
|
|
- uses: actions/cache@v2
|
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
|
with:
|
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-yarn-
|
|
```
|
|
|
|
## OCaml/Reason - esy
|
|
Esy allows you to export built dependencies and import pre-built dependencies.
|
|
```yaml
|
|
- name: Restore Cache
|
|
id: restore-cache
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: _export
|
|
key: ${{ runner.os }}-esy-${{ hashFiles('esy.lock/index.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-esy-
|
|
- name: Esy install
|
|
run: 'esy install'
|
|
- name: Import Cache
|
|
run: |
|
|
esy import-dependencies _export
|
|
rm -rf _export
|
|
|
|
...(Build job)...
|
|
|
|
# Re-export dependencies if anything has changed or if it is the first time
|
|
- name: Setting dependency cache
|
|
run: |
|
|
esy export-dependencies
|
|
if: steps.restore-cache.outputs.cache-hit != 'true'
|
|
```
|
|
|
|
|
|
## PHP - Composer
|
|
|
|
```yaml
|
|
- name: Get Composer Cache Directory
|
|
id: composer-cache
|
|
run: |
|
|
echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ${{ steps.composer-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-composer-
|
|
```
|
|
|
|
## Python - pip
|
|
|
|
For pip, the cache directory will vary by OS. See https://pip.pypa.io/en/stable/reference/pip_install/#caching
|
|
|
|
Locations:
|
|
- Ubuntu: `~/.cache/pip`
|
|
- Windows: `~\AppData\Local\pip\Cache`
|
|
- macOS: `~/Library/Caches/pip`
|
|
|
|
### Simple example
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.cache/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
```
|
|
|
|
Replace `~/.cache/pip` with the correct `path` if not using Ubuntu.
|
|
|
|
### Multiple OS's in a workflow
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'Linux')
|
|
with:
|
|
path: ~/.cache/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'macOS')
|
|
with:
|
|
path: ~/Library/Caches/pip
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'Windows')
|
|
with:
|
|
path: ~\AppData\Local\pip\Cache
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
```
|
|
|
|
### Using pip to get cache location
|
|
|
|
> Note: This requires pip 20.1+
|
|
```yaml
|
|
- name: Get pip cache dir
|
|
id: pip-cache
|
|
run: |
|
|
echo "::set-output name=dir::$(pip cache dir)"
|
|
|
|
- name: pip cache
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: ${{ steps.pip-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
```
|
|
|
|
### Using a script to get cache location
|
|
|
|
> Note: This uses an internal pip API and may not always work
|
|
```yaml
|
|
- name: Get pip cache dir
|
|
id: pip-cache
|
|
run: |
|
|
python -c "from pip._internal.locations import USER_CACHE_DIR; print('::set-output name=dir::' + USER_CACHE_DIR)"
|
|
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ${{ steps.pip-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pip-
|
|
```
|
|
|
|
## R - renv
|
|
|
|
For renv, the cache directory will vary by OS. Look at https://rstudio.github.io/renv/articles/renv.html#cache
|
|
|
|
Locations:
|
|
- Ubuntu: `~/.local/share/renv`
|
|
- macOS: `~/Library/Application Support/renv`
|
|
- Windows: `%LOCALAPPDATA%/renv`
|
|
|
|
### Simple example
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: ~/.local/share/renv
|
|
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-renv-
|
|
```
|
|
|
|
Replace `~/.local/share/renv` with the correct `path` if not using Ubuntu.
|
|
|
|
### Multiple OS's in a workflow
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'Linux')
|
|
with:
|
|
path: ~/.local/share/renv
|
|
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-renv-
|
|
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'macOS')
|
|
with:
|
|
path: ~/Library/Application Support/renv
|
|
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-renv-
|
|
|
|
- uses: actions/cache@v2
|
|
if: startsWith(runner.os, 'Windows')
|
|
with:
|
|
path: ~\AppData\Local\renv
|
|
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-renv-
|
|
```
|
|
|
|
## Ruby - Bundler
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: vendor/bundle
|
|
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-gems-
|
|
```
|
|
When dependencies are installed later in the workflow, we must specify the same path for the bundler.
|
|
|
|
```yaml
|
|
- name: Bundle install
|
|
run: |
|
|
bundle config path vendor/bundle
|
|
bundle install --jobs 4 --retry 3
|
|
```
|
|
|
|
## Rust - Cargo
|
|
|
|
### Simple end product build
|
|
|
|
If `Cargo.lock` is checked into git, its hash can be used as a key
|
|
to cache filesystem state suitable for the build. Use the `--locked` option
|
|
with cargo build and test commands to ensure that the state cached at the
|
|
post step corresponds to the contents of `Cargo.lock` that were hashed for
|
|
the key.
|
|
|
|
```yaml
|
|
- name: Cache cargo dependencies
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
~/.cargo/registry/index
|
|
~/.cargo/registry/cache
|
|
~/.cargo/git/db
|
|
key: cargo-deps-${{ hashFiles('**/Cargo.lock') }}
|
|
- name: Cache cargo build
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: target
|
|
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
|
|
```
|
|
|
|
### A separate job to fetch and cache the dependencies
|
|
|
|
The files cached from `$CARGO_HOME` are platform-independent.
|
|
If cargo build/test jobs are run on a matrix and `Cargo.lock` changes often,
|
|
it might make sense to populate the cache with the matching state in one job,
|
|
then reuse it in the matrix jobs.
|
|
|
|
This example also uses a separate cache to avoid expensive syncs with the
|
|
`crates.io-index` repository.
|
|
|
|
```yaml
|
|
jobs:
|
|
update-deps:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v2
|
|
|
|
- id: cargo-deps
|
|
name: Cache cargo dependencies
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
~/.cargo/registry/index
|
|
~/.cargo/registry/cache
|
|
~/.cargo/git/db
|
|
key: cargo-deps-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- if: ${{ steps.cargo-deps.outputs.cache-hit != 'true' }}
|
|
id: ls-crates-io-index
|
|
name: Get head commit hash of crates.io registry index
|
|
shell: bash
|
|
run: |
|
|
commit=$(
|
|
git ls-remote --heads https://github.com/rust-lang/crates.io-index.git master |
|
|
cut -f 1
|
|
)
|
|
echo "::set-output name=head::$commit"
|
|
- if: ${{ steps.cargo-deps.outputs.cache-hit != 'true' }}
|
|
name: Cache cargo registry index
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: ~/.cargo/registry/index
|
|
key: cargo-index-${{ steps.ls-crates-io-index.outputs.head }}
|
|
restore-keys: cargo-index-
|
|
|
|
- if: ${{ steps.cargo-deps.outputs.cache-hit != 'true' }}
|
|
name: Fetch dependencies and update registry index
|
|
run: cargo fetch --locked
|
|
|
|
test:
|
|
needs: update-deps
|
|
strategy:
|
|
matrix:
|
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- uses: actions/checkout@v2
|
|
|
|
# https://github.com/actions/runner/issues/498
|
|
- if: ${{ runner.os == 'Windows' }}
|
|
name: Fix up Cargo.lock hash
|
|
shell: powershell
|
|
run: |
|
|
Get-ChildItem . -Recurse -Filter Cargo.lock |
|
|
Foreach-Object {
|
|
((Get-Content $_.FullName) -join "`n") + "`n" |
|
|
Set-Content -NoNewline $_.FullName
|
|
}
|
|
|
|
- name: Restore cargo dependencies
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
~/.cargo/registry/index
|
|
~/.cargo/registry/cache
|
|
~/.cargo/git/db
|
|
key: cargo-deps-${{ hashFiles('**/Cargo.lock') }}
|
|
|
|
- name: Build and test
|
|
uses: actions-rs/cargo@v1
|
|
with:
|
|
command: test
|
|
args: --locked
|
|
```
|
|
|
|
## Scala - SBT
|
|
|
|
```yaml
|
|
- name: Cache SBT
|
|
uses: actions/cache@v2
|
|
with:
|
|
path: |
|
|
~/.ivy2/cache
|
|
~/.sbt
|
|
key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }}
|
|
```
|
|
|
|
## Swift, Objective-C - Carthage
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: Carthage
|
|
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-carthage-
|
|
```
|
|
|
|
## Swift, Objective-C - CocoaPods
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: Pods
|
|
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pods-
|
|
```
|
|
|
|
## Swift - Swift Package Manager
|
|
|
|
```yaml
|
|
- uses: actions/cache@v2
|
|
with:
|
|
path: .build
|
|
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-spm-
|
|
```
|