Files
loop-loop/lib/archive.sh

90 lines
3.7 KiB
Bash

#!/bin/bash
# Branch archiving — archives previous run artifacts when the branch changes.
# Preserves prd.json, progress.md, and contracts from the previous feature.
#
# Design: At the end of each run, snapshot_for_archive saves current artifacts
# to .archive-staging/. On the next run, if the branch changed, check_archive
# moves the snapshot to archive/ and cleans up. This avoids archiving the
# WRONG artifacts (the new feature's) when prd.json has already been overwritten.
LAST_BRANCH_FILE="$LOOP_DIR/.last-branch"
STAGING_DIR="$LOOP_DIR/.archive-staging"
# Snapshot current artifacts so they can be archived later if the branch changes.
# Call this at the END of a successful run or before exit.
snapshot_for_archive() {
rm -rf "$STAGING_DIR"
mkdir -p "$STAGING_DIR"
[ -f "$LOOP_DIR/prd.json" ] && cp "$LOOP_DIR/prd.json" "$STAGING_DIR/"
[ -f "$LOOP_DIR/progress.md" ] && cp "$LOOP_DIR/progress.md" "$STAGING_DIR/"
[ -d "$LOOP_DIR/contracts" ] && cp -r "$LOOP_DIR/contracts" "$STAGING_DIR/"
}
# Check if we need to archive and do so if branch changed.
# Reads the NEW branch from live prd.json and the OLD branch from the staging
# snapshot (which was saved at the end of the previous run). This avoids the
# bug where both branches read from the same (already-overwritten) prd.json.
check_archive() {
local current_branch
current_branch=$(prd_branch_name 2>/dev/null)
[ -z "$current_branch" ] && return
# Determine the previous branch from the staging snapshot (most reliable)
# or fall back to .last-branch file
local last_branch=""
if [ -f "$STAGING_DIR/prd.json" ]; then
if command -v jq &>/dev/null; then
last_branch=$(jq -r '.branchName // empty' "$STAGING_DIR/prd.json" 2>/dev/null)
else
last_branch=$(LOOP_PRD="$STAGING_DIR/prd.json" python3 -c "
import json, os
print(json.load(open(os.environ['LOOP_PRD'])).get('branchName', ''), end='')
" 2>/dev/null)
fi
fi
[ -z "$last_branch" ] && [ -f "$LAST_BRANCH_FILE" ] && last_branch=$(cat "$LAST_BRANCH_FILE")
if [ -n "$last_branch" ] && [ "$last_branch" != "$current_branch" ]; then
archive_run "$last_branch"
fi
echo "$current_branch" > "$LAST_BRANCH_FILE"
}
# Archive the previous run's staged artifacts (NOT current prd.json)
archive_run() {
local branch_name="$1"
local feature_name
feature_name=$(echo "$branch_name" | sed 's|.*/||')
local archive_dir="$LOOP_DIR/archive/$(date +%Y-%m-%d)-${feature_name}"
mkdir -p "$archive_dir"
if [ -d "$STAGING_DIR" ]; then
# Use the staged snapshot (correct artifacts from the previous run)
cp -r "$STAGING_DIR"/* "$archive_dir/" 2>/dev/null || true
rm -rf "$STAGING_DIR"
else
# Fallback: no snapshot exists (first run or upgrade from old version).
# Current artifacts may belong to the new feature — archive what we have
# but warn the user.
log "WARNING: No archive snapshot found. Archiving current artifacts (may be from new feature)."
[ -f "$LOOP_DIR/prd.json" ] && cp "$LOOP_DIR/prd.json" "$archive_dir/"
[ -f "$LOOP_DIR/progress.md" ] && cp "$LOOP_DIR/progress.md" "$archive_dir/"
[ -d "$LOOP_DIR/contracts" ] && cp -r "$LOOP_DIR/contracts" "$archive_dir/"
fi
# Verify the archive received content before deleting originals
if ! find "$archive_dir" -maxdepth 1 -type f | read -r; then
log "WARNING: Archive directory $archive_dir is empty after copy — skipping deletion of originals to prevent data loss"
return
fi
# Clean up old run's artifacts (progress.md, contracts — NOT prd.json which belongs to new feature)
rm -f "$LOOP_DIR/progress.md"
rm -rf "$LOOP_DIR/contracts"
log "Archived previous run to $archive_dir"
}