Compare commits
1 Commits
1c16d50d67
...
4baf2a1c78
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4baf2a1c78 |
12
README.md
12
README.md
@@ -37,13 +37,11 @@ broken. We provide:
|
||||
|
||||
- `script/bootstrap` — install all dependencies, assuming nothing is present:
|
||||
pinned node via nvm if needed, yarn via corepack,
|
||||
`yarn install --frozen-lockfile`, and the backend's toolchain — Go (an
|
||||
already-installed Go is reused only when its version falls inside the window
|
||||
the pinned golangci-lint can analyse; a newer Go is ignored, not preferred)
|
||||
and golangci-lint at the version `Dockerfile.backend` pins. Everything not
|
||||
installed by the system package manager comes from a hash-verified release
|
||||
archive and is symlinked into `~/.local/bin`, so `make check` works in a plain
|
||||
shell afterwards
|
||||
`yarn install --frozen-lockfile`, and the backend's toolchain — Go (reused if
|
||||
already new enough) and golangci-lint at the version `Dockerfile.backend`
|
||||
pins. Everything not installed by the system package manager comes from a
|
||||
hash-verified release archive and is symlinked onto `PATH`, so `make check`
|
||||
works in a plain shell afterwards
|
||||
- `script/setup` — make a fresh clone ready for development: bootstrap plus the
|
||||
git pre-commit hook
|
||||
- `script/projectname` — print the project name (used for the Docker image tags)
|
||||
|
||||
4
TODO.md
4
TODO.md
@@ -33,9 +33,7 @@ files, so merging it also closes most compliance gaps.
|
||||
golangci-lint cannot analyse packages built by a newer Go; it links only into
|
||||
`~/.local/bin`, never a system-wide prefix, and refuses to replace anything it
|
||||
did not create; and it exits non-zero rather than reporting success when the
|
||||
tools on the caller's `PATH` are not the pinned ones — `gofmt` included, held
|
||||
to the same version agreement as `go` and relinked on every run so a deleted
|
||||
link cannot leave another Go's `gofmt` gating the repo
|
||||
tools on the caller's `PATH` are not the pinned ones
|
||||
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints, Makefile
|
||||
shims, README Entrypoints section
|
||||
- 2026-02-27: backend with buffered zstd-compressed report storage; CI workflow
|
||||
|
||||
103
script/bootstrap
103
script/bootstrap
@@ -5,11 +5,10 @@
|
||||
# or apk (detected in that order); assumes nothing is present. Node is
|
||||
# used directly if installed; otherwise it is installed at a pinned
|
||||
# version via nvm (installing nvm itself first, from a hash-verified
|
||||
# release archive, never curl | sh). Go is used directly only if its
|
||||
# version falls inside the pinned window described at GO_MAX_MINOR below
|
||||
# -- a newer Go is ignored, not preferred -- and golangci-lint is
|
||||
# installed at the exact pinned version; both come from hash-verified
|
||||
# official release archives, never an install script.
|
||||
# release archive, never curl | sh). Go is used directly if it is
|
||||
# already new enough, and golangci-lint is installed at the exact pinned
|
||||
# version; both come from hash-verified official release archives, never
|
||||
# an install script.
|
||||
#
|
||||
# The backend's toolchain is bootstrapped here because script/check runs
|
||||
# backend/script/test and backend/script/lint, so a machine that cannot
|
||||
@@ -23,13 +22,10 @@
|
||||
#
|
||||
# Three rules govern what this script is allowed to touch:
|
||||
#
|
||||
# 1. Everything it installs itself lands under $HOME, using $TMPDIR
|
||||
# only for scratch downloads it then deletes. The one exception is
|
||||
# the system package manager, which it shells out to for base
|
||||
# tooling (see pkg_install) and which owns those paths already. A
|
||||
# per-repo bootstrap has no business writing to /usr/local/bin, a
|
||||
# Homebrew prefix, or any other system-wide location behind that
|
||||
# package manager's back.
|
||||
# 1. It never writes outside $HOME. A per-repo bootstrap has no
|
||||
# business writing to /usr/local/bin, a Homebrew prefix, or any
|
||||
# other system-wide location shared with other users and with a
|
||||
# package manager.
|
||||
# 2. It never replaces something it did not create. Only a symlink
|
||||
# that already points into one of its own managed directories is
|
||||
# overwritten; anything else is left alone and bootstrap exits
|
||||
@@ -385,32 +381,8 @@ go_ok() {
|
||||
ver_ge "$GO_MAX_MINOR" "$(echo "$have" | cut -d. -f1,2)"
|
||||
}
|
||||
|
||||
# gofmt_ok: gofmt is a gate tool -- backend/script/fmt-check runs it --
|
||||
# and its output is not guaranteed byte-identical across Go releases, so
|
||||
# a gofmt from a different release than the go that compiles the code is
|
||||
# treated exactly like a missing one, the same way a mismatched
|
||||
# golangci-lint is. `go version <file>` prints the toolchain a Go binary
|
||||
# was built with, so this compares the gofmt that resolves on PATH
|
||||
# against the go that resolves on PATH, without depending on where
|
||||
# either one lives. Anything it cannot read -- no go to ask, gofmt
|
||||
# absent, not a Go binary -- fails closed.
|
||||
gofmt_ok() {
|
||||
if missing go; then return 1; fi
|
||||
if missing gofmt; then return 1; fi
|
||||
go_have="$(go version 2>/dev/null | awk '{print $3}')"
|
||||
[ -n "$go_have" ] || return 1
|
||||
fmt_have="$(go version "$(command -v gofmt)" 2>/dev/null | awk '{print $NF}')"
|
||||
[ "$fmt_have" = "$go_have" ]
|
||||
}
|
||||
|
||||
# ensure_go: reuse the host toolchain only when the go on PATH is inside
|
||||
# the window AND a gofmt from that same release is on PATH with it. Both
|
||||
# link_bin calls sit outside that early return, so whenever the pinned
|
||||
# toolchain is the one in use they run on every bootstrap, not only on
|
||||
# the run that unpacked the archive: a deleted or never-created gofmt
|
||||
# link is restored rather than silently left to some other Go's gofmt.
|
||||
ensure_go() {
|
||||
if go_ok && gofmt_ok; then return 0; fi
|
||||
if go_ok; then return 0; fi
|
||||
if [ ! -x "$GO_DIR/bin/go" ]; then
|
||||
plat="$(platform)"
|
||||
tmp="$(mktemp -d)"
|
||||
@@ -502,22 +474,7 @@ ensure_golangci_lint() {
|
||||
# warning buried in a long bootstrap log is not enough. So the checks
|
||||
# re-run against the PATH the caller will have (theirs, plus $BIN_DIR at
|
||||
# the front if bootstrap had to ask for it), and a failure is fatal.
|
||||
#
|
||||
# Every gate tool that has a version constraint is checked with the same
|
||||
# predicate its install used -- go_ok, gofmt_ok, golangci_lint_ok -- not
|
||||
# with a bare presence test, because a wrong-version gate tool produces
|
||||
# different results from the one CI runs, which is the failure this
|
||||
# function exists to prevent. node and yarn have no pinned version to
|
||||
# disagree about, so presence is the whole constraint for them.
|
||||
verify_toolchain() {
|
||||
# BIN_DIR is only set once something needed linking, but the remedy
|
||||
# text must name a real directory in every reachable state, so fall
|
||||
# back to the one ensure_bin_dir would have chosen.
|
||||
bin_dir="${BIN_DIR:-$HOME/.local/bin}"
|
||||
|
||||
# Model the PATH the caller will actually have: their own, plus
|
||||
# $BIN_DIR at the front only if bootstrap linked something there and
|
||||
# therefore told them to add it.
|
||||
verify_path="$ORIG_PATH"
|
||||
if [ -n "$BIN_DIR" ]; then
|
||||
case ":$ORIG_PATH:" in
|
||||
@@ -531,9 +488,8 @@ verify_toolchain() {
|
||||
export PATH
|
||||
bad=""
|
||||
go_ok || bad="$bad go"
|
||||
gofmt_ok || bad="$bad gofmt"
|
||||
golangci_lint_ok || bad="$bad golangci-lint"
|
||||
for t in node yarn; do
|
||||
for t in gofmt node yarn; do
|
||||
if missing "$t"; then bad="$bad $t"; fi
|
||||
done
|
||||
PATH="$saved_path"
|
||||
@@ -541,43 +497,20 @@ verify_toolchain() {
|
||||
|
||||
[ -z "$bad" ] && return 0
|
||||
|
||||
# Two different faults land here and they need different remedies: a
|
||||
# tool that resolves but is the wrong build is being shadowed, and
|
||||
# telling the user to fix PATH is right; a tool that does not resolve
|
||||
# at all is not being shadowed by anything, and saying so would send
|
||||
# them hunting for a conflict that does not exist.
|
||||
echo "bootstrap: the toolchain on your PATH cannot run the gate." >&2
|
||||
wrong=""
|
||||
absent=""
|
||||
for t in $bad; do
|
||||
where="$(
|
||||
export PATH="$verify_path"
|
||||
command -v "$t" 2>/dev/null || true
|
||||
command -v "$t" || echo "not found"
|
||||
)"
|
||||
if [ -n "$where" ]; then
|
||||
echo " $t: $where (wrong version)" >&2
|
||||
wrong="$wrong $t"
|
||||
else
|
||||
echo " $t: not found" >&2
|
||||
absent="$absent $t"
|
||||
fi
|
||||
echo " $t: $where" >&2
|
||||
done
|
||||
echo " The pinned toolchain is linked into $bin_dir." >&2
|
||||
if [ -n "$wrong" ]; then
|
||||
echo " The tools shown with a path resolve to a build this" >&2
|
||||
echo " script did not provision: something earlier on your PATH" >&2
|
||||
echo " shadows $bin_dir. Put $bin_dir first in" >&2
|
||||
echo " PATH, or remove the conflicting tool, then re-run." >&2
|
||||
fi
|
||||
if [ -n "$absent" ]; then
|
||||
echo " The tools shown as not found are on no directory of your" >&2
|
||||
echo " PATH at all, so nothing is shadowing them. Add $bin_dir" >&2
|
||||
echo " to PATH and re-run; if they are still not found after" >&2
|
||||
echo " that, bootstrap failed to install them and that is a bug" >&2
|
||||
echo " in this script, not in your environment." >&2
|
||||
fi
|
||||
echo " Failing rather than leaving you a bootstrap that reports" >&2
|
||||
echo " success and a \`make check\` that does not run." >&2
|
||||
echo " Expected these to come from $BIN_DIR. Something earlier on" >&2
|
||||
echo " your PATH is shadowing them, or PATH does not reach it." >&2
|
||||
echo " Put $BIN_DIR first in PATH, or remove the conflicting tool," >&2
|
||||
echo " then re-run bootstrap. Failing rather than leaving you a" >&2
|
||||
echo " bootstrap that reports success and a \`make check\` that does" >&2
|
||||
echo " not run." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user