mirror of
https://github.com/pnpm/action-setup.git
synced 2026-08-14 14:02:10 +08:00
feat: cache the lockfile verification log regardless of cache
The log is under a kilobyte and pnpm writes it on every install, not only where supply-chain policies are configured: the integrity and tarball-URL checks are unconditional. A job that starts without it re-checks every lockfile entry against the registry — on a ~2000-entry lockfile with a warm store, 13.5s vs 1.5s with `minimumReleaseAge` and `trustPolicy` configured, and still 6.7s vs 1.6s with no policies at all. Tying that to the `cache` input made the common case slow for no saving worth counting, so the log is now restored and saved on its own key whether or not the store is cached. `cache` goes back to meaning what its name says.
This commit is contained in:
@@ -334,14 +334,24 @@ jobs:
|
|||||||
# The action caches pnpm's lockfile verification log, which lives in
|
# The action caches pnpm's lockfile verification log, which lives in
|
||||||
# `cacheDir` — a directory pnpm resolves per platform and does not print.
|
# `cacheDir` — a directory pnpm resolves per platform and does not print.
|
||||||
# Guard the action's copy of that default against pnpm's own.
|
# Guard the action's copy of that default against pnpm's own.
|
||||||
name: 'Lockfile verification cache (${{ matrix.os }})'
|
name: 'Lockfile verification cache (${{ matrix.os }}, cache=${{ matrix.cache }})'
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
include:
|
||||||
|
# The log is cached independently of the store, so the store-less
|
||||||
|
# configuration has to reach it too.
|
||||||
|
- os: ubuntu-latest
|
||||||
|
cache: false
|
||||||
|
- os: ubuntu-latest
|
||||||
|
cache: true
|
||||||
|
- os: macos-latest
|
||||||
|
cache: true
|
||||||
|
- os: windows-latest
|
||||||
|
cache: true
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||||
@@ -357,7 +367,7 @@ jobs:
|
|||||||
- uses: ./
|
- uses: ./
|
||||||
with:
|
with:
|
||||||
version: '12.0.0-rc.4'
|
version: '12.0.0-rc.4'
|
||||||
cache: true
|
cache: ${{ matrix.cache }}
|
||||||
run_install: |
|
run_install: |
|
||||||
- args: [--no-frozen-lockfile]
|
- args: [--no-frozen-lockfile]
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ If `run_install` is a YAML string representation of either an object or an array
|
|||||||
|
|
||||||
### `cache`
|
### `cache`
|
||||||
|
|
||||||
**Optional** (_type:_ `boolean`, _default:_ `false`) Whether to cache the pnpm store directory and, on pnpm v11 and newer, the results of pnpm's lockfile verification against the configured supply-chain policies. Both are keyed on the lockfile's content hash.
|
**Optional** (_type:_ `boolean`, _default:_ `false`) Whether to cache the pnpm store directory, keyed on the lockfile's content hash. On pnpm v11 and newer, the results of pnpm's lockfile verification are cached regardless of this input — see [Lockfile verification cache](#lockfile-verification-cache).
|
||||||
|
|
||||||
### `cache_dependency_path`
|
### `cache_dependency_path`
|
||||||
|
|
||||||
@@ -208,7 +208,18 @@ jobs:
|
|||||||
|
|
||||||
**Note:** You don't need to run `pnpm store prune` at the end; post-action has already taken care of that.
|
**Note:** You don't need to run `pnpm store prune` at the end; post-action has already taken care of that.
|
||||||
|
|
||||||
Besides the store, this also caches pnpm's lockfile verification results (pnpm v11 and newer). Repositories that configure supply-chain policies such as `minimumReleaseAge` or `trustPolicy` make pnpm check every lockfile entry against the registry on each install; that check depends only on the lockfile and the policies, so its result is cached and reused until the lockfile changes.
|
### Lockfile verification cache
|
||||||
|
|
||||||
|
pnpm v11 and newer check every lockfile entry before installing it — that each entry pins an integrity hash, that a pinned tarball URL matches the registry's own metadata, and, where configured, your `minimumReleaseAge` and `trustPolicy` policies. The verdict is memoized in a sub-kilobyte file, so an unchanged lockfile is not re-checked against the registry.
|
||||||
|
|
||||||
|
The action restores and saves that file on every run, independently of the `cache` input, because a job that starts without it pays for the check every time. On a repository with ~2000 lockfile entries and a warm store:
|
||||||
|
|
||||||
|
| | without the log | with it |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `minimumReleaseAge` + `trustPolicy` | 13.5s | 1.5s |
|
||||||
|
| no policies configured | 6.7s | 1.6s |
|
||||||
|
|
||||||
|
Reusing a verdict is not a weaker check: pnpm re-verifies whenever the lockfile content changes, and whenever the recorded policy is looser than the one now configured.
|
||||||
|
|
||||||
### Cache dependencies from multiple lockfiles
|
### Cache dependencies from multiple lockfiles
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -17,9 +17,9 @@ inputs:
|
|||||||
default: 'null'
|
default: 'null'
|
||||||
cache:
|
cache:
|
||||||
description: |
|
description: |
|
||||||
Whether to cache the pnpm store directory and, on pnpm v11 and newer,
|
Whether to cache the pnpm store directory, keyed on the lockfile's
|
||||||
the results of pnpm's lockfile verification against the configured
|
content hash. On pnpm v11 and newer, the results of pnpm's lockfile
|
||||||
supply-chain policies. Both are keyed on the lockfile's content hash.
|
verification are cached either way — see the README.
|
||||||
required: false
|
required: false
|
||||||
default: 'false'
|
default: 'false'
|
||||||
cache_dependency_path:
|
cache_dependency_path:
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -4,10 +4,10 @@ import { Inputs } from '../inputs'
|
|||||||
import { runRestoreCache } from './run'
|
import { runRestoreCache } from './run'
|
||||||
|
|
||||||
export async function restoreCache(inputs: Inputs) {
|
export async function restoreCache(inputs: Inputs) {
|
||||||
if (!inputs.cache) return
|
|
||||||
|
|
||||||
if (!isFeatureAvailable()) {
|
if (!isFeatureAvailable()) {
|
||||||
|
if (inputs.cache) {
|
||||||
warning('Cache is not available, skipping cache restoration')
|
warning('Cache is not available, skipping cache restoration')
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,23 @@ import { removeWindowsExtendedPathPrefix } from '../windows-path'
|
|||||||
export async function runRestoreCache(inputs: Inputs) {
|
export async function runRestoreCache(inputs: Inputs) {
|
||||||
const fileHash = await hashFiles(inputs.cacheDependencyPath)
|
const fileHash = await hashFiles(inputs.cacheDependencyPath)
|
||||||
if (!fileHash) {
|
if (!fileHash) {
|
||||||
|
// Both caches are keyed on the lockfile, so neither can be restored
|
||||||
|
// without one. Only the store cache was asked for by name.
|
||||||
|
if (inputs.cache) {
|
||||||
throw new Error('Some specified paths were not resolved, unable to cache dependencies.')
|
throw new Error('Some specified paths were not resolved, unable to cache dependencies.')
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await runRestoreStoreCache(fileHash)
|
// Restored whether or not the store is cached: the log is a fraction of a
|
||||||
|
// kilobyte, and without it pnpm re-checks every lockfile entry against the
|
||||||
|
// registry on each run — seconds even on a repository that configures no
|
||||||
|
// supply-chain policies.
|
||||||
await restoreVerificationCache(fileHash)
|
await restoreVerificationCache(fileHash)
|
||||||
|
|
||||||
|
if (inputs.cache) {
|
||||||
|
await runRestoreStoreCache(fileHash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runRestoreStoreCache(fileHash: string) {
|
async function runRestoreStoreCache(fileHash: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user