From 63728c1f216da2c5cae3f949c2f805b8926c1b68 Mon Sep 17 00:00:00 2001 From: Anay Dhawan Date: Mon, 17 Aug 2026 09:26:29 +0530 Subject: [PATCH] fix: apply.sh writes to a temp dir first, commits to target only after generation succeeds A crash mid-generation (a missing template, a fill() failure on some stack's command table) previously left the target repo with whichever files had written before the failure. Because apply.sh never overwrites an existing file, a re-run then skipped the files it did manage to write on the first, partial pass -- a confusing state to land in. Generation now writes into a mktemp staging dir; the target repo is only touched in a final commit loop once every write has already succeeded once. Fixes #43. --- scripts/apply.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/apply.sh b/scripts/apply.sh index c7ed8f1..a7d4887 100644 --- a/scripts/apply.sh +++ b/scripts/apply.sh @@ -34,6 +34,14 @@ if [ -z "$DIR" ] || [ ! -d "$DIR" ]; then fi DIR="$(cd "$DIR" && pwd)" +# Generated files land in STAGE first, not $DIR directly. A crash mid-generation (a +# missing template, a fill() failure on some stack's command table) then leaves the +# target repo untouched instead of holding whichever files happened to write before the +# failure. The "never overwrites an existing file" check below still reads real $DIR, so +# skip decisions are unaffected; only the write destination moves. +STAGE="$(mktemp -d)" +trap 'rm -rf "$STAGE"' EXIT + CREATED=(); SKIPPED=(); MANUAL=() # --- 0. scan --- @@ -126,11 +134,11 @@ default_var INITIAL_FEATURE_2 "See README for details." # --- 3. generate (skip anything that already exists -- see file header) --- write() { # write - local rel="$1" src="$2" dest="$DIR/$1" + local rel="$1" src="$2" dest="$DIR/$1" staged="$STAGE/$1" if [ -e "$dest" ]; then SKIPPED+=("$rel"); return; fi - mkdir -p "$(dirname "$dest")" - cp "$src" "$dest" - fill "$dest" + mkdir -p "$(dirname "$staged")" + cp "$src" "$staged" + fill "$staged" CREATED+=("$rel") } @@ -216,6 +224,14 @@ if [ ! -f "$DIR/README.md" ]; then fi MANUAL+=("Labels: run 'bash scripts/setup-labels.sh ${OWNER}/${REPO}' -- .github/labeler.yml references labels that must exist first") +# --- commit: move everything from STAGE into $DIR now that generation finished without +# error. This is the only loop that touches the target repo; every path in CREATED +# already rendered successfully once, so this is data movement, not generation. --- +for rel in "${CREATED[@]}"; do + mkdir -p "$DIR/$(dirname "$rel")" + cp "$STAGE/$rel" "$DIR/$rel" +done + # --- 4. re-audit --- DETECTED="stack: $STACK" [ -n "$MONOREPO" ] && DETECTED="$DETECTED, $MONOREPO monorepo"