Bootstrap keeps yarn and node only at their pinned versions (closes #154)
check / check (push) Canceled after 0s

script/bootstrap kept any yarn found on PATH, so YARN_VERSION applied
only where none was installed. It now keeps the yarn on PATH only when
yarn --version is exactly YARN_VERSION, and otherwise prepares that
version through corepack. The node on PATH is used only when it has the
pinned major version and is at least NODE_MIN_VERSION, as
REPO_POLICIES.md asks. After installing either, bootstrap looks the tool
up through PATH again, stops naming the path if it is not the pinned
one, and prints the version it uses, as it does for Go. script/fmt and
script/fmt-check use the same node test, and otherwise run prettier
under the pinned node in nvm.

Model: opus-5-5
This commit is contained in:
2026-10-19 03:57:54 +00:00
parent f5aa81f024
commit c8e65f2468
5 changed files with 149 additions and 22 deletions
+36 -1
View File
@@ -6,12 +6,47 @@ set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
# Must match the pins in script/bootstrap.
NODE_VERSION="22.17.0"
NODE_MIN_VERSION="22.13.0"
# node_ok: the node on PATH has the major version of NODE_VERSION and is
# at least NODE_MIN_VERSION. Only the major is compared with the pin:
# the Dockerfile's node stages start from a node 22 alpine image whose
# exact version is not the pin, and nvm cannot install a prebuilt node
# on alpine. node itself compares the versions: major, then minor, then
# patch. A node that fails does not pass. script/bootstrap, script/fmt
# and script/fmt-check carry this function unchanged.
node_ok() {
if ! command -v node >/dev/null 2>&1; then return 1; fi
node -e '
const have = process.versions.node.split(".").map(Number);
const want = process.argv[1].split(".").map(Number);
const pinned = process.argv[2].split(".").map(Number);
if (have[0] !== pinned[0]) process.exit(1);
for (let i = 0; i < 3; i++) {
if (have[i] !== want[i]) process.exit(have[i] > want[i] ? 0 : 1);
}
' "$NODE_MIN_VERSION" "$NODE_VERSION"
}
main() {
cd "$ROOT"
# script/bootstrap links the node, yarn and gofmt it installs into
# ~/.local/bin, which the shell that called it may not have on PATH.
PATH="$HOME/.local/bin:$PATH"
"$ROOT/script/frontend-fmt-check"
# prettier runs under a node script/bootstrap would use: the node on
# PATH when it passes node_ok, and otherwise the pinned node in nvm.
# nvm is a bash script, hence the bash.
if node_ok; then
"$ROOT/script/frontend-fmt-check"
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
bash -c '. "$HOME/.nvm/nvm.sh" && nvm use "$1" >/dev/null && "$2"' \
bash "$NODE_VERSION" "$ROOT/script/frontend-fmt-check"
else
echo "fmt-check: no node script/bootstrap would use; run it first" >&2
exit 1
fi
unformatted="$(gofmt -l cmd internal)"
if [ -n "$unformatted" ]; then
echo "Go files not formatted:" >&2