Format the markdown with prettier in script/fmt and script/fmt-check (closes #100)
check / check (push) Failing after 3s

script/fmt and script/fmt-check run prettier 3.8.1 on the markdown after
gofmt, with the same yarn helper and arguments as the copies in
sneak/prompts. prettier is pinned in package.json and yarn.lock;
.prettierrc sets four-space tabs and proseWrap always, and
.prettierignore keeps prettier off REPO_POLICIES.md and vendor/. Plain
script/bootstrap now installs Node and Yarn the way the one in
sneak/prompts does, then prettier; with --cgo it does not, as the
Dockerfile stages that pass it format nothing. The HTML templates stay
out: prettier cannot parse a Go template action inside a tag.

Model: opus-5-5
This commit is contained in:
2026-10-05 01:55:13 +00:00
parent a941a80bf9
commit 15260c827e
9 changed files with 182 additions and 19 deletions
+7
View File
@@ -0,0 +1,7 @@
node_modules/
yarn.lock
# A byte-for-byte copy of the one in sneak/prompts.
REPO_POLICIES.md
vendor/
+4
View File
@@ -0,0 +1,4 @@
{
"tabWidth": 4,
"proseWrap": "always"
}
+16 -9
View File
@@ -94,9 +94,10 @@ Outside Docker, pixa needs libvips (the image has 8.15) and libheif to run, as
it uses libvips through CGO; building it also needs their development files, it uses libvips through CGO; building it also needs their development files,
`pkg-config` and a C compiler. `script/bootstrap --cgo` installs all of these, `pkg-config` and a C compiler. `script/bootstrap --cgo` installs all of these,
as the `Dockerfile` does where it compiles pixa. Plain `script/bootstrap`, which as the `Dockerfile` does where it compiles pixa. Plain `script/bootstrap`, which
`script/setup` and `script/cibuild` run, installs only git, make and Go: the `script/setup` and `script/cibuild` run, installs git, make and Go, and Node,
checks compile pixa in Docker, so the host needs none of the C libraries. Docker Yarn and the prettier pinned in `yarn.lock` for formatting the markdown, but
itself must already be installed. none of the C libraries: the checks compile pixa in Docker. Docker itself must
already be installed.
## Running under upaas ## Running under upaas
@@ -568,9 +569,10 @@ standard: normalized scripts in `script/` are the entrypoints for the
development workflow, and the Makefile targets are thin shims that call development workflow, and the Makefile targets are thin shims that call
them. We provide: them. We provide:
- `script/bootstrap` — install git, make and Go and download the Go modules - `script/bootstrap` — install git, make, Go, Node, Yarn and prettier and
(idempotent); with `--cgo`, also the C compiler and the libvips and libheif download the Go modules (idempotent); with `--cgo`, the C compiler and the
libraries that compiling pixa needs libvips and libheif libraries that compiling pixa needs instead of Node, Yarn
and prettier
- `script/setup` — make a fresh clone ready for development - `script/setup` — make a fresh clone ready for development
(bootstrap, then install-precommit) (bootstrap, then install-precommit)
- `script/projectname` — output the project name ("pixa") - `script/projectname` — output the project name ("pixa")
@@ -578,8 +580,9 @@ them. We provide:
`Dockerfile`, tagged `pixa-test` `Dockerfile`, tagged `pixa-test`
- `script/lint` — run golangci-lint: build the `lint` phase of the `Dockerfile`, - `script/lint` — run golangci-lint: build the `lint` phase of the `Dockerfile`,
tagged `pixa-lint`; the linter never runs on the host tagged `pixa-lint`; the linter never runs on the host
- `script/fmt` — format all code (writes) - `script/fmt` — format the Go code with gofmt and the markdown with prettier
- `script/fmt-check` — check formatting (read-only), on the host (writes)
- `script/fmt-check` — check the same formatting (read-only), on the host
- `script/check` — run test, lint, and fmt-check - `script/check` — run test, lint, and fmt-check
- `script/docker` — build the Docker image tagged via `script/projectname`, with - `script/docker` — build the Docker image tagged via `script/projectname`, with
the version from `git describe`; the image's build stage depends on the `lint` the version from `git describe`; the image's build stage depends on the `lint`
@@ -598,7 +601,11 @@ Every `docker build` in these scripts passes `--no-cache`, so the lint and test
phases run on every build instead of coming from the build cache. phases run on every build instead of coming from the build cache.
`script/check`, `script/cibuild`, `script/docker`, `script/lint`, `script/test`, `script/check`, `script/cibuild`, `script/docker`, `script/lint`, `script/test`,
`script/setup` and `script/install-precommit` are the standard copies from `script/setup` and `script/install-precommit` are the standard copies from
`sneak/prompts`, kept identical to them. `sneak/prompts`, kept identical to them. `script/fmt` and `script/fmt-check` are
the standard copies with pixa's `gofmt` step kept before prettier. prettier
formats the markdown only: not the HTML templates, as it cannot parse a Go
template action inside a tag, and not `REPO_POLICIES.md` (see
`.prettierignore`), a copy of the one in `sneak/prompts`.
## Load Test ## Load Test
+10
View File
@@ -31,6 +31,16 @@ P2: security: per-IP rate limiting on the image routes
# Completed Steps # Completed Steps
- 2026-10-05 the markdown is formatted with prettier (closes #100):
`script/fmt` and `script/fmt-check` run prettier 3.8.1, pinned in
`package.json` and `yarn.lock`, on `**/*.md` after `gofmt`, with four-space
tabs and `proseWrap: always` as `.prettierrc` says; `.prettierignore` keeps
it off `REPO_POLICIES.md`, the copy from `sneak/prompts`, and `vendor/`.
Plain `script/bootstrap` installs Node and Yarn as the one in `sneak/prompts`
does and then prettier; `script/bootstrap --cgo` does not, as the
`Dockerfile` stages that run it format nothing. The HTML templates stay
unformatted: prettier cannot parse a Go template action inside a tag. The
markdown was reflowed in a commit of its own.
- 2026-10-05 lint and tests run as the `lint` and `test` phases of the - 2026-10-05 lint and tests run as the `lint` and `test` phases of the
`Dockerfile`, built with `--no-cache` (closes #202): `script/check`, `Dockerfile`, built with `--no-cache` (closes #202): `script/check`,
`script/cibuild`, `script/docker`, `script/lint`, `script/test`, `script/cibuild`, `script/docker`, `script/lint`, `script/test`,
+6
View File
@@ -0,0 +1,6 @@
{
"license": "GPL-3.0",
"devDependencies": {
"prettier": "3.8.1"
}
}
+91 -10
View File
@@ -3,20 +3,33 @@
# 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 (not git, # or apk (detected in that order); assumes NOTHING is present (not git,
# make, or go). The linter is never installed on the host: golangci-lint # make, or go). Node is used directly if installed; otherwise it is
# runs only in the lint phase of the Dockerfile (see script/lint). # installed at a pinned version via nvm (installing nvm itself first,
# from a hash-verified release archive, never curl | sh). The linter is
# never installed on the host: golangci-lint runs only in the lint phase
# of the Dockerfile (see script/lint).
# #
# script/bootstrap git, make and Go, all the host needs: the # script/bootstrap git, make, Go, and Node, Yarn and the
# checks compile pixa in Docker # prettier in yarn.lock for script/fmt and
# script/bootstrap --cgo also a C compiler and the CGO image # script/fmt-check: all the host needs, as
# libraries (pkg-config, vips, libheif) for # the checks compile pixa in Docker
# the govips bindings, to compile pixa; the # script/bootstrap --cgo git, make, Go, and a C compiler and the
# Dockerfile's test phase and build stage # CGO image libraries (pkg-config, vips,
# run this # libheif) for the govips bindings instead
# of Node: to compile pixa, in the
# Dockerfile's test phase and build stage,
# which format nothing
set -eu set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
# Pinned versions, 2026-07-06
NODE_VERSION="22.17.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"
YARN_VERSION="1.22.22"
PKGMGR="" PKGMGR=""
SUDO="" SUDO=""
@@ -61,6 +74,69 @@ missing() {
! command -v "$1" >/dev/null 2>&1 ! command -v "$1" >/dev/null 2>&1
} }
# verify_sha256 <file> <expected-hash>
verify_sha256() {
if command -v sha256sum >/dev/null 2>&1; then
actual="$(sha256sum "$1" | cut -d' ' -f1)"
else
actual="$(shasum -a 256 "$1" | cut -d' ' -f1)"
fi
if [ "$actual" != "$2" ]; then
echo "bootstrap: sha256 mismatch for $1" >&2
echo " expected: $2" >&2
echo " actual: $actual" >&2
exit 1
fi
}
# nvm is a bash script; run a command in a bash with nvm loaded
nvm_sh() {
bash -c ". \"\$HOME/.nvm/nvm.sh\" && $*"
}
ensure_nvm() {
[ -s "$HOME/.nvm/nvm.sh" ] && return 0
# nvm prerequisites; nvm itself requires bash
if missing bash; then pkg_install bash bash bash bash; fi
if missing curl; then pkg_install curl curl curl curl; fi
if missing git; then pkg_install git git git git; fi
tmp="$(mktemp -d)"
curl -fsSL -o "$tmp/nvm.tar.gz" \
"https://github.com/nvm-sh/nvm/archive/refs/tags/v${NVM_VERSION}.tar.gz"
verify_sha256 "$tmp/nvm.tar.gz" "$NVM_SHA256"
mkdir -p "$HOME/.nvm"
tar -xzf "$tmp/nvm.tar.gz" -C "$HOME/.nvm" --strip-components=1
rm -rf "$tmp"
}
ensure_node() {
if ! missing node; then return 0; fi
ensure_nvm
nvm_sh "nvm install $NODE_VERSION"
}
ensure_yarn() {
if ! missing yarn; then return 0; fi
if ! missing corepack; then
corepack enable
corepack prepare "yarn@$YARN_VERSION" --activate
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
nvm_sh "nvm use $NODE_VERSION >/dev/null && corepack enable && \
corepack prepare yarn@$YARN_VERSION --activate"
else
npm install -g "yarn@$YARN_VERSION"
fi
}
install_js_deps() {
if missing yarn && [ -s "$HOME/.nvm/nvm.sh" ]; then
nvm_sh "nvm use $NODE_VERSION >/dev/null && cd \"$ROOT\" && \
yarn install --frozen-lockfile"
else
yarn install --frozen-lockfile
fi
}
# CGO dependencies for govips (image processing) # CGO dependencies for govips (image processing)
ensure_cgo_deps() { ensure_cgo_deps() {
# cgo compiles with gcc on Linux; build-base and build-essential # cgo compiles with gcc on Linux; build-base and build-essential
@@ -98,9 +174,14 @@ main() {
# Go toolchain # Go toolchain
if missing go; then pkg_install go golang go go; fi if missing go; then pkg_install go golang go go; fi
# CGO image libraries, only where pixa is compiled # CGO image libraries where pixa is compiled; elsewhere Node, Yarn
# and prettier
if [ "$*" = "--cgo" ]; then if [ "$*" = "--cgo" ]; then
ensure_cgo_deps ensure_cgo_deps
else
ensure_node
ensure_yarn
install_js_deps
fi fi
go mod download go mod download
+20
View File
@@ -4,11 +4,31 @@ set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
# Must match the pin in script/bootstrap.
NODE_VERSION="22.17.0"
# script/bootstrap installs node and yarn under nvm and leaves neither
# on the PATH of the shell that called it, so resolve the pinned
# toolchain here the way bootstrap's own install step does. nvm is a
# bash script, hence the subshell.
run_yarn() {
if command -v yarn >/dev/null 2>&1; then
exec yarn "$@"
fi
if [ ! -s "$HOME/.nvm/nvm.sh" ]; then
echo "fmt: 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() { main() {
cd "$ROOT" cd "$ROOT"
echo "Formatting code..." echo "Formatting code..."
# shellcheck disable=SC2046 # word splitting of file list is wanted # shellcheck disable=SC2046 # word splitting of file list is wanted
gofmt -w $(find . -name '*.go' -not -path './vendor/*') gofmt -w $(find . -name '*.go' -not -path './vendor/*')
run_yarn run prettier --write '**/*.md' --tab-width 4 --prose-wrap always
} }
main "$@" main "$@"
+20
View File
@@ -5,6 +5,25 @@ set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
# Must match the pin in script/bootstrap.
NODE_VERSION="22.17.0"
# script/bootstrap installs node and yarn under nvm and leaves neither
# on the PATH of the shell that called it, so resolve the pinned
# toolchain here the way bootstrap's own install step does. nvm is a
# bash script, hence the subshell.
run_yarn() {
if command -v yarn >/dev/null 2>&1; then
exec yarn "$@"
fi
if [ ! -s "$HOME/.nvm/nvm.sh" ]; then
echo "fmt-check: 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() { main() {
cd "$ROOT" cd "$ROOT"
echo "Checking formatting..." echo "Checking formatting..."
@@ -13,6 +32,7 @@ main() {
gofmt -l . | grep -v '^vendor/' gofmt -l . | grep -v '^vendor/'
exit 1 exit 1
fi fi
run_yarn run prettier --check '**/*.md' --tab-width 4 --prose-wrap always
} }
main "$@" main "$@"
+8
View File
@@ -0,0 +1,8 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
prettier@3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173"
integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==