main's tree, with next merged on 26 October, as one commit onto prod, on sneak's order. Model: opus-5-5 Co-authored-by: clawbot <clawbot@noreply.example.org>
This commit was merged in pull request #198.
This commit is contained in:
+92
-32
@@ -3,30 +3,34 @@
|
||||
# this repo. Idempotent: every install is guarded by a check so already
|
||||
# installed tools are skipped. Base tooling comes from nix, apt, brew,
|
||||
# or apk (detected in that order); assumes nothing is present. Node is
|
||||
# used directly if it is at least NODE_MIN_VERSION; otherwise it is
|
||||
# installed at a pinned version via nvm (installing nvm itself first,
|
||||
# from a hash-verified release archive, never curl | sh). Go, with its
|
||||
# gofmt, is used directly if it is at least the version backend/go.mod
|
||||
# asks for; otherwise the pinned Go release is installed from its
|
||||
# hash-verified archive.
|
||||
# used directly only if it has the major version of NODE_VERSION and is
|
||||
# at least NODE_MIN_VERSION; otherwise NODE_VERSION is installed via nvm
|
||||
# (installing nvm itself first, from a hash-verified release archive,
|
||||
# never curl | sh). Yarn is used directly only if it is exactly
|
||||
# YARN_VERSION; otherwise that version is prepared through corepack,
|
||||
# or installed with npm where there is no corepack.
|
||||
# Go, with its gofmt, is used directly only if it is exactly GO_VERSION;
|
||||
# otherwise that release is installed from its hash-verified archive.
|
||||
#
|
||||
# What this script installs outside the system package manager lives
|
||||
# under $HOME and is linked into ~/.local/bin, where make and the git
|
||||
# hook find it once that directory is on PATH. Nothing in ~/.local/bin
|
||||
# that this script did not create is ever replaced.
|
||||
#
|
||||
# golangci-lint is not installed: make lint runs it in Docker, which
|
||||
# this script does not install either.
|
||||
# golangci-lint is not installed: make lint runs it in Docker, as make
|
||||
# test runs the tests, and this script does not install Docker either.
|
||||
#
|
||||
# Unlike the org model: Go for the backend, a newer node for eslint.
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
|
||||
# Pinned versions, 2026-07-07
|
||||
# Pinned versions, 2026-07-06
|
||||
NODE_VERSION="22.17.0"
|
||||
# The oldest node the frontend's dependencies accept: the "engines"
|
||||
# field of puppeteer-core 25.5.0, the most demanding of them, asks for
|
||||
# 22.12.0 or newer, 2026-09-29. An older installed node is not used.
|
||||
NODE_MIN_VERSION="22.12.0"
|
||||
# field of eslint 10.12.0, the most demanding of them, asks for 22.13.0
|
||||
# or newer, 2026-10-03. An older installed node is not used.
|
||||
NODE_MIN_VERSION="22.13.0"
|
||||
NVM_VERSION="0.40.3"
|
||||
# sha256 of https://github.com/nvm-sh/nvm/archive/refs/tags/v0.40.3.tar.gz
|
||||
NVM_SHA256="5f4d6aaa04a177dc93c985e31dbc411ab6b8c6e1e21d8015dbc1372625fcd1d0"
|
||||
@@ -64,7 +68,8 @@ detect_pkgmgr() {
|
||||
fi
|
||||
}
|
||||
|
||||
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
|
||||
# pkg_install <nix-attr> <apt-pkgs> <brew-formula> <apk-pkgs>: the apt
|
||||
# and apk arguments may each list several packages, separated by spaces.
|
||||
pkg_install() {
|
||||
detect_pkgmgr
|
||||
case "$PKGMGR" in
|
||||
@@ -74,10 +79,10 @@ pkg_install() {
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update
|
||||
APT_UPDATED=1
|
||||
fi
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y "$2"
|
||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y $2
|
||||
;;
|
||||
brew) brew install "$3" ;;
|
||||
apk) apk add --no-cache "$4" ;;
|
||||
apk) apk add --no-cache $4 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -140,32 +145,63 @@ ensure_nvm() {
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
# node_ok: the node on PATH is at least NODE_MIN_VERSION. node itself
|
||||
# compares the two: major, then minor, then patch.
|
||||
# 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,
|
||||
# as REPO_POLICIES.md asks. node itself compares the versions: major,
|
||||
# then minor, then patch. A node that fails does not pass.
|
||||
# script/bootstrap and script/yarn carry this function unchanged.
|
||||
node_ok() {
|
||||
if missing node; then return 1; fi
|
||||
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_MIN_VERSION" "$NODE_VERSION"
|
||||
}
|
||||
|
||||
# ensure_node: unless node_ok, install NODE_VERSION and link its node.
|
||||
# Afterwards node is looked up through PATH again and must pass node_ok.
|
||||
ensure_node() {
|
||||
if node_ok; then return 0; fi
|
||||
if node_ok; then
|
||||
echo "bootstrap: using node $(node --version)"
|
||||
return 0
|
||||
fi
|
||||
ensure_nvm
|
||||
nvm_sh "nvm install $NODE_VERSION"
|
||||
link_bin "$HOME/.nvm/versions/node/v$NODE_VERSION/bin/node" node
|
||||
hash -r
|
||||
if ! node_ok; then
|
||||
echo "bootstrap: after installing node $NODE_VERSION through nvm," >&2
|
||||
echo " the node on PATH, $(command -v node), is not it" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "bootstrap: installed node $(node --version)"
|
||||
}
|
||||
|
||||
# ensure_yarn: corepack writes its shims (pnpm and yarnpkg as well as
|
||||
# yarn) into $TOOLCHAIN rather than next to itself, and the npm fallback
|
||||
# installs there too; only yarn is linked.
|
||||
# yarn_ok: yarn --version on PATH prints exactly YARN_VERSION, compared
|
||||
# over the whole version. A yarn that fails or prints anything else does
|
||||
# not pass.
|
||||
yarn_ok() {
|
||||
if missing yarn; then return 1; fi
|
||||
version="$(yarn --version 2>/dev/null)" || return 1
|
||||
[ "$version" = "$YARN_VERSION" ]
|
||||
}
|
||||
|
||||
# ensure_yarn: unless yarn_ok, prepare YARN_VERSION and link its yarn.
|
||||
# corepack writes its shims (pnpm and yarnpkg as well as yarn) into
|
||||
# $TOOLCHAIN rather than next to itself, and the npm fallback installs
|
||||
# there too; only yarn is linked. Afterwards yarn is looked up through
|
||||
# PATH again and must pass yarn_ok, so another yarn that hides the link
|
||||
# stops bootstrap.
|
||||
ensure_yarn() {
|
||||
if ! missing yarn; then return 0; fi
|
||||
if yarn_ok; then
|
||||
echo "bootstrap: using yarn $(yarn --version)"
|
||||
return 0
|
||||
fi
|
||||
shims="$TOOLCHAIN/corepack-shims"
|
||||
mkdir -p "$shims"
|
||||
if ! missing corepack; then
|
||||
@@ -180,23 +216,40 @@ ensure_yarn() {
|
||||
shims="$TOOLCHAIN/npm-global/bin"
|
||||
fi
|
||||
link_bin "$shims/yarn" yarn
|
||||
hash -r
|
||||
if ! yarn_ok; then
|
||||
echo "bootstrap: after installing yarn $YARN_VERSION in $shims," >&2
|
||||
echo " the yarn on PATH, $(command -v yarn), does not report it" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "bootstrap: installed yarn $(yarn --version)"
|
||||
}
|
||||
|
||||
# go_ok: the go on PATH has its gofmt beside it (a Go release ships the
|
||||
# two together) and is at least the version backend/go.mod asks for.
|
||||
# GOTOOLCHAIN=local makes an older go fail here instead of fetching a
|
||||
# newer toolchain for itself.
|
||||
# two together) and go version reports exactly GO_VERSION, compared over
|
||||
# the whole version, not a prefix of it. A go that fails or prints
|
||||
# anything else does not pass. GOTOOLCHAIN=local makes go report itself
|
||||
# rather than a toolchain it would fetch.
|
||||
go_ok() {
|
||||
if missing go; then return 1; fi
|
||||
[ -x "$(dirname "$(command -v go)")/gofmt" ] || return 1
|
||||
(cd "$ROOT/backend" && GOTOOLCHAIN=local go list -m >/dev/null 2>&1)
|
||||
version="$(GOTOOLCHAIN=local go version 2>/dev/null)" || return 1
|
||||
case "$version" in
|
||||
"go version go$GO_VERSION "*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ensure_go: unless go_ok, install GO_VERSION and link its go and gofmt.
|
||||
# They are linked on every run that needs them, so a deleted link is put
|
||||
# back, and the archive is unpacked again if either binary is missing.
|
||||
# Afterwards go is looked up through PATH again and must pass go_ok, so
|
||||
# another go that hides the link stops bootstrap.
|
||||
ensure_go() {
|
||||
if go_ok; then return 0; fi
|
||||
if go_ok; then
|
||||
echo "bootstrap: using $(GOTOOLCHAIN=local go version)"
|
||||
return 0
|
||||
fi
|
||||
go_dir="$TOOLCHAIN/go-$GO_VERSION"
|
||||
if [ ! -x "$go_dir/bin/go" ] || [ ! -x "$go_dir/bin/gofmt" ]; then
|
||||
# sha256 of each archive, from https://go.dev/dl/?mode=json
|
||||
@@ -237,6 +290,13 @@ ensure_go() {
|
||||
fi
|
||||
link_bin "$go_dir/bin/go" go
|
||||
link_bin "$go_dir/bin/gofmt" gofmt
|
||||
hash -r
|
||||
if ! go_ok; then
|
||||
echo "bootstrap: after installing go $GO_VERSION in $go_dir," >&2
|
||||
echo " the go on PATH, $(command -v go), is not it or has no gofmt" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "bootstrap: installed $(GOTOOLCHAIN=local go version)"
|
||||
}
|
||||
|
||||
main() {
|
||||
@@ -259,11 +319,11 @@ main() {
|
||||
yarn install --frozen-lockfile
|
||||
|
||||
ensure_go
|
||||
(cd "$ROOT/backend" && go mod download)
|
||||
go mod download
|
||||
|
||||
if missing docker; then
|
||||
echo "bootstrap: docker not found; make lint, and so make check" >&2
|
||||
echo " and the pre-commit hook, need it to run the Go linter" >&2
|
||||
echo "bootstrap: docker not found; make test and make lint, and so" >&2
|
||||
echo " make check and the pre-commit hook, need it" >&2
|
||||
fi
|
||||
if [ -n "$path_hint" ] && [ -d "$BIN_DIR" ]; then
|
||||
echo "bootstrap: add $BIN_DIR to the front of your PATH, e.g." >&2
|
||||
|
||||
Reference in New Issue
Block a user