open-standards/scripts/check-lockfiles.sh
Transaction Science e22955434f
All checks were successful
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m24s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m28s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 53s
standards workspaces build + test / aac-rs (pull_request) Successful in 2m37s
standards workspaces build + test / map-rs (pull_request) Successful in 56s
standards workspaces build + test / mesh-rs (pull_request) Successful in 51s
standards workspaces build + test / openpay (pull_request) Successful in 3m25s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 52s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m4s
lockfiles / every Cargo.lock is current (pull_request) Successful in 44s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m22s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m7s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m13s
standards workspaces build + test / jcp-rs (pull_request) Successful in 2m51s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m17s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m22s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m14s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m23s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m51s
ci: every committed Cargo.lock is current
The workspaces here depend on one another by path, so a version bump in one
leaves its dependents' lockfiles behind. Only jobs that pass --locked notice,
and they fail on changes that never touched them. This job resolves each
workspace against its lock on every push (cargo update --workspace --locked:
no crate is downloaded and nothing is built) and names the stale ones with the
command that fixes each. A self-test shows the check fails on a bumped path
dependency, an added dependency, a missing lock and an unparseable manifest.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-12 20:16:43 -04:00

90 lines
3.1 KiB
Shell
Executable file

#!/usr/bin/env bash
#
# check-lockfiles.sh — every committed Cargo.lock is current.
#
# A lockfile is stale when cargo would change it: a crate's version was bumped,
# or a dependency was added, and the lock was not regenerated. This tree holds
# many workspaces that depend on one another by path, so a version bump in one
# leaves the locks of the others behind. Nothing notices until a job that
# passes `--locked` fails, for a reason that has nothing to do with what the
# job tests.
#
# For each directory that holds a tracked Cargo.lock this runs
#
# cargo update --workspace --locked
#
# which resolves the workspace against its lock and fails if the lock would
# change. It reads the registry index and any git dependency; it downloads no
# crate and builds nothing.
#
# check-lockfiles.sh every tracked Cargo.lock, less the list below
# check-lockfiles.sh DIR ... exactly these directories
#
# Exit 0: every lock is current. Exit 1: at least one is stale, or could not be
# checked. A lock that could not be checked (no network, say) fails the run too,
# under its own heading, so nobody goes looking for a stale lock that is not
# one.
set -uo pipefail
# Directories that hold a Cargo.lock cargo does not read. Each needs a reason,
# and each must still exist: a stale entry fails the run.
SKIP=(
# A vendored crate, patched into jouledesk-rs. Cargo resolves it as part of
# that workspace, against that workspace's lock; its own lock is the
# upstream's, kept with the vendored source.
"jouledesk/jouledesk-rs/vendor/libwebrtc"
)
skipped() { local d; for d in "${SKIP[@]}"; do [ "$d" = "$1" ] && return 0; done; return 1; }
if [ $# -gt 0 ]; then
dirs=("$@")
else
cd "$(git rev-parse --show-toplevel)" || exit 1
for d in "${SKIP[@]}"; do
if [ ! -f "$d/Cargo.lock" ]; then
echo "check-lockfiles: the skip list names $d, which holds no Cargo.lock. Remove the entry." >&2
exit 1
fi
done
dirs=()
while IFS= read -r l; do
d=$(dirname "$l")
skipped "$d" || dirs+=("$d")
done < <(git ls-files | grep -E '(^|/)Cargo\.lock$')
fi
if [ ${#dirs[@]} -eq 0 ]; then
echo "check-lockfiles: found no Cargo.lock to check." >&2
exit 1
fi
stale=(); unchecked=()
for d in "${dirs[@]}"; do
out=$( (cd "$d" && cargo update --workspace --locked) 2>&1 ); rc=$?
if [ $rc -eq 0 ]; then
continue
elif printf '%s' "$out" | grep -qE -- '--locked was passed|lock file .* (is missing|needs to be updated)'; then
stale+=("$d")
echo "STALE $d"
printf '%s\n' "$out" | grep -E '^error|^Caused by|^ ' | head -6 | sed 's/^/ /'
else
unchecked+=("$d")
echo "ERROR $d (cargo could not resolve it; this is not a verdict on the lock)"
printf '%s\n' "$out" | tail -8 | sed 's/^/ /'
fi
done
if [ ${#stale[@]} -gt 0 ]; then
echo
echo "Stale lockfiles. Regenerate each, and commit the result:"
for d in "${stale[@]}"; do echo " (cd $d && cargo update --workspace)"; done
fi
if [ ${#unchecked[@]} -gt 0 ]; then
echo
echo "Could not be checked: ${unchecked[*]}"
fi
if [ ${#stale[@]} -gt 0 ] || [ ${#unchecked[@]} -gt 0 ]; then
exit 1
fi
echo "check-lockfiles: ${#dirs[@]} lockfiles, all current."