@biffo/cli 0.250.1 → 0.250.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.250.1",
3
+ "version": "0.250.3",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -157,6 +157,54 @@ psql_db() { psql -q -h "$HOST" -p "$PORT" -U "$USER_" -d "$DB" "$@"; }
157
157
  #
158
158
  # Started here rather than assumed, because "docker run one yourself" is exactly
159
159
  # the tribal knowledge this script replaces. An already-running server is reused.
160
+ # ── Reap abandoned sibling containers ────────────────────────────────────────
161
+ #
162
+ # The container name is keyed to the CHECKOUT (see `CONTAINER` above), which is
163
+ # what makes reuse work -- and also what makes them accumulate: every worktree
164
+ # ever created leaves one behind, running, forever. Nothing ever removed them.
165
+ # Measured on one workstation: 76 live `biffo-pg-test-*` containers holding
166
+ # ~5.4 GiB, the oldest four days old (tabsii-platform#703). That is not merely
167
+ # untidy -- they compete for the same page cache and I/O as the lane being
168
+ # timed, so a leak like this shows up as the pg gate drifting toward its own
169
+ # timeout, which is the failure #703 was actually filed about.
170
+ #
171
+ # Age is the only signal available. Docker records when a container was CREATED,
172
+ # not when it was last used, and `docker ps --filter until=` is a prune filter
173
+ # that this daemon rejects on `ps` -- so the comparison is done here.
174
+ #
175
+ # Reaping something still wanted is cheap and self-correcting: the next run
176
+ # recreates it, which this script's own header prices at ~4s against ~0.3s for
177
+ # reuse. Being wrong therefore costs four seconds, once. Leaving them costs a
178
+ # gigabyte a day.
179
+ #
180
+ # NEVER reaps this checkout's own container, is skipped entirely when the date
181
+ # maths is unavailable rather than guessing, and never fails the run: a
182
+ # housekeeping step that can break a test lane is worse than the mess it clears.
183
+ BIFFO_PG_REAP_HOURS="${BIFFO_PG_REAP_HOURS:-24}"
184
+ if [ "$BIFFO_PG_REAP_HOURS" -gt 0 ] 2>/dev/null && command -v docker >/dev/null 2>&1; then
185
+ # GNU first, then BSD/macOS. If neither answers, say so and skip -- a silent
186
+ # skip here would be the same fail-open this estate keeps finding.
187
+ _reap_cutoff=$(date -u -d "-${BIFFO_PG_REAP_HOURS} hours" +%Y-%m-%dT%H:%M:%S 2>/dev/null) ||
188
+ _reap_cutoff=$(date -u -v-"${BIFFO_PG_REAP_HOURS}"H +%Y-%m-%dT%H:%M:%S 2>/dev/null) || _reap_cutoff=""
189
+ if [ -z "$_reap_cutoff" ]; then
190
+ say "cannot compute a reap cutoff on this date(1); skipping container reaping"
191
+ else
192
+ _reaped=0
193
+ for _c in $(docker ps -a --filter "name=biffo-pg-test-" --format '{{.Names}}' 2>/dev/null); do
194
+ [ "$_c" = "$CONTAINER" ] && continue
195
+ _made=$(docker inspect -f '{{.Created}}' "$_c" 2>/dev/null | cut -c1-19)
196
+ [ -z "$_made" ] && continue
197
+ # Both are UTC ISO-8601 to the second, so a string compare IS a time
198
+ # compare -- no epoch conversion, and portable across date(1) flavours.
199
+ if awk -v a="$_made" -v b="$_reap_cutoff" 'BEGIN { exit !(a < b) }'; then
200
+ docker rm -f "$_c" >/dev/null 2>&1 && _reaped=$((_reaped + 1))
201
+ fi
202
+ done
203
+ [ "$_reaped" -gt 0 ] &&
204
+ say "reaped $_reaped container(s) unused for over ${BIFFO_PG_REAP_HOURS}h (set BIFFO_PG_REAP_HOURS=0 to disable)"
205
+ fi
206
+ fi
207
+
160
208
  if ! psql_admin -c 'SELECT 1' >/dev/null 2>&1; then
