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.
15 KiB
Examples
- Examples
- C# - NuGet
- D - DUB
- Elixir - Mix
- Go - Modules
- Haskell - Cabal
- Java - Gradle
- Java - Maven
- Node - npm
- Node - Lerna
- Node - Yarn
- OCaml/Reason - esy
- PHP - Composer
- Python - pip
- R - renv
- Ruby - Bundler
- Rust - Cargo
- Scala - SBT
- Swift, Objective-C - Carthage
- Swift, Objective-C - CocoaPods
- Swift - Swift Package Manager
C# - NuGet
Using NuGet lock files:
- 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
- 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
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
- uses: actions/cache@v2
with:
path: ~/.dub
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.json') }}
restore-keys: |
${{ runner.os }}-dub-
Windows
- uses: actions/cache@v2
with:
path: ~\AppData\Local\dub
key: ${{ runner.os }}-dub-${{ hashFiles('**/dub.json') }}
restore-keys: |
${{ runner.os }}-dub-
Elixir - Mix
- 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
- 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.
- 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
- uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
Java - Maven
- 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 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 withnpm ci
macOS and Ubuntu
- uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Windows
- 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
- 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
- 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.
- 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.
- 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
- 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
- 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
- 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+
- 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
- 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
- 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
- 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
- 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.
- 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.
- 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.
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
- name: Cache SBT
uses: actions/cache@v2
with:
path: |
~/.ivy2/cache
~/.sbt
key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }}
Swift, Objective-C - Carthage
- uses: actions/cache@v2
with:
path: Carthage
key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }}
restore-keys: |
${{ runner.os }}-carthage-
Swift, Objective-C - CocoaPods
- uses: actions/cache@v2
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
Swift - Swift Package Manager
- uses: actions/cache@v2
with:
path: .build
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
restore-keys: |
${{ runner.os }}-spm-