SDD workspace в worktree активной задачи хвостом не считается (O-19, живой прогон). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
5.5 KiB
Bash
61 lines
5.5 KiB
Bash
# retro_leftovers.py: хвосты чеклиста закрытия по состоянию репозиториев (спека harness-retro, #29).
|
||
L="$ROOT/docs/retro/scripts/retro_leftovers.py"
|
||
G="$TMP/lo"; mkdir -p "$G"
|
||
git init -q --bare -b main "$G/o.git"
|
||
git clone -q "$G/o.git" "$G/c" 2>/dev/null; git -C "$G/c" symbolic-ref HEAD refs/heads/main
|
||
printf '.superpowers/\n.claude/worktrees/\n' > "$G/c/.gitignore"
|
||
git -C "$G/c" add .gitignore && git -C "$G/c" commit -q -m init && git -C "$G/c" push -q origin main 2>/dev/null
|
||
git -C "$G/c" switch -q -c feat/1 && git -C "$G/c" commit -q --allow-empty -m f1 && git -C "$G/c" push -q -u origin feat/1 2>/dev/null
|
||
git -C "$G/c" switch -q main && git -C "$G/c" merge -q --no-ff feat/1 -m "merge feat/1"
|
||
mkdir -p "$G/c/openspec/changes/foo" "$G/c/openspec/changes/archive/2026-01-01-bar"
|
||
echo x > "$G/c/openspec/changes/foo/proposal.md"; echo y > "$G/c/openspec/changes/archive/2026-01-01-bar/p.md"
|
||
git -C "$G/c" add openspec && git -C "$G/c" commit -q -m spec && git -C "$G/c" push -q origin main 2>/dev/null
|
||
git -C "$G/c" worktree add -q "$G/c/.claude/worktrees/w1" feat/1
|
||
mkdir -p "$G/c/.superpowers/sdd/plan-x" && touch "$G/c/.superpowers/sdd/plan-x/progress.md"
|
||
# активная задача: worktree на неслитой ветке со своим SDD workspace — не хвост
|
||
git -C "$G/c" worktree add -q "$G/c/.claude/worktrees/w2" -b feat/2 && git -C "$G/c/.claude/worktrees/w2" commit -q --allow-empty -m wip
|
||
mkdir -p "$G/c/.claude/worktrees/w2/.superpowers/sdd/plan-y" && touch "$G/c/.claude/worktrees/w2/.superpowers/sdd/plan-y/progress.md"
|
||
git clone -q "$G/o.git" "$G/c2" 2>/dev/null && git -C "$G/c2" commit -q --allow-empty -m ahead && git -C "$G/c2" push -q origin main 2>/dev/null
|
||
git -C "$G/c" fetch -q origin
|
||
echo x > "$G/c/untracked.txt"
|
||
J="$TMP/lo.json"
|
||
python3 "$L" "$G/c" > "$J"; rc=$?
|
||
assert_eq "хвосты: exit 0" "$rc" "0"
|
||
k(){ python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print(eval(sys.argv[2]))' "$J" "$1"; }
|
||
assert_eq "виды хвостов" "$(k 'sorted(d["totals"])')" "['local-branch', 'main-behind', 'main-dirty', 'openspec-change', 'remote-branch', 'sdd-workspace', 'worktree']"
|
||
assert_eq "ветка на сервере и подсказка" "$(k '[(i["item"], i["hint"]) for i in d["items"] if i["kind"] == "remote-branch"]')" "[('origin/feat/1', 'git push origin --delete feat/1')]"
|
||
assert_eq "локальная ветка" "$(k '[i["item"] for i in d["items"] if i["kind"] == "local-branch"]')" "['feat/1']"
|
||
assert_eq "worktree на слитой ветке" "$(k '[i["item"].endswith("/.claude/worktrees/w1") for i in d["items"] if i["kind"] == "worktree"]')" "[True]"
|
||
assert_eq "SDD workspace" "$(k '[i["item"].endswith("/sdd/plan-x") for i in d["items"] if i["kind"] == "sdd-workspace"]')" "[True]"
|
||
assert_eq "неархивный change — без archive" "$(k '[i["item"] for i in d["items"] if i["kind"] == "openspec-change"]')" "['openspec/changes/foo']"
|
||
assert_grep "отставание от origin/main" 'позади origin/main на 1' "$J"
|
||
assert_grep "грязное дерево с путём" 'untracked.txt' "$J"
|
||
# только чтение: без --fetch ссылки и дерево не меняются
|
||
git -C "$G/c2" commit -q --allow-empty -m ahead2 && git -C "$G/c2" push -q origin main 2>/dev/null
|
||
before="$(git -C "$G/c" for-each-ref)$(git -C "$G/c" status --porcelain)"
|
||
python3 "$L" "$G/c" > /dev/null
|
||
assert_eq "без --fetch ничего не меняется" "$(git -C "$G/c" for-each-ref)$(git -C "$G/c" status --porcelain)" "$before"
|
||
python3 "$L" "$G/c" --fetch > "$J"
|
||
assert_grep "--fetch видит новые коммиты" 'позади origin/main на 2' "$J"
|
||
md=$(python3 "$L" "$G/c" --markdown)
|
||
assert_grep "таблица для черновика" '^\| remote-branch \| c \| `origin/feat/1` \| `git push origin --delete feat/1` \|$' <(printf '%s' "$md")
|
||
# чистый репозиторий: свежая ветка на вершине origin/main — не хвост
|
||
git init -q --bare -b main "$G/k.git"; git clone -q "$G/k.git" "$G/k" 2>/dev/null; git -C "$G/k" symbolic-ref HEAD refs/heads/main
|
||
git -C "$G/k" commit -q --allow-empty -m init && git -C "$G/k" push -q origin main 2>/dev/null && git -C "$G/k" branch feat/new
|
||
python3 "$L" "$G/k" > "$J"
|
||
assert_eq "чистый репозиторий — хвостов нет" "$(k 'd["items"]')" "[]"
|
||
assert_eq "чистый репозиторий — markdown" "$(python3 "$L" "$G/k" --markdown)" "Хвостов закрытия нет."
|
||
# без origin
|
||
git init -q -b main "$G/n" && git -C "$G/n" commit -q --allow-empty -m init
|
||
python3 "$L" "$G/n" > "$J"; rc=$?
|
||
assert_eq "без origin: exit 0 и no-origin-main" "$rc $(k '[i["kind"] for i in d["items"]]')" "0 ['no-origin-main']"
|
||
# workspace: репозитории из таблицы CLAUDE.md
|
||
W="$TMP/ws"; mkdir -p "$W"; git clone -q "$G/o.git" "$W/r" 2>/dev/null
|
||
printf '# w\n\n| Каталог | Репозиторий | Роль |\n|---|---|---|\n| r/ | o/r | dev |\n| - | x | qa |\n' > "$W/CLAUDE.md"
|
||
python3 "$L" "$W" > "$J"
|
||
assert_eq "workspace: репозитории из таблицы" "$(k '[r.endswith("/ws/r") for r in d["repos"]]')" "[True]"
|
||
assert_eq "workspace: ветка на сервере видна" "$(k '[i["item"] for i in d["items"] if i["kind"] == "remote-branch"]')" "['origin/feat/1']"
|
||
# не проект и не workspace
|
||
mkdir -p "$TMP/empty"; python3 "$L" "$TMP/empty" > /dev/null 2>&1; rc=$?
|
||
assert_eq "не репозиторий и не workspace: exit 1" "$rc" "1"
|