161
209
  if ! command -v docker >/dev/null 2>&1; then
162
210
  say "no Postgres at $HOST:$PORT and docker is not installed."
package/scripts/verify.sh CHANGED
@@ -688,8 +688,42 @@ pg_test_modules() {
688
688
  # assertions its CI workflow makes, for the same reason.
689
689
  pg_test_run() {
690
690
  _out="/tmp/biffo-verify-pg.$$"
691
- if ! TABSII_TEST_PG_DSN="$PG_TEST_DSN" BIFFO_TEST_PG_DSN="$PG_TEST_DSN" \
692
- timeout "$PG_TEST_BUDGET_SECONDS" uv run --directory "$1" pytest -q $2 >"$_out" 2>&1; then
691
+ _pg_started=$(date +%s)
692
+ TABSII_TEST_PG_DSN="$PG_TEST_DSN" BIFFO_TEST_PG_DSN="$PG_TEST_DSN" \
693
+ timeout "$PG_TEST_BUDGET_SECONDS" uv run --directory "$1" pytest -q $2 >"$_out" 2>&1
694
+ _pg_rc=$?
695
+ _pg_elapsed=$(($(date +%s) - _pg_started))
696
+
697
+ # `timeout` exits 124 when it kills the command (137 if SIGKILL was needed).
698
+ # Reported apart from a real failure, because they are different facts and
699
+ # this gate used to render them identically: a killed run printed
700
+ # `verify failed: pg-test` with NO failing test named, which reads exactly
701
+ # like a defect and sends the reader hunting one. It happened on
702
+ # tabsii-platform (#703) -- the same push succeeded on retry, unchanged.
703
+ #
704
+ # Same discipline as `wait-for-checks` and the dependency audits: "could not
705
+ # determine" must never wear the clothes of "found something wrong".
706
+ if [ "$_pg_rc" -eq 124 ] || [ "$_pg_rc" -eq 137 ]; then
707
+ echo "TIMED OUT after ${_pg_elapsed}s (budget ${PG_TEST_BUDGET_SECONDS}s)."
708
+ echo ""
709
+ echo "This is INCONCLUSIVE, not a failing test: the lane was killed partway,"
710
+ echo "so nothing below is a verdict on your change. Do not go looking for a"
711
+ echo "bug on this evidence."
712
+ echo ""
713
+ echo "Most likely the lane has simply outgrown its budget. Re-run with more:"
714
+ echo " BIFFO_VERIFY_PG_BUDGET=$((PG_TEST_BUDGET_SECONDS * 2)) sh scripts/verify.sh"
715
+ echo ""
716
+ echo "If that passes, raise PG_TEST_BUDGET_SECONDS rather than living with a"
717
+ echo "gate that fails at random -- and re-measure the comment above it, which"
718
+ echo "records what the lane cost when the number was last chosen."
719
+ echo ""
720
+ echo "Partial output before the kill (NOT a result):"
721
+ tail -15 "$_out"
722
+ rm -f "$_out"
723
+ return 1
724
+ fi
725
+
726
+ if [ "$_pg_rc" -ne 0 ]; then
693
727
  cat "$_out"
694
728
  rm -f "$_out"
695
729
  return 1
@@ -707,6 +741,13 @@ pg_test_run() {
707
741
  rm -f "$_out"
708
742
  return 1
709
743
  fi
744
+ # A pass with almost no headroom is the state just before the confusing
745
+ # failure above, and it is silent unless somebody says so. 80% is early
746
+ # enough to act on and rare enough not to become noise.
747
+ if [ "$((_pg_elapsed * 100))" -gt "$((PG_TEST_BUDGET_SECONDS * 80))" ]; then
748
+ printf '\033[33m note: pg-test took %ss of a %ss budget -- raise PG_TEST_BUDGET_SECONDS before it starts timing out at random.\033[0m\n' \
749
+ "$_pg_elapsed" "$PG_TEST_BUDGET_SECONDS"
750
+ fi
710
751
  rm -f "$_out"
711
752
  return 0
712
753
  }