From 02da9ea354c2f197492e652403ad85262be3c152 Mon Sep 17 00:00:00 2001 From: iam-truongtrungnghia Date: Mon, 14 Sep 2026 04:24:53 +0700 Subject: [PATCH] test: stop a background writer failing teardown's rm --- tests/add-app-errors.bats | 2 +- tests/add-app.bats | 2 +- tests/compose.bats | 2 +- tests/docs.bats | 2 +- tests/helpers/setup.bash | 29 +++++++++++++++++++++++++++++ tests/new-flask.bats | 2 +- tests/new-laravel-api.bats | 2 +- tests/new-laravel-inertia.bats | 2 +- tests/new-nestjs.bats | 2 +- tests/new-nextjs.bats | 2 +- tests/new-project.bats | 2 +- tests/publish.bats | 2 +- tests/update.bats | 2 +- tests/workflows.bats | 2 +- 14 files changed, 42 insertions(+), 13 deletions(-) diff --git a/tests/add-app-errors.bats b/tests/add-app-errors.bats index d8bc56f..23c812f 100644 --- a/tests/add-app-errors.bats +++ b/tests/add-app-errors.bats @@ -12,7 +12,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "add refuses to run outside a git repository" { diff --git a/tests/add-app.bats b/tests/add-app.bats index d8fd6d5..f6d9705 100644 --- a/tests/add-app.bats +++ b/tests/add-app.bats @@ -6,7 +6,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "add installs an adapter at an arbitrary path" { diff --git a/tests/compose.bats b/tests/compose.bats index 4a673cc..e600abd 100644 --- a/tests/compose.bats +++ b/tests/compose.bats @@ -6,7 +6,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "the compose files are valid" { diff --git a/tests/docs.bats b/tests/docs.bats index f287618..f14373c 100644 --- a/tests/docs.bats +++ b/tests/docs.bats @@ -6,7 +6,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "docs is a config root with the full contract" { diff --git a/tests/helpers/setup.bash b/tests/helpers/setup.bash index fa45558..b05a4f6 100644 --- a/tests/helpers/setup.bash +++ b/tests/helpers/setup.bash @@ -21,6 +21,11 @@ if [ -z "${GIT_CONFIG_GLOBAL:-}" ]; then export GIT_CONFIG_GLOBAL git config --global user.name "scaffold tests" git config --global user.email "tests@scaffold.invalid" + # `scaffold new` commits, and a commit can hand the repository to a detached + # `git gc`. That process outlives the command and keeps writing into .git, + # which is the likeliest thing remove_workdir below is racing. A throwaway + # repository has nothing worth maintaining. + git config --global gc.auto 0 fi # mise records every config it trusts under its state directory, so a suite @@ -62,3 +67,27 @@ copy_toolbox() { cp "${SCAFFOLD_ROOT}/docs/PROVENANCE.md" "$dest/docs/" 2>/dev/null || true printf '%s' "$dest" } + +# remove_workdir — teardown's `rm -rf`, retried. +# +# `rm -rf` reports "Directory not empty" when an entry appears after it walked +# the directory, so a background process still writing into a generated project +# fails a teardown that has nothing to do with what the test asserted. Seen on +# CI against `tests/compose.bats`, which generates a project per test under +# --jobs, and on a different test each run; never reproduced locally, and the +# writer was never caught in the act, so this waits the race out rather than +# naming a cause. A tree that is genuinely stuck still fails, and says what is +# left in it. +remove_workdir() { + local -r dir="$1" + + for _ in 1 2 3 4 5; do + rm -rf "$dir" 2>/dev/null && return 0 + sleep 1 + done + + rm -rf "$dir" && return 0 + echo "could not remove ${dir}, left behind:" >&2 + find "$dir" >&2 + return 1 +} diff --git a/tests/new-flask.bats b/tests/new-flask.bats index 617854f..584a7d9 100644 --- a/tests/new-flask.bats +++ b/tests/new-flask.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "flask generates an app at apps/api" { diff --git a/tests/new-laravel-api.bats b/tests/new-laravel-api.bats index 8c044f1..431847c 100644 --- a/tests/new-laravel-api.bats +++ b/tests/new-laravel-api.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "laravel-api generates an app at apps/api" { diff --git a/tests/new-laravel-inertia.bats b/tests/new-laravel-inertia.bats index 83c5add..3bbaab3 100644 --- a/tests/new-laravel-inertia.bats +++ b/tests/new-laravel-inertia.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "laravel-inertia generates a single app at apps/app" { diff --git a/tests/new-nestjs.bats b/tests/new-nestjs.bats index e9d94ed..f2b0bc3 100644 --- a/tests/new-nestjs.bats +++ b/tests/new-nestjs.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "nestjs generates an app at apps/api" { diff --git a/tests/new-nextjs.bats b/tests/new-nextjs.bats index cd32c53..80ac60f 100644 --- a/tests/new-nextjs.bats +++ b/tests/new-nextjs.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "nextjs generates an app at apps/web" { diff --git a/tests/new-project.bats b/tests/new-project.bats index ac57077..57199fe 100644 --- a/tests/new-project.bats +++ b/tests/new-project.bats @@ -5,7 +5,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "new creates a git repository on main" { diff --git a/tests/publish.bats b/tests/publish.bats index 209feff..4d56e7d 100644 --- a/tests/publish.bats +++ b/tests/publish.bats @@ -9,7 +9,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } # _stub_gh — a `gh` that records what it was asked to do and answers from diff --git a/tests/update.bats b/tests/update.bats index 7720ed9..7551074 100644 --- a/tests/update.bats +++ b/tests/update.bats @@ -14,7 +14,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } _commit() { diff --git a/tests/workflows.bats b/tests/workflows.bats index fac798e..8228611 100644 --- a/tests/workflows.bats +++ b/tests/workflows.bats @@ -28,7 +28,7 @@ setup() { } teardown() { - rm -rf "$WORKDIR" + remove_workdir "$WORKDIR" } @test "the project ships five workflows" {