Compare commits
2 Commits
00e18d66b5
...
be25a7a3f5
| Author | SHA1 | Date | |
|---|---|---|---|
| be25a7a3f5 | |||
| 6ffafe7536 |
@@ -238,6 +238,13 @@ The leg re-checks the conversions and nothing else — each fixture's emitted ma
|
|||||||
document, its error code — leaving the corpus's pairing, uniqueness, source positions and
|
document, its error code — leaving the corpus's pairing, uniqueness, source positions and
|
||||||
byte-level equality to the Node suite that owns them.
|
byte-level equality to the Node suite that owns them.
|
||||||
|
|
||||||
|
Every leg announces its name and its image before it runs and its elapsed time after, `publish.sh`
|
||||||
|
alongside `ci.sh`, so a long run reads as progress rather than as a hang — which is what a silent
|
||||||
|
one cost the `0.1.0` release. A leg added later owes the same marker, and a leg that buffers its
|
||||||
|
output to read something out of it streams and keeps the copy in a file: `tee /dev/stderr` reopens
|
||||||
|
the stream, so under the `> log 2>&1` a reader runs locally the two offsets advance independently
|
||||||
|
and punch NUL holes through each other's lines (4d).
|
||||||
|
|
||||||
The floors live in the `test` script, so `npm test` and the gate are one path: 100% of lines and
|
The floors live in the `test` script, so `npm test` and the gate are one path: 100% of lines and
|
||||||
functions, and a branch floor that only ever moves upward. It sits below 100 because the guards
|
functions, and a branch floor that only ever moves upward. It sits below 100 because the guards
|
||||||
`noUncheckedIndexedAccess` and ADF's optional keys force — `?? []`, `?? {}`, `?.`, an index
|
`noUncheckedIndexedAccess` and ADF's optional keys force — `?? []`, `?? {}`, `?.`, an index
|
||||||
|
|||||||
@@ -3,28 +3,32 @@ set -euo pipefail
|
|||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
source ./docker-runner.sh
|
source ./docker-runner.sh
|
||||||
|
|
||||||
in_image "$node_image" npm ci
|
test_log=$(mktemp)
|
||||||
in_image "$node_image" npm run typecheck
|
|
||||||
|
|
||||||
if ! test_output=$(in_image "$node_image" npm test 2>&1); then
|
# Streamed, and copied so the zero-test guard reads the count without trading the output for it.
|
||||||
printf '%s\n' "$test_output"
|
node_tests() {
|
||||||
exit 1
|
in_image "$node_image" npm test 2>&1 | tee "$test_log"
|
||||||
fi
|
}
|
||||||
printf '%s\n' "$test_output"
|
|
||||||
if printf '%s' "$test_output" | grep -q 'ℹ tests 0'; then
|
leg "install ($node_image)" in_image "$node_image" npm ci
|
||||||
|
leg "typecheck ($node_image)" in_image "$node_image" npm run typecheck
|
||||||
|
|
||||||
|
leg "tests ($node_image)" node_tests
|
||||||
|
if grep -q 'ℹ tests 0' "$test_log"; then
|
||||||
echo 'the gate ran zero tests — failing instead of a vacuous green'
|
echo 'the gate ran zero tests — failing instead of a vacuous green'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
rm -f "$test_log"
|
||||||
|
|
||||||
in_image "$deno_image" deno test --allow-env=PROPERTY_RUNS --allow-read --no-check src/
|
leg "tests ($deno_image)" in_image "$deno_image" deno test --allow-env=PROPERTY_RUNS --allow-read --no-check src/
|
||||||
in_image "$bun_image" bun test src/
|
leg "tests ($bun_image)" in_image "$bun_image" bun test src/
|
||||||
|
|
||||||
in_image "$node_image" npm run build
|
leg "build ($node_image)" in_image "$node_image" npm run build
|
||||||
in_image "$node_image" sh -c 'set -e
|
leg "pack and install the tarball ($node_image)" in_image "$node_image" sh -c 'set -e
|
||||||
rm -rf package-tests/node_modules
|
rm -rf package-tests/node_modules
|
||||||
npm pack --pack-destination /tmp >/dev/null
|
npm pack --pack-destination /tmp
|
||||||
npm install --no-audit --no-fund --no-package-lock --no-save --offline --prefix package-tests /tmp/*.tgz >/dev/null'
|
npm install --no-audit --no-fund --no-package-lock --no-save --offline --prefix package-tests /tmp/*.tgz'
|
||||||
in_image "$node_image" npx tsc -p package-tests
|
leg "typecheck the consumer ($node_image)" in_image "$node_image" npx tsc -p package-tests
|
||||||
in_image "$floor_image" node package-tests/node-floor.js
|
leg "round-trip on the engines floor ($floor_image)" in_image "$floor_image" node package-tests/node-floor.js
|
||||||
|
|
||||||
with_firefox in_image "$node_image" node browser-tests/run.js
|
leg "browser ($firefox_image)" with_firefox in_image "$node_image" node browser-tests/run.js
|
||||||
|
|||||||
@@ -10,6 +10,20 @@ in_image() {
|
|||||||
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp ${PROPERTY_RUNS+-e PROPERTY_RUNS} ${in_image_network:+--network "$in_image_network"} -v "$PWD:/app" -w /app --entrypoint "$entrypoint" "$image" "$@"
|
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp ${PROPERTY_RUNS+-e PROPERTY_RUNS} ${in_image_network:+--network "$in_image_network"} -v "$PWD:/app" -w /app --entrypoint "$entrypoint" "$image" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Markers go to stderr so a leg reporting a value stays capturable, and the locals carry the
|
||||||
|
# function's own name because bash scopes them dynamically into whatever the leg runs.
|
||||||
|
leg() {
|
||||||
|
local leg_name=$1 leg_elapsed leg_started leg_status=0
|
||||||
|
shift
|
||||||
|
printf '\n\033[1;34m==> %s\033[0m\n' "$leg_name" >&2
|
||||||
|
# EPOCHREALTIME carries the locale's radix character, so keep the digits and read microseconds.
|
||||||
|
leg_started=${EPOCHREALTIME//[^0-9]/}
|
||||||
|
"$@" || leg_status=$?
|
||||||
|
leg_elapsed=$((${EPOCHREALTIME//[^0-9]/} - leg_started))
|
||||||
|
printf '\033[1;34m<== %s: %d.%ds\033[0m\n' "$leg_name" "$((leg_elapsed / 1000000))" "$((leg_elapsed % 1000000 / 100000))" >&2
|
||||||
|
return $leg_status
|
||||||
|
}
|
||||||
|
|
||||||
with_firefox() {
|
with_firefox() {
|
||||||
local container in_image_network status=0
|
local container in_image_network status=0
|
||||||
container=$(docker run -d --rm "$firefox_image")
|
container=$(docker run -d --rm "$firefox_image")
|
||||||
|
|||||||
+18
-9
@@ -7,31 +7,40 @@ read_field() {
|
|||||||
in_image "$node_image" npm pkg get "$1" | tr -d '"\r'
|
in_image "$node_image" npm pkg get "$1" | tr -d '"\r'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_package_fields() {
|
||||||
|
private=$(read_field private)
|
||||||
|
name=$(read_field name)
|
||||||
|
version=$(read_field version)
|
||||||
|
}
|
||||||
|
|
||||||
published_version() {
|
published_version() {
|
||||||
in_image "$node_image" npm view "$1@$2" version 2>/dev/null || true
|
in_image "$node_image" npm view "$1@$2" version 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
private=$(read_field private)
|
push_tag() {
|
||||||
|
git tag "v$version"
|
||||||
|
git push origin "v$version"
|
||||||
|
}
|
||||||
|
|
||||||
|
leg "read package.json ($node_image)" read_package_fields
|
||||||
if [ "$private" = 'true' ]; then
|
if [ "$private" = 'true' ]; then
|
||||||
echo 'package.json is private — the maintainer removes that in the bump that first publishes'
|
echo 'package.json is private — the maintainer removes that in the bump that first publishes'
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
name=$(read_field name)
|
published=$(leg "ask npmjs for $name@$version" published_version "$name" "$version")
|
||||||
version=$(read_field version)
|
tagged=$(leg "ask origin for v$version" git ls-remote --tags origin "v$version")
|
||||||
published=$(published_version "$name" "$version")
|
|
||||||
tagged=$(git ls-remote --tags origin "v$version")
|
|
||||||
|
|
||||||
# Both steps observe their own end state, so a partial run converges on the next push to main.
|
# Both steps observe their own end state, so a partial run converges on the next push to main.
|
||||||
if [ -z "$published" ]; then
|
if [ -z "$published" ]; then
|
||||||
: "${NPM_TOKEN:?the publish needs NPM_TOKEN}"
|
: "${NPM_TOKEN:?the publish needs NPM_TOKEN}"
|
||||||
in_image "$node_image" npm ci
|
leg "install ($node_image)" in_image "$node_image" npm ci
|
||||||
in_image "$node_image" npm run build
|
leg "build ($node_image)" in_image "$node_image" npm run build
|
||||||
|
leg "publish $name@$version ($node_image)" \
|
||||||
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -e NPM_TOKEN -v "$PWD:/app" -w /app --entrypoint sh "$node_image" -c \
|
docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -e NPM_TOKEN -v "$PWD:/app" -w /app --entrypoint sh "$node_image" -c \
|
||||||
'printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > "$HOME/.npmrc" && npm publish --access public'
|
'printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > "$HOME/.npmrc" && npm publish --access public'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$tagged" ]; then
|
if [ -z "$tagged" ]; then
|
||||||
git tag "v$version"
|
leg "tag v$version" push_tag
|
||||||
git push origin "v$version"
|
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -546,6 +546,34 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
|
|||||||
lines an indented code block held (200k of them at 200 kB), and `emitRun` joining a mark
|
lines an indented code block held (200k of them at 200 kB), and `emitRun` joining a mark
|
||||||
run's segments (200k nodes under one mark). Both fixed here with the same loop and a test
|
run's segments (200k nodes under one mark). Both fixed here with the same loop and a test
|
||||||
each, and §11 gained the rule so the spelling cannot walk back in.
|
each, and §11 gained the rule so the spelling cannot walk back in.
|
||||||
|
- [x] **4d — What the gate says while it runs (`0.2.0`).** `ci.sh` runs nine legs and announces
|
||||||
|
none of them, so five minutes of a Gitea run read as silence and a hang cannot be told from
|
||||||
|
a slow pull — the maintainer hit exactly this on the `0.1.0` release. Three causes, each its
|
||||||
|
own fix. The legs need markers: `plainpages`' `ci.sh` prints a `step()` header per leg and
|
||||||
|
this one prints nothing, so name the leg and the image before each. The longest leg is the
|
||||||
|
quietest: `test_output=$(… npm test 2>&1)` buffers the whole Node run to replay it after,
|
||||||
|
because the zero-test guard greps the count — stream it and grep a copy (`tee`), rather than
|
||||||
|
trading the output for the guard. And two legs are silenced outright, `npm pack` and the
|
||||||
|
tarball install, whose `>/dev/null` predates the offline install that made them quick and
|
||||||
|
quiet. `publish.sh` owes the same: today it says nothing between reading `private` and the
|
||||||
|
registry answering, which is where its `npm ci` and rebuild sit — the seconds §9 accepts
|
||||||
|
rather than promoting the gate's `dist`, and unmeasured until the log shows them. Per-leg
|
||||||
|
timing is what turns "slow or hung" from a guess into a reading; the browser leg's own
|
||||||
|
5.4–7.9s against a 17s warm gate is the number that made it obviously cheap.
|
||||||
|
**Measured** (2026-09-19): ten legs, not the nine counted above, each naming its image, on a
|
||||||
|
27.9 s warm gate — install 1.5 s, typecheck 1.1 s, Node tests 4.6 s, Deno 6.3 s, Bun 3.9 s,
|
||||||
|
build 1.0 s, pack and install 1.6 s, consumer typecheck 1.0 s, engines floor 0.5 s, browser
|
||||||
|
5.7 s. The browser leg lands in the 5.4–7.9 s the item quotes, and the markers cost nothing
|
||||||
|
measurable: 28.9 s before against 27.9 s after. `publish.sh` reads its fields in 2.5 s and the
|
||||||
|
registry in 1.4 s; its `npm ci` and rebuild are the gate's own 1.5 s and 1.0 s, so the seconds
|
||||||
|
§9 accepts for rebuilding rather than promoting the gate's `dist` are about 2.5.
|
||||||
|
Three things the writing turned up. The markers print to stderr, so a leg whose value is read —
|
||||||
|
`publish.sh` asking npmjs — stays capturable. `leg`'s locals carry its own name because bash
|
||||||
|
scopes them into whatever the leg runs: unprefixed, `name` was swallowed by the leg reading
|
||||||
|
`package.json`. And `leg` returns its command's status the way `with_firefox` already did,
|
||||||
|
because the bare call swallowed a non-zero one wherever `set -e` is suspended, which also gets
|
||||||
|
the elapsed time printed for the leg that failed.
|
||||||
|
|
||||||
- [x] **5a — Rename to `@larvit/adf-codec` (`0.1.0`).** Before the first publish, the name being
|
- [x] **5a — Rename to `@larvit/adf-codec` (`0.1.0`).** Before the first publish, the name being
|
||||||
the published identity: `package.json` `name` and `repository`, the Gitea repo and its
|
the published identity: `package.json` `name` and `repository`, the Gitea repo and its
|
||||||
remote, the README title, §6's published-as line, the checkout directory.
|
remote, the README title, §6's published-as line, the checkout directory.
|
||||||
|
|||||||
@@ -69,20 +69,7 @@ bundle size and the tagline.
|
|||||||
- [x] **4.4 — The real payloads.**
|
- [x] **4.4 — The real payloads.**
|
||||||
- [x] **4b — The block walk's retry (`0.2.0`).**
|
- [x] **4b — The block walk's retry (`0.2.0`).**
|
||||||
- [x] **4c — The scanning rule's remaining sites (`0.2.0`).**
|
- [x] **4c — The scanning rule's remaining sites (`0.2.0`).**
|
||||||
- [ ] **4d — What the gate says while it runs (`0.2.0`).** `ci.sh` runs nine legs and announces
|
- [x] **4d — What the gate says while it runs (`0.2.0`).**
|
||||||
none of them, so five minutes of a Gitea run read as silence and a hang cannot be told from
|
|
||||||
a slow pull — the maintainer hit exactly this on the `0.1.0` release. Three causes, each its
|
|
||||||
own fix. The legs need markers: `plainpages`' `ci.sh` prints a `step()` header per leg and
|
|
||||||
this one prints nothing, so name the leg and the image before each. The longest leg is the
|
|
||||||
quietest: `test_output=$(… npm test 2>&1)` buffers the whole Node run to replay it after,
|
|
||||||
because the zero-test guard greps the count — stream it and grep a copy (`tee`), rather than
|
|
||||||
trading the output for the guard. And two legs are silenced outright, `npm pack` and the
|
|
||||||
tarball install, whose `>/dev/null` predates the offline install that made them quick and
|
|
||||||
quiet. `publish.sh` owes the same: today it says nothing between reading `private` and the
|
|
||||||
registry answering, which is where its `npm ci` and rebuild sit — the seconds §9 accepts
|
|
||||||
rather than promoting the gate's `dist`, and unmeasured until the log shows them. Per-leg
|
|
||||||
timing is what turns "slow or hung" from a guess into a reading; the browser leg's own
|
|
||||||
5.4–7.9s against a 17s warm gate is the number that made it obviously cheap.
|
|
||||||
- [x] **5 — Ship `0.1.0`.**
|
- [x] **5 — Ship `0.1.0`.**
|
||||||
- [ ] **5e — The publish token's deadline.** `0.1.0` published only once the npm
|
- [ ] **5e — The publish token's deadline.** `0.1.0` published only once the npm
|
||||||
token carried **Bypass 2FA**: the account requiring no 2FA on writes was not enough, and npm
|
token carried **Bypass 2FA**: the account requiring no 2FA on writes was not enough, and npm
|
||||||
|
|||||||
Reference in New Issue
Block a user