feat(scripts): prepare-contour-snapshot.sh проверяет свежесть копии arm_statements (sync-statements --check, Р-42) (#120)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
bb7c1a0c07
commit
7900191401
2
Makefile
2
Makefile
@ -24,7 +24,7 @@ validate-openspec:
|
||||
|
||||
# Снимок для контура вырезает артефакты агента на любой глубине (dev/contour-transfer-guide.md §3); нужны git и bash
|
||||
test-snapshot:
|
||||
scripts/test_prepare_contour_snapshot.sh
|
||||
STATEMENTS_PY=$(PY) scripts/test_prepare_contour_snapshot.sh
|
||||
|
||||
# sync-web.sh на синтетических репозиториях: точка синхронизации, перенос набора, отказ при расхождении, пайплайн переноса
|
||||
test-sync-web:
|
||||
|
||||
@ -71,6 +71,10 @@ docs/scripts/prepare-contour-snapshot.sh scan-gateway /tmp/contour
|
||||
задаётся: нужен флаг `--web-as-is` первым аргументом, иначе код 3. Если `web/` правили напрямую в arm-core мимо arm-web
|
||||
(точки синхронизации нет) — снимок не делается, разбирать вручную. Если `arm-web` рядом не найден — предупреждение,
|
||||
снимок делается.
|
||||
0a. Для каждого сервиса, где в `<ref>` есть `api/arm_statements/`: проверяет свежесть копии пакета (`sync-statements.sh --check`
|
||||
по дереву `<ref>`). Отстаёт — предупреждение и абзац в `SNAPSHOT.md`; копия правлена напрямую или чужая — снимок не
|
||||
делается (код 1); нет `arm-statements` рядом или подходящего Python — предупреждение, снимок делается. Нет
|
||||
`api/arm_statements/` — проверка молча пропускается.
|
||||
1. `git archive <ref>` → `/tmp/contour/<repo>/` — дерево коммита без `.git` и без игнорируемых файлов.
|
||||
2. Удаляет `.claude/`, `.codegraph/`, `CLAUDE.md`, `openspec/config.yaml`, `docs/superpowers/` на любой глубине (в т.ч.
|
||||
`web/` arm-core; опустевший `docs/` тоже), `Dockerfile` и `.dockerignore` — в корне.
|
||||
@ -88,7 +92,8 @@ docs/scripts/prepare-contour-snapshot.sh scan-gateway /tmp/contour
|
||||
`.env.test`, `contracts/`). Любая проблема — код возврата 1 и список.
|
||||
|
||||
Тест скрипта — `make test-snapshot` (синтетический репозиторий с артефактами агента в корне и в `web/`); проверка
|
||||
отставания `web/` и остановка переноса — в `make test-sync-web`.
|
||||
отставания `web/` и остановка переноса — в `make test-sync-web`; проверка копии `arm_statements` (пропуск, отставание, правка)
|
||||
— там же, в `make test-snapshot` (нужен Python ≥ 3.11 с PyYAML, `make venv`).
|
||||
|
||||
### 3.1. Синхронизация `arm-core/web` с `arm-web`: `scripts/sync-web.sh`
|
||||
|
||||
|
||||
@ -17,6 +17,10 @@
|
||||
# issue. Без терминала вопрос не задаётся: нужен флаг --web-as-is, иначе код 3. Расхождение (прямые правки web/ в arm-core) —
|
||||
# всегда стоп. arm-web ищется рядом с репозиторием (../arm-web) или в $ARM_WEB; если его нет — предупреждение, снимок делается.
|
||||
# $SYNC_WEB_ARGS — дополнительные аргументы sync-web.sh (для теста: --dry-run --wt-root …).
|
||||
# Для каждого сервиса, где в $REF есть api/arm_statements, проверяется свежесть копии пакета (sync-statements.sh --check
|
||||
# по дереву $REF; Р-42): отставание — предупреждение и абзац в SNAPSHOT.md, прямая правка копии — стоп (код 1), нет
|
||||
# arm-statements или Python — предупреждение. Нет api/arm_statements — проверка пропускается. $SYNC_STATEMENTS_ARGS —
|
||||
# дополнительные аргументы sync-statements.sh (для теста: --source … --docs …).
|
||||
# $SNAPSHOT_SKIP_WEB_BUILD=1 — не проверять сборку web/ (для тестов без сети); по умолчанию проверка включена.
|
||||
#
|
||||
# Встроенный фронт arm-core в контуре только собирается (npm install через Nexus + rsbuild build), а зеркало npm банка не
|
||||
@ -85,7 +89,38 @@ if [ "$NAME" = arm-core ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 0a. Копия пакета arm_statements в api/arm_statements не должна отставать от arm-statements ---------------------------
|
||||
# Проверяется дерево $REF хоста (git archive api → временный каталог), не рабочее. Нет api/arm_statements в $REF — пакет в
|
||||
# хост ещё не подключён, проверка молча пропускается. Коды sync-statements.sh --check: 0 — тихо; 10 — предупреждение в
|
||||
# stderr и абзац в SNAPSHOT.md; 20 — прямая правка/чужая версия копии, снимок не делается; 2 (нет arm-statements или
|
||||
# интерпретатора) — предупреждение, снимок делается.
|
||||
git -C "$REPO" fetch -q origin
|
||||
STATEMENTS_LAG=""
|
||||
if git -C "$REPO" rev-parse -q --verify "$REF:api/arm_statements" >/dev/null 2>&1; then
|
||||
SYNC_STATEMENTS="$(cd "$(dirname "$0")" && pwd)/sync-statements.sh"
|
||||
STM_TMP=$(mktemp -d)
|
||||
git -C "$REPO" archive "$REF" api | tar -x -C "$STM_TMP"
|
||||
rc=0
|
||||
# shellcheck disable=SC2086
|
||||
stm_out=$("$SYNC_STATEMENTS" --check --host "$NAME" --host-dir "$STM_TMP" ${SYNC_STATEMENTS_ARGS:-} 2>&1) || rc=$?
|
||||
rm -rf "$STM_TMP"
|
||||
case "$rc" in
|
||||
0) ;;
|
||||
10)
|
||||
echo "предупреждение: копия arm_statements в $NAME отстаёт от arm-statements или требует внимания:" >&2
|
||||
echo "$stm_out" >&2
|
||||
STATEMENTS_LAG=$(printf '%s\n' "$stm_out" | grep '^statements-check' | tail -n 1)
|
||||
[ -n "$STATEMENTS_LAG" ] || STATEMENTS_LAG="sync-statements.sh --check вернул 10" ;;
|
||||
20) echo "$stm_out" >&2
|
||||
echo "ошибка: копия arm_statements в $NAME расходится с arm-statements (прямые правки или чужая версия) — снимок не делается, разберитесь вручную" >&2
|
||||
exit 1 ;;
|
||||
2) echo "предупреждение: копия arm_statements в $NAME не проверена (sync-statements.sh --check: нет arm-statements рядом или подходящего Python):" >&2
|
||||
echo "$stm_out" >&2 ;;
|
||||
*) echo "$stm_out" >&2
|
||||
echo "ошибка: sync-statements.sh --check завершился с кодом $rc" >&2; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
HASH=$(git -C "$REPO" rev-parse "$REF")
|
||||
DATE=$(git -C "$REPO" show -s --format=%cs "$REF")
|
||||
SUBJECT=$(git -C "$REPO" show -s --format=%s "$REF")
|
||||
@ -258,6 +293,9 @@ if [ -n "$WEB_REMOVED" ]; then
|
||||
printf '\nЦель `make web-check` — `npm install` и `npm run build`. `web/package.json` из контура обратно не переносить: он урезан.\n'
|
||||
} >> "$DEST/SNAPSHOT.md"
|
||||
fi
|
||||
if [ -n "$STATEMENTS_LAG" ]; then
|
||||
printf '\nКопия пакета arm_statements (`api/arm_statements/`) на момент снимка требует внимания: %s\n' "$STATEMENTS_LAG" >> "$DEST/SNAPSHOT.md"
|
||||
fi
|
||||
if [ -n "$WEB_LAG" ]; then
|
||||
printf '\nВстроенный фронт \`web/\` на момент снимка %s.\n' "$WEB_LAG" >> "$DEST/SNAPSHOT.md"
|
||||
fi
|
||||
|
||||
@ -152,3 +152,81 @@ PATH="$STUB:$PATH" "$SCRIPT" "$T" "$WORK/out-tp" origin/main >/dev/null
|
||||
[ ! -s "$NPM_STUB_LOG" ] || { echo "FAIL: для tabular-parser вызван npm" >&2; fail=1; }
|
||||
[ "$fail" = 0 ] || exit 1
|
||||
echo "ok: проверка сборки web/ — выдаёт снимок без node_modules/dist, при падении снимка нет, у сервисов без фронта не вызывается"
|
||||
|
||||
# --- копия arm_statements в сервисе: sync-statements.sh --check (Р-42) -------------------------------------------------
|
||||
# Синтетический arm-statements и хосты; флаги sync-statements.sh — через SYNC_STATEMENTS_ARGS (реальные репозитории не нужны).
|
||||
PY=${STATEMENTS_PY:-python3}
|
||||
if ! "$PY" -c 'import tomllib, yaml' 2>/dev/null; then
|
||||
echo "нужен Python >= 3.11 с PyYAML: выполните make venv (или задайте STATEMENTS_PY)" >&2
|
||||
exit 1
|
||||
fi
|
||||
export STATEMENTS_PY="$PY"
|
||||
export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t
|
||||
SS="$WORK/arm-statements"
|
||||
git init -q --bare "$WORK/arm-statements.git"
|
||||
git clone -q "$WORK/arm-statements.git" "$SS" 2>/dev/null
|
||||
git -C "$SS" checkout -q -b main
|
||||
printf '[project]\nname = "arm-statements"\ndependencies = ["PyYAML==6.0.3"]\n' > "$SS/pyproject.toml"
|
||||
mkdir -p "$SS/arm_statements"
|
||||
echo "# init" > "$SS/arm_statements/__init__.py"
|
||||
echo "пакет" > "$SS/README.md"
|
||||
mkdir -p "$SS/arm_statements/rules"
|
||||
printf 'version: 1\nrepeats: {}\neditions:\n 66n:\n BALANCE: {full: ["1110", "1100"], simplified: ["1100"]}\n' \
|
||||
> "$SS/arm_statements/rules/statement_code_orders.yaml"
|
||||
git -C "$SS" add -A; git -C "$SS" commit -qm S1; git -C "$SS" push -q origin HEAD:main 2>/dev/null; git -C "$SS" fetch -q origin
|
||||
S1=$(git -C "$SS" rev-parse HEAD)
|
||||
mkdir -p "$WORK/docs-x/contracts"
|
||||
cp "$SS/arm_statements/rules/statement_code_orders.yaml" "$WORK/docs-x/contracts/statement-code-orders.yaml"
|
||||
export SYNC_STATEMENTS_ARGS="--source $SS --docs $WORK/docs-x"
|
||||
|
||||
# mk_service <имя>: сервис с копией пакета на S1 в api/arm_statements (после коммита — origin/main)
|
||||
mk_service() {
|
||||
local name=$1 d="$WORK/src/$1"
|
||||
git init -q --bare "$WORK/$name-o.git"
|
||||
git clone -q "$WORK/$name-o.git" "$d" 2>/dev/null
|
||||
printf 'venv:\n\tuv venv api/.venv\n' > "$d/Makefile"
|
||||
for p in raisa_config.yml setup/setup.sh setup/pip.conf api/run_server.py api/.env.test api/contracts/s.json; do
|
||||
mkdir -p "$(dirname "$d/$p")"; echo x > "$d/$p"
|
||||
done
|
||||
printf 'aiohttp==3.14.3\nPyYAML==6.0.3\n' > "$d/api/requirements.txt"
|
||||
git -C "$SS" archive "$S1" arm_statements | tar -x -C "$d/api"
|
||||
echo "$S1" > "$d/api/arm_statements/VERSION"
|
||||
git -C "$d" add -A; git -C "$d" commit -qm init; git -C "$d" push -q origin HEAD:main 2>/dev/null; git -C "$d" fetch -q origin
|
||||
}
|
||||
|
||||
# хост без api/arm_statements (tabular-parser выше): проверка пропущена молча
|
||||
: > "$WORK/tp.err"
|
||||
"$SCRIPT" "$T" "$WORK/out-tp2" origin/main >/dev/null 2>"$WORK/tp.err"
|
||||
[ ! -s "$WORK/tp.err" ] && ! grep -q arm_statements "$WORK/out-tp2/tabular-parser/SNAPSHOT.md" \
|
||||
|| { echo "FAIL: хост без arm_statements: проверка не пропущена молча" >&2; fail=1; }
|
||||
|
||||
# копия на актуальной версии: тихо, абзаца нет
|
||||
mk_service scan-gateway
|
||||
G="$WORK/src/scan-gateway"
|
||||
"$SCRIPT" "$G" "$WORK/out-g1" origin/main >/dev/null 2>"$WORK/g1.err"
|
||||
[ ! -s "$WORK/g1.err" ] && ! grep -q arm_statements "$WORK/out-g1/scan-gateway/SNAPSHOT.md" \
|
||||
|| { echo "FAIL: актуальная копия: ожидалась тишина и SNAPSHOT.md без абзаца" >&2; cat "$WORK/g1.err" >&2; fail=1; }
|
||||
|
||||
# нет источника (код 2): предупреждение, снимок делается
|
||||
rc=0
|
||||
SYNC_STATEMENTS_ARGS="--source $WORK/nope --docs $WORK/docs-x" "$SCRIPT" "$G" "$WORK/out-g2" origin/main >/dev/null 2>"$WORK/g2.err" || rc=$?
|
||||
[ "$rc" = 0 ] && [ -e "$WORK/out-g2/scan-gateway/SNAPSHOT.md" ] && grep -q "arm_statements" "$WORK/g2.err" \
|
||||
|| { echo "FAIL: нет источника: ожидалось предупреждение и снимок (rc=$rc)" >&2; fail=1; }
|
||||
|
||||
# копия отстала (код 10): предупреждение в stderr и абзац в SNAPSHOT.md, снимок делается
|
||||
echo "пакет, правка" > "$SS/README.md"
|
||||
git -C "$SS" add -A; git -C "$SS" commit -qm S2; git -C "$SS" push -q origin HEAD:main 2>/dev/null; git -C "$SS" fetch -q origin
|
||||
rc=0
|
||||
"$SCRIPT" "$G" "$WORK/out-g3" origin/main >/dev/null 2>"$WORK/g3.err" || rc=$?
|
||||
[ "$rc" = 0 ] && grep -q "arm_statements" "$WORK/g3.err" && grep -q "Копия пакета arm_statements" "$WORK/out-g3/scan-gateway/SNAPSHOT.md" \
|
||||
|| { echo "FAIL: копия отстала: ожидались предупреждение и абзац в SNAPSHOT.md (rc=$rc)" >&2; cat "$WORK/g3.err" >&2; fail=1; }
|
||||
|
||||
# прямая правка копии (код 20): код 1, снимка нет
|
||||
echo "# правка" >> "$G/api/arm_statements/__init__.py"
|
||||
git -C "$G" add -A; git -C "$G" commit -qm "direct edit"; git -C "$G" push -q origin HEAD:main 2>/dev/null; git -C "$G" fetch -q origin
|
||||
rc=0
|
||||
"$SCRIPT" "$G" "$WORK/out-g4" origin/main >/dev/null 2>"$WORK/g4.err" || rc=$?
|
||||
[ "$rc" = 1 ] && [ ! -e "$WORK/out-g4/scan-gateway" ] && grep -q "arm_statements" "$WORK/g4.err" \
|
||||
|| { echo "FAIL: прямая правка копии: ожидался код 1 без снимка (rc=$rc)" >&2; cat "$WORK/g4.err" >&2; fail=1; }
|
||||
[ "$fail" = 0 ] || exit 1
|
||||
echo "ok: копия arm_statements — пропуск без пакета, тишина при актуальной, предупреждение при отставании, стоп при правке"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user