diff --git a/AGENTS.md b/AGENTS.md index c132b13..6decc9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 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 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 diff --git a/ci.sh b/ci.sh index dd3d712..012f0ba 100755 --- a/ci.sh +++ b/ci.sh @@ -3,28 +3,32 @@ set -euo pipefail cd "$(dirname "$0")" source ./docker-runner.sh -in_image "$node_image" npm ci -in_image "$node_image" npm run typecheck +test_log=$(mktemp) -if ! test_output=$(in_image "$node_image" npm test 2>&1); then - printf '%s\n' "$test_output" - exit 1 -fi -printf '%s\n' "$test_output" -if printf '%s' "$test_output" | grep -q 'ℹ tests 0'; then +# Streamed, and copied so the zero-test guard reads the count without trading the output for it. +node_tests() { + in_image "$node_image" npm test 2>&1 | tee "$test_log" +} + +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' exit 1 fi +rm -f "$test_log" -in_image "$deno_image" deno test --allow-env=PROPERTY_RUNS --allow-read --no-check src/ -in_image "$bun_image" bun test src/ +leg "tests ($deno_image)" in_image "$deno_image" deno test --allow-env=PROPERTY_RUNS --allow-read --no-check src/ +leg "tests ($bun_image)" in_image "$bun_image" bun test src/ -in_image "$node_image" npm run build -in_image "$node_image" sh -c 'set -e +leg "build ($node_image)" in_image "$node_image" npm run build +leg "pack and install the tarball ($node_image)" in_image "$node_image" sh -c 'set -e rm -rf package-tests/node_modules - npm pack --pack-destination /tmp >/dev/null - npm install --no-audit --no-fund --no-package-lock --no-save --offline --prefix package-tests /tmp/*.tgz >/dev/null' -in_image "$node_image" npx tsc -p package-tests -in_image "$floor_image" node package-tests/node-floor.js + npm pack --pack-destination /tmp + npm install --no-audit --no-fund --no-package-lock --no-save --offline --prefix package-tests /tmp/*.tgz' +leg "typecheck the consumer ($node_image)" in_image "$node_image" npx tsc -p package-tests +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 diff --git a/docker-runner.sh b/docker-runner.sh index 8602e71..4fa0ad7 100644 --- a/docker-runner.sh +++ b/docker-runner.sh @@ -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" "$@" } +# 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() { local container in_image_network status=0 container=$(docker run -d --rm "$firefox_image") diff --git a/publish.sh b/publish.sh index d0f5999..e4c480c 100755 --- a/publish.sh +++ b/publish.sh @@ -7,31 +7,40 @@ read_field() { 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() { 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 echo 'package.json is private — the maintainer removes that in the bump that first publishes' exit 0 fi -name=$(read_field name) -version=$(read_field version) -published=$(published_version "$name" "$version") -tagged=$(git ls-remote --tags origin "v$version") +published=$(leg "ask npmjs for $name@$version" published_version "$name" "$version") +tagged=$(leg "ask origin for v$version" 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. if [ -z "$published" ]; then : "${NPM_TOKEN:?the publish needs NPM_TOKEN}" - in_image "$node_image" npm ci - in_image "$node_image" npm run build - docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -e NPM_TOKEN -v "$PWD:/app" -w /app --entrypoint sh "$node_image" -c \ + leg "install ($node_image)" in_image "$node_image" npm ci + 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 \ 'printf "//registry.npmjs.org/:_authToken=%s\n" "$NPM_TOKEN" > "$HOME/.npmrc" && npm publish --access public' fi if [ -z "$tagged" ]; then - git tag "v$version" - git push origin "v$version" + leg "tag v$version" push_tag fi