Although @setup/node as a built-in cache option, it lacks an opportunity regarding cache persistence. Depending on usage, the action below might give you faster installs and potentially reduce carbon emissions (β»οΈπ³β€οΈ).
pnpm v7 or v8 (not using pnpm ? see the corresponding yarn action gist)
Based on the nextjs-monorepo-example with pnpm.
A cold cache install on the ci is around Β±1m20s.
With warmed cache: Β±40s + (add Β±10s for compression). Crafted from benchmarks results in https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b. Depending on repo (renovatebot...), the slight complexity increase in ci setup might worth it.
.
βββ .github
βββ actions
β βββ pnpm-install/action.yml (composite action)
βββ workflows
βββ ci.yml (uses: ./.github/actions/pnpm-install)
Create a file in .github/actions/pnpm-install/action.yml and paste
#######################################################################################
# "pnpm install" composite action #
#--------------------------------------------------------------------------------------#
# - bench: https://gist.github.com/belgattitude/0ecd26155b47e7be1be6163ecfbb0f0b #
########################################################################################
name: 'Monorepo install (pnpm)'
description: 'Run pnpm install'
runs:
using: 'composite'
steps:
- uses: pnpm/[email protected]
# If you're not setting the packageManager field in package.json, add the version here
# with:
# version: 8.4.0
- name: Expose pnpm config(s) through "$GITHUB_OUTPUT"
id: pnpm-config
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Cache rotation keys
id: cache-rotation
shell: bash
run: |
echo "YEAR_MONTH=$(/bin/date -u "+%Y%m")" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-config.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-cache-${{ steps.cache-rotation.outputs.YEAR_MONTH }}-
# Prevent store to grow over time (not needed with yarn)
# Note: not perfect as it prune too much in monorepos so the idea
# is to use cache-rotation as above. In the future this might work better.
#- name: Prune pnpm store
# shell: bash
# run: pnpm prune store
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile --prefer-offline
env:
# Other environment variables
HUSKY: '0' # By default do not run HUSKY install To use it in the workflows
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: π₯ Monorepo install
uses: ./.github/actions/pnpm-install## PNPM related ###############
## https://pnpm.io/npmrc #
###############################
# Not always possible to be strict, but if it works for you, keep it to true.
# https://pnpm.io/next/npmrc#strict-peer-dependencies
strict-peer-dependencies=false
# Auto install peers should be false to avoid downloading
# extraneous deps. If the install fails, try first to explicitly add
# the missing deps in your package. Set it to true at last resort
# (when the problem comes from upstream dependencies). The best is false.
# https://pnpm.io/npmrc#auto-install-peers
auto-install-peers=false
# Helps locating duplicates, default in v8
# https://pnpm.io/next/npmrc#use-lockfile-v6
use-lockfile-v6=true
# Will fix duplicates due to peer-dependencies (>=7.29.0), default in v8
# https://github.com/pnpm/pnpm/releases/tag/v7.29.0
dedupe-peer-dependents=true
# Helps with peer-deps (>=7.23.0), default in v8
# https://pnpm.io/npmrc#resolve-peers-from-workspace-root
resolve-peers-from-workspace-root=true
# https://pnpm.io/npmrc#resolution-mode
resolution-mode=lowest
# Default in 8.1.0 to fix issues with root/workspaces hoisting
# https://github.com/pnpm/pnpm/releases/tag/v8.1.0
dedupe-direct-deps=false
save-workspace-protocol=rolling
save-prefix=''
Install
Post-install
When a PR is closed or merged the best is to remove install cache rather than letting github reach the max (10GB) and prune.
Here's an example (feel free to adapt if you need to preserse some things, ie gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 | grep pnpm will only clear pnpm related caches)
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
name: Cleanup caches for closed branches
on:
pull_request:
types:
- closed
workflow_dispatch:
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


