Compare commits
1
Commits
next
...
6bfe119e96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bfe119e96 |
@@ -41,11 +41,13 @@ The scripts cover both the frontend and the Go backend, so `make check` fails if
|
|||||||
either one is broken. We provide:
|
either one is broken. We provide:
|
||||||
|
|
||||||
- `script/bootstrap` — install all dependencies (the pinned node via nvm unless
|
- `script/bootstrap` — install all dependencies (the pinned node via nvm unless
|
||||||
one new enough for the frontend's dependencies is installed, yarn via
|
the `node` on `PATH` has the pinned major version and is new enough for the
|
||||||
corepack, `yarn install --frozen-lockfile`, Go `GO_VERSION` unless the `go` on
|
frontend's dependencies, yarn `YARN_VERSION` via corepack unless the `yarn` on
|
||||||
`PATH` is exactly that version, and the Go modules), linking what it installs
|
`PATH` is exactly that version, `yarn install --frozen-lockfile`, Go
|
||||||
itself into `~/.local/bin`, which has to be on `PATH`. It installs no Go
|
`GO_VERSION` unless the `go` on `PATH` is exactly that version, and the Go
|
||||||
linter and not Docker: `make test` and `make lint` run in Docker
|
modules), linking what it installs itself into `~/.local/bin`, which has to be
|
||||||
|
on `PATH`. It installs no Go linter and not Docker: `make test` and
|
||||||
|
`make lint` run in Docker
|
||||||
- `script/setup` — make a fresh clone ready for development: bootstrap plus the
|
- `script/setup` — make a fresh clone ready for development: bootstrap plus the
|
||||||
git pre-commit hook
|
git pre-commit hook
|
||||||
- `script/dev` — run the Vite dev server, which proxies `/api` to a locally
|
- `script/dev` — run the Vite dev server, which proxies `/api` to a locally
|
||||||
@@ -58,6 +60,11 @@ either one is broken. We provide:
|
|||||||
defaults (see [Settings](#settings))
|
defaults (see [Settings](#settings))
|
||||||
- `script/clean` — remove what `script/build` writes
|
- `script/clean` — remove what `script/build` writes
|
||||||
- `script/projectname` — print the project name (used for the Docker image tag)
|
- `script/projectname` — print the project name (used for the Docker image tag)
|
||||||
|
- `script/yarn` — run yarn with the given arguments under the node
|
||||||
|
`script/bootstrap` would use: with `~/.local/bin` first on `PATH`, the `node`
|
||||||
|
there when it has the pinned major version and is new enough for the
|
||||||
|
frontend's dependencies, and otherwise the pinned node in nvm. Every other
|
||||||
|
script that runs yarn on the host runs it through this one
|
||||||
- `script/test` — build the `test` phase of `Dockerfile`, writing no image: the
|
- `script/test` — build the `test` phase of `Dockerfile`, writing no image: the
|
||||||
frontend's unit tests in its `frontend-test` stage, and the backend's Go tests
|
frontend's unit tests in its `frontend-test` stage, and the backend's Go tests
|
||||||
with the race detector and coverage. The frontend's production build is left
|
with the race detector and coverage. The frontend's production build is left
|
||||||
|
|||||||
@@ -21,6 +21,19 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-10-19: `script/bootstrap` keeps the `yarn` on `PATH` only when
|
||||||
|
`yarn --version` is exactly `YARN_VERSION`, and otherwise prepares that
|
||||||
|
version through corepack, as it did when no yarn was installed
|
||||||
|
([#154](https://git.eeqj.de/sneak/netwatch/issues/154)); any yarn used to be
|
||||||
|
kept. It uses the `node` on `PATH` only when that node has the major version
|
||||||
|
of `NODE_VERSION` as well as being at least `NODE_MIN_VERSION`, as
|
||||||
|
`REPO_POLICIES.md` asks; a node 24 was kept before. After installing node or
|
||||||
|
yarn it looks the tool up through `PATH` again and stops if that is not the
|
||||||
|
pinned one, as it does for Go, and it prints the node and yarn versions it
|
||||||
|
uses. Every script that runs yarn on the host runs it through the new
|
||||||
|
`script/yarn`, which puts `~/.local/bin` first on `PATH`, uses the `node`
|
||||||
|
there when it passes the same test, and otherwise runs yarn under the pinned
|
||||||
|
node in nvm; `make build` ran yarn under whatever node was first on `PATH`
|
||||||
- 2026-10-19: report file writes no longer overlap
|
- 2026-10-19: report file writes no longer overlap
|
||||||
([#150](https://git.eeqj.de/sneak/netwatch/issues/150)), so the reports of
|
([#150](https://git.eeqj.de/sneak/netwatch/issues/150)), so the reports of
|
||||||
failed writes are written in the order they arrived. Two writes that failed at
|
failed writes are written in the order they arrived. Two writes that failed at
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ main() {
|
|||||||
"" | -* | *[[:space:]]*) usage ;;
|
"" | -* | *[[:space:]]*) usage ;;
|
||||||
esac
|
esac
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
yarn add --dev "$1"
|
"$ROOT/script/yarn" add --dev "$1"
|
||||||
yarn install --frozen-lockfile
|
"$ROOT/script/yarn" install --frozen-lockfile
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
+56
-14
@@ -3,11 +3,13 @@
|
|||||||
# this repo. Idempotent: every install is guarded by a check so already
|
# this repo. Idempotent: every install is guarded by a check so already
|
||||||
# installed tools are skipped. Base tooling comes from nix, apt, brew,
|
# installed tools are skipped. Base tooling comes from nix, apt, brew,
|
||||||
# or apk (detected in that order); assumes nothing is present. Node is
|
# 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
|
# used directly only if it has the major version of NODE_VERSION and is
|
||||||
# installed at a pinned version via nvm (installing nvm itself first,
|
# at least NODE_MIN_VERSION; otherwise NODE_VERSION is installed via nvm
|
||||||
# from a hash-verified release archive, never curl | sh). Go, with its
|
# (installing nvm itself first, from a hash-verified release archive,
|
||||||
# gofmt, is used directly only if it is exactly GO_VERSION; otherwise
|
# never curl | sh). Yarn is used directly only if it is exactly
|
||||||
# that release is installed from its hash-verified archive.
|
# YARN_VERSION; otherwise that version is prepared through 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
|
# What this script installs outside the system package manager lives
|
||||||
# under $HOME and is linked into ~/.local/bin, where make and the git
|
# under $HOME and is linked into ~/.local/bin, where make and the git
|
||||||
@@ -142,32 +144,65 @@ ensure_nvm() {
|
|||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
# node_ok: the node on PATH is at least NODE_MIN_VERSION. node itself
|
# node_ok: the node on PATH has the major version of NODE_VERSION and is
|
||||||
# compares the two: major, then minor, then patch.
|
# 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 and
|
||||||
|
# script/yarn carry this function unchanged.
|
||||||
node_ok() {
|
node_ok() {
|
||||||
if missing node; then return 1; fi
|
if ! command -v node >/dev/null 2>&1; then return 1; fi
|
||||||
node -e '
|
node -e '
|
||||||
const have = process.versions.node.split(".").map(Number);
|
const have = process.versions.node.split(".").map(Number);
|
||||||
const want = process.argv[1].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++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
if (have[i] !== want[i]) process.exit(have[i] > want[i] ? 0 : 1);
|
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.
|
# 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() {
|
ensure_node() {
|
||||||
if node_ok; then return 0; fi
|
if node_ok; then
|
||||||
|
echo "bootstrap: using node $(node --version)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
ensure_nvm
|
ensure_nvm
|
||||||
nvm_sh "nvm install $NODE_VERSION"
|
nvm_sh "nvm install $NODE_VERSION"
|
||||||
link_bin "$HOME/.nvm/versions/node/v$NODE_VERSION/bin/node" node
|
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_ok: yarn --version on PATH prints exactly YARN_VERSION, compared
|
||||||
# yarn) into $TOOLCHAIN rather than next to itself, and the npm fallback
|
# over the whole version. A yarn that fails or prints anything else does
|
||||||
# installs there too; only yarn is linked.
|
# 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() {
|
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"
|
shims="$TOOLCHAIN/corepack-shims"
|
||||||
mkdir -p "$shims"
|
mkdir -p "$shims"
|
||||||
if ! missing corepack; then
|
if ! missing corepack; then
|
||||||
@@ -182,6 +217,13 @@ ensure_yarn() {
|
|||||||
shims="$TOOLCHAIN/npm-global/bin"
|
shims="$TOOLCHAIN/npm-global/bin"
|
||||||
fi
|
fi
|
||||||
link_bin "$shims/yarn" yarn
|
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
|
# go_ok: the go on PATH has its gofmt beside it (a Go release ships the
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
yarn build
|
"$ROOT/script/yarn" build
|
||||||
|
|
||||||
# VERSION comes from the environment. Unset or empty, it is git
|
# VERSION comes from the environment. Unset or empty, it is git
|
||||||
# describe, or "dev" where there is no git or no repository history.
|
# describe, or "dev" where there is no git or no repository history.
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
yarn dev
|
"$ROOT/script/yarn" dev
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
yarn prettier --write '**/*.{js,css,html,md}'
|
"$ROOT/script/yarn" prettier --write '**/*.{js,css,html,md}'
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
yarn prettier --check '**/*.{js,css,html,md}'
|
"$ROOT/script/yarn" prettier --check '**/*.{js,css,html,md}'
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
NODE_OPTIONS=--test-reporter=dot timeout 90 yarn --silent run test || {
|
NODE_OPTIONS=--test-reporter=dot \
|
||||||
|
timeout 90 "$ROOT/script/yarn" --silent run test || {
|
||||||
echo "--- Rerunning with every test listed for details ---"
|
echo "--- Rerunning with every test listed for details ---"
|
||||||
NODE_OPTIONS=--test-reporter=spec timeout 90 yarn --silent run test
|
NODE_OPTIONS=--test-reporter=spec \
|
||||||
|
timeout 90 "$ROOT/script/yarn" --silent run test
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
timeout 30 yarn build
|
timeout 30 "$ROOT/script/yarn" build
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# script/yarn: run yarn with the given arguments under the node
|
||||||
|
# script/bootstrap would use. Every other script that runs yarn on the
|
||||||
|
# host runs it through this one.
|
||||||
|
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 and
|
||||||
|
# script/yarn 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run the yarn script/bootstrap installed: the yarn on PATH when the
|
||||||
|
# node on PATH passes node_ok, and otherwise yarn under the pinned node
|
||||||
|
# in nvm. nvm is a bash script, hence the subshell.
|
||||||
|
run_yarn() {
|
||||||
|
if node_ok && command -v yarn >/dev/null 2>&1; then
|
||||||
|
exec yarn "$@"
|
||||||
|
fi
|
||||||
|
if node_ok || [ ! -s "$HOME/.nvm/nvm.sh" ]; then
|
||||||
|
echo "script/yarn: no yarn; run script/bootstrap first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exec bash -c '. "$HOME/.nvm/nvm.sh" && nvm use "$1" >/dev/null &&
|
||||||
|
shift && exec yarn "$@"' bash "$NODE_VERSION" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
cd "$ROOT"
|
||||||
|
# script/bootstrap links the node and yarn it installs into
|
||||||
|
# ~/.local/bin, which the shell that called it may not have on PATH.
|
||||||
|
PATH="$HOME/.local/bin:$PATH"
|
||||||
|
run_yarn "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user