prepare-contour-snapshot.sh урезает web/package.json arm-core по разрешённому списку (devDependencies: @rsbuild/core, @rsbuild/plugin-react, tailwindcss, daisyui; optional: raisa-*; scripts: build, start, preview), сокращает web-check до npm install + npm run build, пишет убранное в SNAPSHOT.md и сам собирает урезанный web/ во временной копии: не собралось — снимка нет. Гайд: раздел 3.2 и правило «web/package.json из контура обратно не переносить». Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
136 lines
10 KiB
Bash
Executable File
136 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Тест sync-web.sh на синтетических репозиториях arm-web и arm-core (bare origin + клон), без tea, npm и сети.
|
||
# Сценарии: синхронно; arm-core отстаёт (--check и --dry-run); arm-core правили напрямую (отказ);
|
||
# пайплайн переноса в контур (prepare-contour-snapshot.sh спрашивает / останавливается / идёт «как есть»).
|
||
# Запуск: make test-sync-web (или напрямую из корня docs).
|
||
set -euo pipefail
|
||
|
||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||
SYNC="$HERE/sync-web.sh"
|
||
SNAPSHOT="$HERE/prepare-contour-snapshot.sh"
|
||
WORK=$(mktemp -d)
|
||
trap 'rm -rf "$WORK"' EXIT
|
||
export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t
|
||
|
||
fail=0
|
||
check() { if [ "$1" = 0 ]; then echo "ok: $2"; else echo "FAIL: $2" >&2; fail=1; fi; }
|
||
|
||
put() { mkdir -p "$(dirname "$1")"; printf '%s\n' "${2:-x}" > "$1"; }
|
||
commit_push() { git -C "$1" add -A; git -C "$1" commit -qm "$2"; git -C "$1" push -q origin "HEAD:$3" 2>/dev/null; git -C "$1" fetch -q origin; }
|
||
|
||
# --- синтетический arm-web: ветка test ---------------------------------------------------------------------------
|
||
WEB="$WORK/arm-web"
|
||
git init -q --bare "$WORK/arm-web.git"
|
||
git clone -q "$WORK/arm-web.git" "$WEB" 2>/dev/null
|
||
git -C "$WEB" checkout -q -b test
|
||
put "$WEB/src/a.ts" "export const a = 1;"
|
||
put "$WEB/README.md" "arm-web v1"
|
||
put "$WEB/package.json" '{"name":"web","devDependencies":{"@rsbuild/core":"1","@rsbuild/plugin-react":"1","tailwindcss":"3","daisyui":"4"}}'
|
||
for p in CLAUDE.md .claude/skills/s/SKILL.md openspec/config.yaml openspec/specs/ui/spec.md docs/superpowers/plans/p.md \
|
||
scripts/demo-prepare.sh Makefile ARCHITECTURE.md .gitignore; do put "$WEB/$p" "/Users/someone/arm-web"; done
|
||
commit_push "$WEB" "web v1" test
|
||
POINT=$(git -C "$WEB" rev-parse HEAD)
|
||
|
||
# --- синтетический arm-core: web/ = снимок arm-web v1 без служебных файлов, плюс платформенные файлы ----------------
|
||
CORE="$WORK/arm-core"
|
||
git init -q --bare "$WORK/arm-core.git"
|
||
git clone -q "$WORK/arm-core.git" "$CORE" 2>/dev/null
|
||
git -C "$CORE" checkout -q -b main
|
||
put "$CORE/web/src/a.ts" "export const a = 1;"
|
||
put "$CORE/web/README.md" "arm-web v1"
|
||
put "$CORE/web/package.json" '{"name":"web","devDependencies":{"@rsbuild/core":"1","@rsbuild/plugin-react":"1","tailwindcss":"3","daisyui":"4"}}'
|
||
printf 'venv:\n\tuv venv api/.venv\n' > "$CORE/Makefile"
|
||
for p in raisa_config.yml setup/setup.sh setup/pip.conf api/run_server.py api/requirements.txt api/.env.test \
|
||
api/contracts/schema.json; do put "$CORE/$p"; done
|
||
commit_push "$CORE" "core v1" main
|
||
|
||
COMMON=(--arm-web "$WEB" --arm-core "$CORE" --wt-root "$WORK/wt")
|
||
|
||
# --- 1. синхронно ---------------------------------------------------------------------------------------------------
|
||
rc=0; "$SYNC" --check "${COMMON[@]}" >/dev/null || rc=$?
|
||
check "$([ "$rc" = 0 ] && echo 0 || echo 1)" "синхронно: --check возвращает 0 (rc=$rc)"
|
||
rc=0; out=$("$SYNC" --dry-run "${COMMON[@]}") || rc=$?
|
||
check "$([ "$rc" = 0 ] && [ ! -d "$WORK/wt" ] && echo 0 || echo 1)" "синхронно: --dry-run ничего не делает (rc=$rc)"
|
||
|
||
# --- arm-web уходит вперёд: правка src, новый файл, README; служебные файлы тоже меняются ---------------------------
|
||
put "$WEB/src/a.ts" "export const a = 2;"
|
||
put "$WEB/src/b.ts" "export const b = 1;"
|
||
put "$WEB/README.md" "arm-web v2"
|
||
put "$WEB/CLAUDE.md" "/Users/someone/arm-web v2"
|
||
put "$WEB/scripts/demo-prepare.sh" "v2"
|
||
commit_push "$WEB" "web v2" test
|
||
HEAD7=$(git -C "$WEB" rev-parse --short=7 HEAD)
|
||
|
||
# --- 2. отстаёт: --check ----------------------------------------------------------------------------------------------
|
||
rc=0; out=$("$SYNC" --check "${COMMON[@]}" 2>&1) || rc=$?
|
||
check "$([ "$rc" = 10 ] && echo 0 || echo 1)" "отстаёт: --check возвращает 10 (rc=$rc)"
|
||
check "$(grep -q "web v2" <<<"$out" && echo 0 || echo 1)" "отстаёт: --check перечисляет непереносённые коммиты"
|
||
check "$(grep -q "${POINT:0:7}" <<<"$out" && echo 0 || echo 1)" "отстаёт: --check называет точку синхронизации"
|
||
|
||
# --- 3. отстаёт: --dry-run переносит набор в worktree -------------------------------------------------------------------
|
||
rc=0; "$SYNC" --dry-run "${COMMON[@]}" >/dev/null || rc=$?
|
||
WT="$WORK/wt/web-sync-$HEAD7/arm-core"
|
||
check "$([ "$rc" = 0 ] && [ -d "$WT" ] && echo 0 || echo 1)" "dry-run: worktree $WT создан (rc=$rc)"
|
||
check "$([ "$(git -C "$WT" rev-parse --abbrev-ref HEAD)" = "tmp/web-sync-$HEAD7" ] && echo 0 || echo 1)" "dry-run: временная ветка tmp/web-sync-$HEAD7"
|
||
check "$([ -f "$WT/.bounded" ] && echo 0 || echo 1)" "dry-run: .bounded создан"
|
||
check "$([ "$(cat "$WT/web/src/a.ts")" = "export const a = 2;" ] && echo 0 || echo 1)" "dry-run: изменённый src/a.ts перенесён"
|
||
check "$([ -f "$WT/web/src/b.ts" ] && echo 0 || echo 1)" "dry-run: новый src/b.ts перенесён"
|
||
check "$([ "$(cat "$WT/web/README.md")" = "arm-web v2" ] && echo 0 || echo 1)" "dry-run: README перенесён"
|
||
check "$([ ! -e "$WT/web/CLAUDE.md" ] && [ ! -e "$WT/web/scripts" ] && echo 0 || echo 1)" "dry-run: служебные файлы arm-web не перенесены"
|
||
git -C "$WT" add -A web >/dev/null
|
||
TREE_WT=$(git -C "$WT" write-tree)
|
||
check "$([ "$(git -C "$WT" rev-parse "$TREE_WT:web/src")" = "$(git -C "$WEB" rev-parse test:src)" ] && echo 0 || echo 1)" "dry-run: дерево web/src совпадает с arm-web test:src"
|
||
git -C "$WT" reset -q
|
||
rc=0; "$SYNC" --dry-run "${COMMON[@]}" >/dev/null 2>&1 || rc=$?
|
||
check "$([ "$rc" != 0 ] && echo 0 || echo 1)" "dry-run повторно: отказ, worktree уже существует (rc=$rc)"
|
||
git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7"
|
||
|
||
# --- 4. пайплайн переноса: prepare-contour-snapshot.sh видит отставание ---------------------------------------------
|
||
# сети в тесте нет: проверку сборки web/ в снимке отключаем (она покрыта test_prepare_contour_snapshot.sh)
|
||
export SNAPSHOT_SKIP_WEB_BUILD=1
|
||
export ARM_WEB="$WEB" SYNC_WEB_ARGS="--dry-run --wt-root $WORK/wt"
|
||
rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out1" origin/main </dev/null 2>&1) || rc=$?
|
||
check "$([ "$rc" = 3 ] && echo 0 || echo 1)" "пайплайн без терминала: перенос остановлен, rc=3 (rc=$rc)"
|
||
check "$(grep -qi "остановлен" <<<"$out" && echo 0 || echo 1)" "пайплайн: сообщение «перенос остановлен до завершения синхронизации»"
|
||
check "$([ -d "$WT" ] && [ -f "$WT/web/src/b.ts" ] && echo 0 || echo 1)" "пайплайн: синхронизация запущена, worktree создан"
|
||
check "$([ ! -d "$WORK/out1/arm-core" ] && echo 0 || echo 1)" "пайплайн: снимок не создан"
|
||
git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7"
|
||
|
||
rc=0; out=$(printf 'y\n' | "$SNAPSHOT" "$CORE" "$WORK/out2" origin/main 2>&1) || rc=$?
|
||
check "$([ "$rc" = 0 ] && [ -f "$WORK/out2/arm-core/web/src/a.ts" ] && [ ! -e "$WORK/out2/arm-core/web/src/b.ts" ] && echo 0 || echo 1)" \
|
||
"пайплайн, ответ «y»: снимок как есть (rc=$rc)"
|
||
rc=0; out=$(printf 'n\n' | "$SNAPSHOT" "$CORE" "$WORK/out3" origin/main 2>&1) || rc=$?
|
||
check "$([ "$rc" = 3 ] && [ -d "$WT" ] && echo 0 || echo 1)" "пайплайн, ответ «n»: синхронизация запущена, перенос остановлен (rc=$rc)"
|
||
git -C "$CORE" worktree remove --force "$WT"; git -C "$CORE" branch -q -D "tmp/web-sync-$HEAD7"
|
||
|
||
rc=0; out=$("$SNAPSHOT" --web-as-is "$CORE" "$WORK/out4" origin/main </dev/null 2>&1) || rc=$?
|
||
check "$([ "$rc" = 0 ] && [ -f "$WORK/out4/arm-core/SNAPSHOT.md" ] && echo 0 || echo 1)" "пайплайн, --web-as-is: снимок без вопроса (rc=$rc)"
|
||
check "$(grep -q "отстаёт" "$WORK/out4/arm-core/SNAPSHOT.md" && echo 0 || echo 1)" "пайплайн, --web-as-is: отставание записано в SNAPSHOT.md"
|
||
unset SYNC_WEB_ARGS
|
||
|
||
# arm-web рядом нет (в тесте он есть как сосед $CORE, поэтому путь задаётся явно несуществующим)
|
||
export ARM_WEB="$WORK/no-such-arm-web"
|
||
rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out5" origin/main </dev/null 2>&1) || rc=$?
|
||
check "$([ "$rc" = 0 ] && grep -q "arm-web не найден" <<<"$out" && echo 0 || echo 1)" "пайплайн без arm-web рядом: предупреждение, снимок сделан (rc=$rc)"
|
||
unset ARM_WEB
|
||
|
||
# --- 5. arm-core правили напрямую: точки синхронизации нет ----------------------------------------------------------
|
||
put "$CORE/web/src/a.ts" "export const a = 'direct';"
|
||
commit_push "$CORE" "core: прямая правка web" main
|
||
rc=0; out=$("$SYNC" --check "${COMMON[@]}" 2>&1) || rc=$?
|
||
check "$([ "$rc" = 20 ] && echo 0 || echo 1)" "прямая правка arm-core: --check возвращает 20 (rc=$rc)"
|
||
check "$(grep -q "прямая правка web" <<<"$out" && echo 0 || echo 1)" "прямая правка arm-core: названы коммиты arm-core по web/"
|
||
export ARM_WEB="$WEB"
|
||
rc=0; out=$("$SNAPSHOT" "$CORE" "$WORK/out6" origin/main </dev/null 2>&1) || rc=$?
|
||
check "$([ "$rc" != 0 ] && [ ! -d "$WORK/out6/arm-core" ] && echo 0 || echo 1)" "пайплайн при расхождении: снимок не делается (rc=$rc)"
|
||
unset ARM_WEB
|
||
|
||
# --- 6. вызовы tea: флаги после подкоманды ---------------------------------------------------------------------------
|
||
# tea 0.16 не принимает --login/--repo перед подкомандой («flag provided but not defined: -login», arm-ka-docs#110);
|
||
# сам tea тест не вызывает (нет сети), поэтому проверяется текст скриптов
|
||
bad=$(grep -nE '(^|[^[:alnum:]_-])tea[[:space:]]+-' "$SYNC" "$SNAPSHOT" || true)
|
||
check "$([ -z "$bad" ] && echo 0 || echo 1)" "tea: флаги идут после подкоманды${bad:+ — нарушения: $bad}"
|
||
|
||
[ "$fail" = 0 ] || exit 1
|
||
echo "ok: sync-web.sh — точка синхронизации, перенос набора, отказ при расхождении, пайплайн переноса"
|