Three coordinated fixes from the upgrade-flow redesign plan (/home/bunker-admin/.claude/plans/okay-so-we-can-enumerated-hejlsberg.md): 1. scripts/lib/mkdocs-snapshot.sh (NEW): pre-upgrade tarball snapshot of the entire mkdocs/ directory into the install root as mkdocs-backup-<timestamp>.tar.gz. Discoverable via `ls`, retained last 5. No-regrets fallback if anything in the upgrade goes sideways. Sourced by upgrade.sh (and later by image-upgrade.sh under Approach B). 2. scripts/upgrade.sh Phase 6 self-destruct fix: previously, the broad `docker compose up -d` recreated the ccp-agent container that was running the script, sending SIGKILL to the bash process before write_result could land result.json. Marcelle's test upgrade hit this tonight. Fix: temporarily remove `ccp-agent` from COMPOSE_PROFILES during Phase 6's broad up -d, then schedule a detached `nohup ... & disown` restart at the very end of the script (after write_result and archive_success_to_history). The deferred subshell sleeps 3s, then recreates ccp-agent under its profile, picking up the new image. 3. scripts/upgrade-stash-cleanup.sh (NEW): one-shot utility to list and drop accumulated `upgrade-*` git stashes left over by older upgrade.sh runs whose pop failed silently (Pride Corner has three from 2026-03-09 alone). Warns loudly if any stash holds tenant mkdocs.yml content so operators verify recovery before dropping. The .gitignore now excludes /mkdocs-backup-*.tar.gz so the rescue archives don't leak into commits. This is Phase 1 of three: Approach B (image-only upgrade mode) and Approach C (CCP template re-render) follow in subsequent commits. Bunker Admin
136 lines
4.5 KiB
Bash
Executable File
136 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# upgrade-stash-cleanup.sh — clean up stale upgrade-* git stashes
|
|
# =============================================================================
|
|
# Older versions of upgrade.sh used `git stash push --include-untracked` to
|
|
# protect tenant content during pulls. When pop conflicts went unresolved,
|
|
# the stashes accumulated in `git stash list` forever — Pride Corner ended up
|
|
# with three from 2026-03-09 alone, each containing displaced tenant
|
|
# customizations that the running site no longer reflected.
|
|
#
|
|
# This script lists every `upgrade-*` stash, shows its scope, and offers to
|
|
# drop them. It does NOT auto-restore content; that's a separate decision per
|
|
# tenant. The intent is to clear the backlog so future `git stash list` is
|
|
# meaningful.
|
|
#
|
|
# Usage:
|
|
# bash scripts/upgrade-stash-cleanup.sh # interactive, lists + prompts
|
|
# bash scripts/upgrade-stash-cleanup.sh --dry # list only
|
|
# bash scripts/upgrade-stash-cleanup.sh --yes # drop all upgrade-* without prompt
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
cd "$PROJECT_DIR"
|
|
|
|
# Colors
|
|
if [[ -t 1 ]] && [[ -z "${NO_COLOR:-}" ]]; then
|
|
RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m'
|
|
BOLD='\033[1m' NC='\033[0m'
|
|
else
|
|
RED='' GREEN='' YELLOW='' CYAN='' BOLD='' NC=''
|
|
fi
|
|
|
|
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
|
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
|
|
DRY=false
|
|
YES=false
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--dry|--dry-run) DRY=true ;;
|
|
--yes|-y) YES=true ;;
|
|
--help|-h)
|
|
sed -n '2,/^# =====/p' "$0" | sed -n '2,/^# =====/p' | sed 's/^# //;s/^#//'
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ ! -d .git ]]; then
|
|
warn "Not a git repository — this script only applies to source installs."
|
|
exit 0
|
|
fi
|
|
|
|
# Collect upgrade-* stash refs
|
|
mapfile -t STASHES < <(git stash list 2>/dev/null | grep -E ': (On|WIP on) [^:]+: upgrade-' || true)
|
|
|
|
if [[ ${#STASHES[@]} -eq 0 ]]; then
|
|
ok "No upgrade-* stashes found. Nothing to clean up."
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Found ${#STASHES[@]} upgrade-* stash(es):${NC}"
|
|
echo ""
|
|
for entry in "${STASHES[@]}"; do
|
|
REF="${entry%%:*}"
|
|
LABEL="${entry#*: }"
|
|
FILE_COUNT=$(git stash show "$REF" --name-only 2>/dev/null | wc -l)
|
|
HAS_MKDOCS_YML=$(git stash show "$REF" --name-only 2>/dev/null | grep -c '^mkdocs/mkdocs\.yml$' || true)
|
|
printf " %-12s %-50s files=%-4d mkdocs.yml=%s\n" \
|
|
"$REF" "$LABEL" "$FILE_COUNT" "$HAS_MKDOCS_YML"
|
|
done
|
|
echo ""
|
|
|
|
if [[ "$DRY" == "true" ]]; then
|
|
info "Dry-run: no stashes will be dropped."
|
|
exit 0
|
|
fi
|
|
|
|
# Warn loudly if any stash holds mkdocs.yml — operator should manually review
|
|
# before dropping (tenant content might be there).
|
|
MKDOCS_STASHES=$(printf '%s\n' "${STASHES[@]}" \
|
|
| while read -r entry; do
|
|
REF="${entry%%:*}"
|
|
if git stash show "$REF" --name-only 2>/dev/null | grep -q '^mkdocs/mkdocs\.yml$'; then
|
|
echo "$REF"
|
|
fi
|
|
done)
|
|
|
|
if [[ -n "$MKDOCS_STASHES" ]]; then
|
|
echo ""
|
|
echo -e "${RED}${BOLD}⚠ WARNING:${NC} the following stashes contain ${BOLD}mkdocs/mkdocs.yml${NC}:"
|
|
echo "$MKDOCS_STASHES" | sed 's/^/ /'
|
|
echo ""
|
|
echo " These may hold tenant branding (site_name, site_url, custom theme, etc.)"
|
|
echo " that ISN'T reflected on disk. Before dropping, verify:"
|
|
echo ""
|
|
echo " git show <stash-ref>:mkdocs/mkdocs.yml | head -10"
|
|
echo " diff <(git show <stash-ref>:mkdocs/mkdocs.yml) mkdocs/mkdocs.yml"
|
|
echo ""
|
|
echo " If disk mkdocs.yml already has the tenant content, the stash is safe to drop."
|
|
echo " If disk is upstream and stash has tenant content, restore first:"
|
|
echo " git checkout <stash-ref> -- mkdocs/mkdocs.yml"
|
|
echo ""
|
|
fi
|
|
|
|
if [[ "$YES" != "true" ]]; then
|
|
echo -en "${BOLD}Drop all ${#STASHES[@]} upgrade-* stashes? [y/N] ${NC}"
|
|
read -r CONFIRM
|
|
case "$CONFIRM" in
|
|
y|Y|yes|YES) ;;
|
|
*) info "Cancelled. No stashes dropped."; exit 0 ;;
|
|
esac
|
|
fi
|
|
|
|
# Drop in reverse order so indices stay stable
|
|
mapfile -t SORTED_REFS < <(printf '%s\n' "${STASHES[@]}" \
|
|
| sed 's/:.*//' \
|
|
| sort -t'{' -k2 -n -r)
|
|
|
|
for REF in "${SORTED_REFS[@]}"; do
|
|
if git stash drop "$REF" >/dev/null 2>&1; then
|
|
ok "Dropped $REF"
|
|
else
|
|
warn "Failed to drop $REF (already gone?)"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
ok "Cleanup complete. Remaining stashes:"
|
|
git stash list 2>/dev/null || echo " (none)"
|