chore: re-vendor canonical files from prompts at dd4027b (closes #472)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

Copies .dockerignore, .gitignore, .prettierignore, check.yml and
REPO_POLICIES.md from sneak/prompts at dd4027b, keeping the repo's own
entries (dist/, release/, yarn files) after the canonical content.

The Dockerfile gets separate lint and test phases; its last stage
depends on both, checks the git describe version and runs make build.
script/lint, test, check, cibuild and docker are the canonical models.
check-censored moves into the lint phase and test-verify-build into the
test phase. fmt and fmt-check fall back to the nvm-installed node. The
e2e image builds are uncached. Comments citing the old test caps or what
runs a script are updated.

Model: opus-5-5
This commit was merged in pull request #474.
This commit is contained in:
2026-10-06 15:59:21 +02:00
parent 329e64a54d
commit 0206b2f77e
30 changed files with 720 additions and 286 deletions
+4 -4
View File
@@ -1,14 +1,14 @@
#!/bin/sh
# script/check: run all checks (test, test-verify-build, lint, fmt-check).
# Our own extension to scripts-to-rule-them-all. Must not modify any files.
# script/check: run all checks (test, lint, fmt-check). Our own
# extension to scripts-to-rule-them-all. test and lint are Docker
# phases; fmt-check is native, because a formatter writes the working
# tree. Must not modify any files.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
main() {
"$SCRIPT_DIR/test"
"$SCRIPT_DIR/test-verify-build"
"$SCRIPT_DIR/check-censored"
"$SCRIPT_DIR/lint"
"$SCRIPT_DIR/fmt-check"
}
+2 -2
View File
@@ -1,8 +1,8 @@
#!/bin/sh
# script/check-censored: assert that the competitor name RULES.md bars appears
# nowhere in this repo, and nowhere in the built extension, except where it is
# deliberate. Our own extension to scripts-to-rule-them-all, run from
# script/check and from make build.
# deliberate. Our own extension to scripts-to-rule-them-all, run by the
# Dockerfile's lint phase and by make build.
#
# Where the name is allowed, and why each one is not negotiable away:
#
+19 -4
View File
@@ -1,13 +1,28 @@
#!/bin/sh
# script/cibuild: run the CI build. The Dockerfile runs make check, so
# a successful build implies all checks pass.
# script/cibuild: run the CI build. It bootstraps first: a CI runner
# checks out and runs this and nothing else, and script/fmt-check runs
# the formatter on the host, which a pristine checkout cannot do.
# --no-cache for the same reason as script/docker: the gate phases the
# final stage depends on are RUN steps, and a cached one is a check that
# did not run.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
docker build .
"$SCRIPT_DIR/bootstrap"
"$SCRIPT_DIR/check"
# Own line: a failing command substitution inside an argument does
# not trip `set -e`, so the inline form degrades silently to an
# empty constant. The VERSION build argument takes precedence over
# the version a build stage derives from the .git in the context.
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
[ -n "$version" ] || version="unknown"
docker build --no-cache \
--build-arg VERSION="$version" \
-t "$("$SCRIPT_DIR/projectname")" .
}
main "$@"
+11 -1
View File
@@ -1,6 +1,8 @@
#!/bin/sh
# script/docker: build the Docker image tagged with the project name.
# Identical in all repos; the tag comes from script/projectname.
# --no-cache because the gate phases the final stage depends on are RUN
# steps, and a cached one is a check that did not run.
set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
@@ -8,7 +10,15 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
docker build -t "$("$SCRIPT_DIR/projectname")" .
# Own line: a failing command substitution inside an argument does
# not trip `set -e`, so the inline form degrades silently to an
# empty constant. The VERSION build argument takes precedence over
# the version a build stage derives from the .git in the context.
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
[ -n "$version" ] || version="unknown"
docker build --no-cache \
--build-arg VERSION="$version" \
-t "$("$SCRIPT_DIR/projectname")" .
}
main "$@"
+20 -1
View File
@@ -4,10 +4,29 @@ set -eu
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() {
cd "$ROOT"
echo "Formatting..."
yarn run fmt 2>&1
run_yarn run fmt
}
main "$@"
+20 -1
View File
@@ -5,10 +5,29 @@ set -eu
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() {
cd "$ROOT"
echo "Checking formatting..."
yarn run fmt-check 2>&1
run_yarn run fmt-check
}
main "$@"
@@ -14,7 +14,7 @@
// the build when esbuild's own metafile reports src/shared/state.js as an input
// of a background bundle. That consults the resolution esbuild actually
// performed, so no specifier syntax and no resolution rule can slip past it,
// and Dockerfile:42 runs `make build` in CI.
// and the Dockerfile's last stage runs `make build` in CI.
//
// What this rule is: fast local feedback, in the editor and in `make lint`,
// before a full bundle. It reads sources from disk and matches import
+13 -41
View File
@@ -1,51 +1,23 @@
#!/bin/sh
# script/lint: run the linter (eslint, then prettier --check).
# script/lint: run the linter. Linting is a phase of the Dockerfile and
# this builds that phase alone; the linter is never installed or run on
# a developer host, where a shared result cache and a host-global lock
# make its answer untrustworthy.
#
# Linting is containerized. ESLint results depend on the ESLint version, and
# the pinned one is the one in the image; a host's own install must not be
# able to decide whether this repo is green. From a host this therefore builds
# the Dockerfile's `lint` stage, which runs this same script inside the image.
#
# AUTISTMASK_LINT_NATIVE is set only in that image (see the Dockerfile) and is
# what stops the recursion, so `make check` inside the CI build lints in place
# instead of trying to reach a docker daemon it does not have.
# The phase is not the last stage in the file, so it is built only when
# --target names it. --no-cache because a cached lint layer is a lint
# that did not run. The tag makes each build replace the previous image
# instead of leaving a dangling one behind.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
case "${AUTISTMASK_LINT_NATIVE:-}" in
1)
echo "Linting..."
yarn run lint 2>&1
return 0
;;
"") ;;
*)
# Set but not recognized: say so rather than silently taking the
# docker path, which would look like the variable had no effect.
echo "lint: AUTISTMASK_LINT_NATIVE is set to" \
"'${AUTISTMASK_LINT_NATIVE}'; the only recognized value is 1" >&2
exit 1
;;
esac
if ! command -v docker >/dev/null 2>&1; then
echo "lint: docker is required; linting does not run on the host" >&2
exit 1
fi
echo "Linting in the pinned container..."
# --progress=plain: the default progress renderer collapses the lint
# output on success, and a lint run whose output cannot be seen is not
# evidence that it ran.
#
# --output=type=cacheonly: the exit status is the whole result; exporting
# an image afterwards costs about ten times the lint itself.
docker build --progress=plain --target lint \
--output=type=cacheonly . 2>&1
docker build --no-cache \
--target lint \
-t "$("$SCRIPT_DIR/projectname")-lint" .
}
main "$@"
+10 -43
View File
@@ -1,52 +1,19 @@
#!/bin/sh
# script/test: run the test suite.
#
# jest runs three worker processes (package.json), not one per CPU core: on a
# many-core shared host one per core took gigabytes of RAM per run.
#
# The timeout bounds a hung suite; it is not a performance budget. On the busy
# shared build host the suite takes 8-13s with three workers, inside
# REPO_POLICIES' 20s budget. Inside the image the same suite also pays a cold
# jest cache and shares the runner with the rest of the build, which is not what
# that budget describes, so the Dockerfile raises the bound through
# AUTISTMASK_TEST_TIMEOUT. A cap a healthy suite can trip on a cold cache
# produces a red that means nothing, and teaches "just run it again".
# script/test: run the test suite. Testing is a phase of the Dockerfile
# and this builds that phase alone, on the same terms as script/lint:
# --target because a phase that is not the last stage is built only when
# named, --no-cache because a cached test layer is a test that did not
# run, and a tag so each build replaces the previous image.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
TIMEOUT="${AUTISTMASK_TEST_TIMEOUT:-30}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() {
cd "$ROOT"
echo "Running tests (timeout ${TIMEOUT}s)..."
status=0
timeout "$TIMEOUT" yarn run test 2>&1 || status=$?
[ "$status" -eq 0 ] && return 0
# 124 is timeout(1) killing the suite. Say so: a kill is not a failed
# assertion, and the verbose rerun would only spend the same wall clock
# to be killed again.
if [ "$status" -eq 124 ]; then
echo "tests: TIMED OUT after ${TIMEOUT}s (no assertion failed)" >&2
echo "tests: raise AUTISTMASK_TEST_TIMEOUT if the suite is healthy" >&2
exit 1
fi
# 125 is timeout(1) itself failing, which here means AUTISTMASK_TEST_TIMEOUT
# is not a duration it accepts. The suite never ran, so it neither timed out
# nor failed, and the verbose rerun would only reprint the same complaint.
if [ "$status" -eq 125 ]; then
echo "tests: DID NOT RUN: timeout(1) rejected AUTISTMASK_TEST_TIMEOUT=\"${TIMEOUT}\"" >&2
echo "tests: set it to a duration such as 30 or 180 (see timeout(1))" >&2
exit 1
fi
echo "--- Rerunning with --verbose for details ---"
timeout "$TIMEOUT" yarn run test:verbose 2>&1 || true
# Always fail: the first run already proved the tests are broken, so a
# flaky pass on the rerun must not turn the build green.
exit 1
docker build --no-cache \
--target test \
-t "$("$SCRIPT_DIR/projectname")-test" .
}
main "$@"
+5 -2
View File
@@ -4,7 +4,7 @@
# scripts-to-rule-them-all.
#
# Deliberately NOT called by script/check or script/test: REPO_POLICIES.md
# caps make test at 20 seconds and a browser suite does not fit. Run it
# caps make test at 60 seconds and a browser suite does not fit. Run it
# yourself before touching popup views. ESLint's no-undef now catches a
# used-but-not-imported identifier in make check, but only this suite sees
# what a view actually does when it runs.
@@ -45,7 +45,10 @@ main() {
trap 'cleanup; exit 130' INT TERM
echo "Building the Chrome e2e image (extension included)..."
docker build --iidfile "$IIDFILE" -t "$IMAGE" -f tests/e2e/Dockerfile .
# --no-cache: the image build runs make build and its checks, and a
# cached layer is a check that did not run.
docker build --no-cache --iidfile "$IIDFILE" -t "$IMAGE" \
-f tests/e2e/Dockerfile .
echo "Running e2e suite in the pinned Playwright container..."
# The image is run by ID, not by tag: where two clones of this repo run
+4 -2
View File
@@ -4,7 +4,7 @@
# script/test-e2e. Our own extension to scripts-to-rule-them-all.
#
# Deliberately NOT called by script/check or script/test, for the same
# reason as the Chrome suite: REPO_POLICIES.md caps make test at 20 seconds
# reason as the Chrome suite: REPO_POLICIES.md caps make test at 60 seconds
# and a browser suite does not fit. .gitea/workflows/e2e.yml also runs it
# on every push, in a job separate from check.
#
@@ -44,7 +44,9 @@ main() {
trap 'cleanup; exit 130' INT TERM
echo "Building the pinned Firefox e2e image (extension included)..."
docker build --iidfile "$IIDFILE" -t "$IMAGE" \
# --no-cache: the image build runs make build and its checks, and a
# cached layer is a check that did not run.
docker build --no-cache --iidfile "$IIDFILE" -t "$IMAGE" \
-f tests/e2e/firefox/Dockerfile .
echo "Running the Firefox e2e suite..."
+2 -1
View File
@@ -2,7 +2,8 @@
# script/test-verify-build: exercise every failure mode of
# script/verify-build, and what make build does with dist/ after one of them
# (script/discard-dist-on-failure). Our own extension to
# scripts-to-rule-them-all, run from script/check so make check covers it.
# scripts-to-rule-them-all, run by the Dockerfile's test phase so make check
# covers it.
#
# Why this exists: verify-build is the build-integrity guard, and four separate
# reviews of it each found a fresh vacuous pass — the grep exit-2 conflation,