Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ jobs:
run: scripts/test-mobile-worktree-overrides.sh
- name: File size ratchet unit tests
run: node --test scripts/check-file-sizes-core.test.mjs
- name: pnpm cache workflow contract
run: bash scripts/test-ci-pnpm-cache-contract.sh

rust-lint:
name: Rust Lint
Expand Down Expand Up @@ -175,8 +177,9 @@ jobs:
wget
- name: Get pnpm store directory
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
run: bash scripts/resolve-pnpm-cache-path.sh
- name: Restore pnpm store cache
if: steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand Down Expand Up @@ -216,7 +219,7 @@ jobs:
desktop/test-results
if-no-files-found: ignore
- name: Save pnpm store cache
if: github.event_name == 'push'
if: github.event_name == 'push' && steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand All @@ -239,8 +242,9 @@ jobs:
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
- name: Get pnpm store directory
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
run: bash scripts/resolve-pnpm-cache-path.sh
- name: Restore pnpm store cache
if: steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand Down Expand Up @@ -408,8 +412,9 @@ jobs:
done
- name: Get pnpm store directory
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
run: bash scripts/resolve-pnpm-cache-path.sh
- name: Restore pnpm store cache
if: steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand Down Expand Up @@ -548,7 +553,7 @@ jobs:
if-no-files-found: ignore
retention-days: 7
- name: Save pnpm store cache
if: github.event_name == 'push'
if: github.event_name == 'push' && steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand Down Expand Up @@ -791,8 +796,9 @@ jobs:
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
- name: Get pnpm store directory
id: pnpm-cache
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
run: bash scripts/resolve-pnpm-cache-path.sh
- name: Restore pnpm store cache
if: steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand All @@ -805,7 +811,7 @@ jobs:
- name: Web build
run: just web-build
- name: Save pnpm store cache
if: github.event_name == 'push'
if: github.event_name == 'push' && steps.pnpm-cache.outputs.available == 'true'
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
Expand Down
27 changes: 27 additions & 0 deletions scripts/resolve-pnpm-cache-path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail

: "${GITHUB_OUTPUT:?GITHUB_OUTPUT must be set}"

attempts=3
retry_delay="${PNPM_STORE_PATH_RETRY_DELAY:-2}"

for ((attempt = 1; attempt <= attempts; attempt++)); do
if store_path="$(pnpm store path --silent)"; then
store_path="${store_path%$'\r'}"
if [[ -n "${store_path//[[:space:]]/}" && "$store_path" == /* && "$store_path" != *$'\n'* ]]; then
printf 'available=true\nSTORE_PATH=%s\n' "$store_path" >>"$GITHUB_OUTPUT"
exit 0
fi
echo "::warning::pnpm returned an invalid store path on attempt $attempt/$attempts"
else
echo "::warning::pnpm store path failed on attempt $attempt/$attempts"
fi

if [[ "$attempt" -lt "$attempts" ]]; then
sleep "$retry_delay"
fi
done

printf 'available=false\n' >>"$GITHUB_OUTPUT"
echo '::warning::Continuing without the optional pnpm store cache; dependency installation remains required.'
85 changes: 85 additions & 0 deletions scripts/test-ci-pnpm-cache-contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
resolver="$repo_root/scripts/resolve-pnpm-cache-path.sh"
workflow="$repo_root/.github/workflows/ci.yml"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT

mkdir -p "$tmp/bin"
cat >"$tmp/bin/pnpm" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

case "${FAKE_PNPM_MODE:?}" in
valid)
printf '%s\n' '/tmp/pnpm/store/v11'
;;
retry)
count=0
if [[ -f "${FAKE_PNPM_COUNT:?}" ]]; then
count="$(cat "$FAKE_PNPM_COUNT")"
fi
count=$((count + 1))
printf '%s\n' "$count" >"$FAKE_PNPM_COUNT"
if [[ "$count" -lt 3 ]]; then
exit 1
fi
printf '%s\n' '/tmp/pnpm/store/v11'
;;
failure)
exit 1
;;
empty)
exit 0
;;
*)
exit 2
;;
esac
EOF
chmod +x "$tmp/bin/pnpm"

run_resolver() {
local mode="$1"
: >"$tmp/github-output"
rm -f "$tmp/pnpm-count"
PATH="$tmp/bin:$PATH" \
FAKE_PNPM_MODE="$mode" \
FAKE_PNPM_COUNT="$tmp/pnpm-count" \
GITHUB_OUTPUT="$tmp/github-output" \
PNPM_STORE_PATH_RETRY_DELAY=0 \
bash "$resolver" >"$tmp/resolver-log" 2>&1
}

run_resolver valid
grep -Fxq 'available=true' "$tmp/github-output"
grep -Fxq 'STORE_PATH=/tmp/pnpm/store/v11' "$tmp/github-output"

run_resolver retry
grep -Fxq '3' "$tmp/pnpm-count"
grep -Fxq 'available=true' "$tmp/github-output"
grep -Fxq 'STORE_PATH=/tmp/pnpm/store/v11' "$tmp/github-output"

for mode in failure empty; do
run_resolver "$mode"
grep -Fxq 'available=false' "$tmp/github-output"
if grep -Fq 'STORE_PATH=' "$tmp/github-output"; then
echo "$mode resolver output exposed an empty cache path" >&2
exit 1
fi
done

[[ "$(grep -Fc 'run: bash scripts/resolve-pnpm-cache-path.sh' "$workflow")" -eq 4 ]]
[[ "$(grep -Fc " if: steps.pnpm-cache.outputs.available == 'true'" "$workflow")" -eq 4 ]]
[[ "$(grep -Fc " if: github.event_name == 'push' && steps.pnpm-cache.outputs.available == 'true'" "$workflow")" -eq 3 ]]
[[ "$(grep -Fc 'path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}' "$workflow")" -eq 7 ]]
grep -Fq 'bash scripts/test-ci-pnpm-cache-contract.sh' "$workflow"

if grep -Fq 'pnpm store path' "$workflow"; then
echo 'ci.yml must resolve pnpm cache paths through the guarded helper' >&2
exit 1
fi

echo 'pnpm cache workflow contract passed'