377 lines
24 KiB
Bash
Executable File
377 lines
24 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Тест sync-statements.sh на синтетических репозиториях (bare origin + клон), без tea и сети.
|
||
# Разделы: помощник statements_check.py; дальше — сценарии самого скрипта (дописываются по задачам плана).
|
||
# Запуск: make test-sync-statements (или напрямую из корня docs; интерпретатор — STATEMENTS_PY, по умолчанию python3).
|
||
set -euo pipefail
|
||
|
||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||
PY=${STATEMENTS_PY:-python3}
|
||
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
|
||
|
||
if ! "$PY" -c 'import tomllib, yaml' 2>/dev/null; then
|
||
echo "нужен Python >= 3.11 с PyYAML: выполните make venv (или задайте STATEMENTS_PY)" >&2
|
||
exit 1
|
||
fi
|
||
|
||
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"; }
|
||
# shellcheck disable=SC2317
|
||
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; }
|
||
|
||
# --- помощник statements_check.py ---------------------------------------------------------------------------------
|
||
H="$WORK/h"; mkdir -p "$H"
|
||
CHK="$HERE/statements_check.py"
|
||
# run <rc-ожидаемый> <описание> <аргументы…>: вывод — в $OUT
|
||
run() {
|
||
local want=$1 desc=$2 rc=0; shift 2
|
||
OUT=$("$PY" "$CHK" "$@" 2>&1) || rc=$?
|
||
check "$([ "$rc" = "$want" ] && echo 0 || echo 1)" "$desc (rc=$rc, ожидался $want)"
|
||
}
|
||
has() { grep -q -- "$1" <<<"$OUT"; }
|
||
|
||
put "$H/pp.toml" $'[project]\ndependencies = ["PyYAML==6.0.3"]'
|
||
put "$H/r1.txt" $'aiohttp==3.14.3\nPyYAML==6.0.3'
|
||
run 0 "deps: есть" deps "$H/pp.toml" "$H/r1.txt"
|
||
check "$([ -z "$OUT" ] && echo 0 || echo 1)" "deps: есть — вывод пустой"
|
||
put "$H/r2.txt" $'aiohttp==3.14.3\npyyaml==6.0.3'
|
||
run 0 "deps: регистр" deps "$H/pp.toml" "$H/r2.txt"
|
||
put "$H/pp_u.toml" $'[project]\ndependencies = ["Py_YAML==6.0.3"]'
|
||
put "$H/r2u.txt" $'py-yaml==6.0.3'
|
||
run 0 "deps: подчёркивание и дефис равны" deps "$H/pp_u.toml" "$H/r2u.txt"
|
||
put "$H/r3.txt" $'aiohttp==3.14.3\n# PyYAML==6.0.3\n-r other.txt'
|
||
run 20 "deps: нет" deps "$H/pp.toml" "$H/r3.txt"
|
||
check "$(has PyYAML && echo 0 || echo 1)" "deps: нет — в выводе PyYAML"
|
||
put "$H/r4.txt" $'PyYAML==6.0.4'
|
||
run 0 "deps: другая версия" deps "$H/pp.toml" "$H/r4.txt"
|
||
check "$(has 'примечание:' && has 6.0.4 && echo 0 || echo 1)" "deps: другая версия — примечание с 6.0.4"
|
||
put "$H/pp_none.toml" $'[tool.ruff]\nline-length = 120'
|
||
run 0 "deps: без [project]" deps "$H/pp_none.toml" "$H/r1.txt"
|
||
put "$H/pp_jwt.toml" $'[project]\ndependencies = ["PyJWT==2.8.0"]'
|
||
put "$H/r5.txt" $'PyJWT[crypto]==2.8.0'
|
||
run 0 "deps: экстры хоста" deps "$H/pp_jwt.toml" "$H/r5.txt"
|
||
|
||
put "$H/orders.yaml" 'version: 1
|
||
repeats: {}
|
||
editions:
|
||
66n:
|
||
BALANCE: {full: ["1110", "1100"], simplified: ["1100"]}
|
||
INCOME: {full: ["2110"], simplified: ["2110"]}
|
||
fsbu4:
|
||
BALANCE: {full: ["1110", "1100"], simplified: ["1100"]}
|
||
INCOME: {full: ["2110"], simplified: ["2110"]}'
|
||
put "$H/lines.yaml" 'editions:
|
||
- id: 66n
|
||
forms:
|
||
BALANCE:
|
||
- {code: "1110", name: "Основные средства"}
|
||
- {code: "1100", name: "Итого"}
|
||
- id: fsbu4
|
||
forms:
|
||
BALANCE:
|
||
- {code: "1110", name: "Основные средства"}'
|
||
run 0 "lines: все коды есть" lines "$H/lines.yaml" "$H/orders.yaml"
|
||
put "$H/lines_x.yaml" 'editions:
|
||
- id: 66n
|
||
forms:
|
||
BALANCE:
|
||
- {code: "1110", name: "а"}
|
||
- id: fsbu4
|
||
forms:
|
||
BALANCE:
|
||
- {code: "1110", name: "а"}
|
||
- {code: "1120", name: "б"}'
|
||
run 20 "lines: код вне перечня" lines "$H/lines_x.yaml" "$H/orders.yaml"
|
||
check "$(has 1120 && has fsbu4 && echo 0 || echo 1)" "lines: код вне перечня — в выводе 1120 и fsbu4"
|
||
put "$H/orders_s.yaml" 'version: 1
|
||
editions:
|
||
fsbu4:
|
||
BALANCE: {full: ["1110"], simplified: ["1100"]}'
|
||
put "$H/lines_s.yaml" 'editions:
|
||
- id: fsbu4
|
||
forms:
|
||
BALANCE:
|
||
- {code: "1100", name: "а"}'
|
||
run 0 "lines: код только в simplified" lines "$H/lines_s.yaml" "$H/orders_s.yaml"
|
||
put "$H/bad.yaml" 'editions: ['
|
||
run 1 "битый YAML" lines "$H/bad.yaml" "$H/orders.yaml"
|
||
run 2 "аргументы"
|
||
|
||
# --- sync-statements.sh --check -----------------------------------------------------------------------------------
|
||
SYNC="$HERE/sync-statements.sh"
|
||
export STATEMENTS_PY="$PY"
|
||
SRC="$WORK/arm-statements"
|
||
git init -q --bare "$WORK/arm-statements.git"
|
||
git clone -q "$WORK/arm-statements.git" "$SRC" 2>/dev/null
|
||
git -C "$SRC" checkout -q -b main
|
||
put "$SRC/pyproject.toml" $'[project]\nname = "arm-statements"\ndependencies = ["PyYAML==6.0.3"]'
|
||
put "$SRC/README.md" "пакет"
|
||
put "$SRC/arm_statements/__init__.py" "# init"
|
||
put "$SRC/arm_statements/steps.py" "def step(): return 1"
|
||
mkdir -p "$SRC/arm_statements/rules"; cp "$H/orders.yaml" "$SRC/arm_statements/rules/statement_code_orders.yaml"
|
||
put "$SRC/arm_statements/tests/__init__.py" "# t"
|
||
put "$SRC/arm_statements/tests/test_steps.py" "def test_step(): pass"
|
||
commit_push "$SRC" "S1" main
|
||
S1=$(git -C "$SRC" rev-parse HEAD)
|
||
mkdir -p "$WORK/docs/contracts" "$WORK/docs-empty" "$WORK/wt"
|
||
cp "$H/orders.yaml" "$WORK/docs/contracts/statement-code-orders.yaml"
|
||
|
||
# make_host <каталог> <имя origin>: bare + клон с копией S1 в api/arm_statements, requirements и (для arm-core) словарём
|
||
make_host() {
|
||
local dir=$1 name=$2
|
||
git init -q --bare "$WORK/$name.git"
|
||
git clone -q "$WORK/$name.git" "$dir" 2>/dev/null
|
||
git -C "$dir" checkout -q -b main
|
||
put "$dir/api/requirements.txt" $'aiohttp==3.14.3\nPyYAML==6.0.3'
|
||
mkdir -p "$dir/api"
|
||
git -C "$SRC" archive "$S1" arm_statements | tar -x -C "$dir/api"
|
||
printf '%s\n' "$S1" > "$dir/api/arm_statements/VERSION"
|
||
}
|
||
make_host "$WORK/arm-core" arm-core
|
||
mkdir -p "$WORK/arm-core/api/rules"; cp "$H/lines.yaml" "$WORK/arm-core/api/rules/statement_lines.yaml"
|
||
commit_push "$WORK/arm-core" "copy S1" main
|
||
make_host "$WORK/tabular-parser" arm-tabular-parser
|
||
commit_push "$WORK/tabular-parser" "copy S1" main
|
||
make_host "$WORK/scan-gateway" arm-scan-gateway
|
||
mkdir -p "$WORK/scan-gateway/api/rules"
|
||
put "$WORK/scan-gateway/api/rules/statement_lines.yaml" $'editions:\n - id: fsbu4\n forms:\n BALANCE:\n - {code: "9999", name: "х"}'
|
||
commit_push "$WORK/scan-gateway" "copy S1" main
|
||
COMMON=(--source "$WORK/arm-statements" --docs "$WORK/docs" --wt-root "$WORK/wt" --core-dir "$WORK/arm-core")
|
||
AC="$WORK/arm-core/api"
|
||
reset_hosts() { local h; for h in arm-core tabular-parser scan-gateway; do git -C "$WORK/$h" checkout -q -- . && git -C "$WORK/$h" clean -fdq; done; }
|
||
# sync <rc> <описание> <аргументы…>: вывод — в $OUT
|
||
sync() {
|
||
local want=$1 desc=$2 rc=0; shift 2
|
||
OUT=$("$SYNC" "${COMMON[@]}" "$@" 2>&1) || rc=$?
|
||
check "$([ "$rc" = "$want" ] && echo 0 || echo 1)" "$desc (rc=$rc, ожидался $want)"
|
||
}
|
||
|
||
sync 0 "check: синхронно" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'statements-check arm-core: 0' && echo 0 || echo 1)" "check: синхронно — итоговая строка"
|
||
sync 0 "check: имя по origin, словарь не у scan-gateway" --check --host-dir "$WORK/scan-gateway"
|
||
check "$(has 'scan-gateway' && ! has 9999 && echo 0 || echo 1)" "check: scan-gateway — в выводе имя, нет 9999"
|
||
OUT=$(cd "$WORK/tabular-parser" && "$SYNC" --check --host-dir . "${COMMON[@]}" 2>&1) && rc=0 || rc=$?
|
||
check "$([ "$rc" = 0 ] && has 'statements-check tabular-parser: 0' && echo 0 || echo 1)" "check: --host-dir . из каталога хоста (rc=$rc)"
|
||
sync 0 "check: --host вместо origin" --check --host scan-gateway --host-dir "$WORK/scan-gateway"
|
||
sync 2 "check: неизвестное имя --host" --check --host foo --host-dir "$WORK/arm-core"
|
||
|
||
TP="$WORK/tabular-parser/api/arm_statements"
|
||
mkdir -p "$TP/__pycache__" "$TP/tests/.pytest_cache" "$TP/.mypy_cache"
|
||
: > "$TP/__pycache__/steps.cpython-311.pyc"; : > "$TP/tests/.pytest_cache/x"; : > "$TP/.mypy_cache/x"; : > "$TP/.DS_Store"
|
||
sync 0 "check: кэши в копии игнорируются" --check --host-dir "$WORK/tabular-parser"
|
||
reset_hosts
|
||
|
||
echo "# правка" >> "$AC/arm_statements/steps.py"
|
||
sync 20 "check: изменён файл" --check --host-dir "$WORK/arm-core"
|
||
check "$(has steps.py && has 'прямая правка' && echo 0 || echo 1)" "check: изменён файл — steps.py и «прямая правка»"
|
||
reset_hosts
|
||
put "$AC/arm_statements/extra.py" "x = 1"
|
||
sync 20 "check: добавлен файл" --check --host-dir "$WORK/arm-core"
|
||
check "$(has extra.py && echo 0 || echo 1)" "check: добавлен файл — extra.py"
|
||
reset_hosts
|
||
rm "$AC/arm_statements/tests/test_steps.py"
|
||
sync 20 "check: удалён файл" --check --host-dir "$WORK/arm-core"
|
||
check "$(has test_steps.py && echo 0 || echo 1)" "check: удалён файл — test_steps.py"
|
||
reset_hosts
|
||
rm "$AC/arm_statements/VERSION"
|
||
sync 20 "check: нет VERSION" --check --host-dir "$WORK/arm-core"
|
||
reset_hosts
|
||
printf '%s\n' 0000000000000000000000000000000000000000 > "$AC/arm_statements/VERSION"
|
||
sync 20 "check: неизвестный VERSION" --check --host-dir "$WORK/arm-core"
|
||
reset_hosts
|
||
rm -rf "$AC/arm_statements"
|
||
sync 20 "check: нет копии" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'копии нет' && echo 0 || echo 1)" "check: нет копии — сообщение"
|
||
reset_hosts
|
||
|
||
git -C "$SRC" checkout -q -b feat/x
|
||
echo "# F" >> "$SRC/arm_statements/steps.py"
|
||
commit_push "$SRC" "F" feat/x
|
||
F=$(git -C "$SRC" rev-parse HEAD)
|
||
git -C "$SRC" checkout -q main
|
||
git -C "$SRC" archive "$F" arm_statements | tar -x -C "$AC"
|
||
printf '%s\n' "$F" > "$AC/arm_statements/VERSION"
|
||
sync 20 "check: чужая версия" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'чужая версия' && echo 0 || echo 1)" "check: чужая версия — сообщение"
|
||
reset_hosts
|
||
|
||
put "$AC/requirements.txt" "aiohttp==3.14.3"
|
||
sync 20 "check: нет зависимости" --check --host-dir "$WORK/arm-core"
|
||
check "$(has PyYAML && echo 0 || echo 1)" "check: нет зависимости — PyYAML"
|
||
reset_hosts
|
||
cp "$H/lines_x.yaml" "$AC/rules/statement_lines.yaml"
|
||
sync 20 "check: код словаря вне перечня" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 1120 && has fsbu4 && echo 0 || echo 1)" "check: код вне перечня — 1120 и fsbu4"
|
||
reset_hosts
|
||
|
||
rm "$AC/arm_statements/rules/statement_code_orders.yaml"
|
||
sync 20 "check: нет statement_code_orders.yaml в копии" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'statements-check arm-core: 20' && has 'rules/statement_code_orders.yaml' && echo 0 || echo 1)" "check: нет перечня в копии — находка и итоговая строка"
|
||
reset_hosts
|
||
rm "$AC/requirements.txt"
|
||
sync 20 "check: нет requirements.txt" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'statements-check arm-core: 20' && has 'requirements' && echo 0 || echo 1)" "check: нет requirements — находка и итоговая строка"
|
||
reset_hosts
|
||
|
||
echo "# новый код" >> "$WORK/docs/contracts/statement-code-orders.yaml"
|
||
sync 10 "check: перечень в docs новее" --check --host-dir "$WORK/arm-core"
|
||
check "$(has contracts/statement-code-orders.yaml && has 'statements-check arm-core: 10' && echo 0 || echo 1)" "check: перечень в docs — в выводе файл и итог 10"
|
||
cp "$H/orders.yaml" "$WORK/docs/contracts/statement-code-orders.yaml"
|
||
sync 10 "check: перечня нет в docs" --check --host-dir "$WORK/arm-core" --docs "$WORK/docs-empty"
|
||
|
||
sync 2 "check: нет источника" --check --host-dir "$WORK/arm-core" --source "$WORK/nope"
|
||
sync 2 "check: нет хоста" --check --host-dir "$WORK/nope"
|
||
sync 2 "check: неизвестный аргумент" --check --bogus
|
||
sync 2 "check: нет --host/--host-dir" --check
|
||
sync 2 "check: --ref не разрешается" --check --host-dir "$WORK/arm-core" --ref origin/nope
|
||
sync 2 "--in-place вместе с --dry-run" --in-place --dry-run --host-dir "$WORK/arm-core"
|
||
sync 0 "check важнее --dry-run и --in-place" --in-place --dry-run --check --host-dir "$WORK/arm-core"
|
||
|
||
# проверки с S2 — последними
|
||
put "$SRC/README.md" "пакет, правка"
|
||
commit_push "$SRC" "S2 правка README" main
|
||
sync 10 "check: отстала" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'копия отстала' && has 'S2 правка README' && echo 0 || echo 1)" "check: отстала — сообщение и тема S2"
|
||
echo "# правка" >> "$AC/arm_statements/steps.py"
|
||
sync 20 "check: правка + отставание = 20" --check --host-dir "$WORK/arm-core"
|
||
reset_hosts
|
||
|
||
# коммит без arm_statements/ (T2.1): код 20 с итоговой строкой, а не 128
|
||
NOARCH=$(git -C "$SRC" commit-tree "$(git -C "$SRC" hash-object -t tree /dev/null)" -m "без пакета")
|
||
printf '%s\n' "$NOARCH" > "$AC/arm_statements/VERSION"
|
||
sync 20 "check: в коммите VERSION нет arm_statements/" --check --host-dir "$WORK/arm-core"
|
||
check "$(has 'нет arm_statements/' && has 'statements-check arm-core: 20' && echo 0 || echo 1)" "check: нет arm_statements/ — сообщение и итог"
|
||
reset_hosts
|
||
|
||
# --- sync-statements.sh --in-place --------------------------------------------------------------------------------
|
||
S2=$(git -C "$SRC" rev-parse origin/main)
|
||
FR="$WORK/fresh/tabular-parser"
|
||
mkdir -p "$WORK/fresh"
|
||
git init -q --bare "$WORK/fresh/arm-tabular-parser.git"
|
||
git clone -q "$WORK/fresh/arm-tabular-parser.git" "$FR" 2>/dev/null
|
||
git -C "$FR" checkout -q -b main
|
||
put "$FR/api/requirements.txt" $'PyYAML==6.0.3'
|
||
commit_push "$FR" "fresh" main
|
||
|
||
# хосты — на ветку задачи: --in-place отвергает main/master
|
||
for h in arm-core tabular-parser scan-gateway; do git -C "$WORK/$h" checkout -q -b work; done
|
||
git -C "$FR" checkout -q -b work
|
||
sync 2 "in-place: --host без --host-dir" --in-place --host tabular-parser
|
||
check "$(has -- '--host-dir' && echo 0 || echo 1)" "in-place: --host без --host-dir — сообщение"
|
||
git -C "$WORK/scan-gateway" checkout -q main
|
||
sync 2 "in-place: ветка main хоста" --in-place --host-dir "$WORK/scan-gateway"
|
||
check "$(has main && [ "$(tr -d '\n' < "$WORK/scan-gateway/api/arm_statements/VERSION")" = "$S1" ] && echo 0 || echo 1)" "in-place: main — копия не тронута"
|
||
git -C "$WORK/scan-gateway" checkout -q work
|
||
|
||
sync 0 "in-place: первичная раскладка" --in-place --host-dir "$FR" --ref origin/main
|
||
check "$([ "$(tr -d '\n' < "$FR/api/arm_statements/VERSION")" = "$S2" ] && echo 0 || echo 1)" "in-place: VERSION = полный хэш S2"
|
||
rm -rf "$WORK/arc"; mkdir -p "$WORK/arc"; git -C "$SRC" archive "$S2" arm_statements | tar -x -C "$WORK/arc"
|
||
check "$(diff -r -x VERSION "$WORK/arc/arm_statements" "$FR/api/arm_statements" >/dev/null && echo 0 || echo 1)" "in-place: копия равна git archive S2"
|
||
check "$(git -C "$FR" status --porcelain | grep -qv '^?? api/arm_statements' && echo 1 || echo 0)" "in-place: хост менялся только в api/arm_statements"
|
||
check "$(has закоммитьте && echo 0 || echo 1)" "in-place: подсказка про коммит"
|
||
sync 0 "in-place: повтор" --in-place --host-dir "$FR" --ref origin/main
|
||
check "$(has 'раскладывать нечего' && echo 0 || echo 1)" "in-place: повтор — раскладывать нечего"
|
||
|
||
sync 0 "in-place: обновление arm-core S1 -> S2" --in-place --host-dir "$WORK/arm-core"
|
||
check "$([ "$(tr -d '\n' < "$AC/arm_statements/VERSION")" = "$S2" ] && echo 0 || echo 1)" "in-place: arm-core VERSION = S2"
|
||
echo "# правка" >> "$AC/arm_statements/steps.py"
|
||
sync 20 "in-place: отказ при правке" --in-place --host-dir "$WORK/arm-core" --ref origin/main
|
||
check "$(grep -q '^# правка' "$AC/arm_statements/steps.py" && [ "$(tr -d '\n' < "$AC/arm_statements/VERSION")" = "$S2" ] && echo 0 || echo 1)" "in-place: правка на месте, VERSION прежний"
|
||
reset_hosts
|
||
|
||
TPR="$WORK/tabular-parser/api"
|
||
put "$TPR/requirements.txt" "aiohttp==3.14.3"
|
||
sync 20 "in-place: отказ без зависимости (обновление)" --in-place --host-dir "$WORK/tabular-parser"
|
||
check "$([ "$(tr -d '\n' < "$TPR/arm_statements/VERSION")" = "$S1" ] && has PyYAML && echo 0 || echo 1)" "in-place: копия не тронута, в выводе PyYAML"
|
||
reset_hosts
|
||
cp "$FR/api/requirements.txt" "$WORK/req.bak"
|
||
put "$FR/api/requirements.txt" "aiohttp==3.14.3"
|
||
sync 20 "in-place: отказ без зависимости (fresh)" --in-place --host-dir "$FR" --ref origin/main
|
||
check "$([ "$(tr -d '\n' < "$FR/api/arm_statements/VERSION")" = "$S2" ] && diff -r -x VERSION "$WORK/arc/arm_statements" "$FR/api/arm_statements" >/dev/null && echo 0 || echo 1)" "in-place: fresh — api/arm_statements не тронут"
|
||
cp "$WORK/req.bak" "$FR/api/requirements.txt"
|
||
cp "$H/lines_x.yaml" "$AC/rules/statement_lines.yaml"
|
||
sync 20 "in-place: код словаря вне перечня" --in-place --host-dir "$WORK/arm-core" --ref origin/main
|
||
check "$([ "$(tr -d '\n' < "$AC/arm_statements/VERSION")" = "$S1" ] && has 1120 && echo 0 || echo 1)" "in-place: словарь — копия не тронута, 1120 в выводе"
|
||
reset_hosts
|
||
|
||
# защиты: коммиты S3/S4 на ветке test-guards, чтобы origin/main (S2) остался прежним
|
||
git -C "$SRC" checkout -q -b test-guards
|
||
put "$SRC/arm_statements/tests/golden/case.json" '{}'
|
||
commit_push "$SRC" "S3 json" test-guards
|
||
put "$FR/.gitignore" '*.json'
|
||
sync 1 "in-place: .gitignore прячет файл" --in-place --host-dir "$FR" --ref origin/test-guards
|
||
check "$(has case.json && has .gitignore && echo 0 || echo 1)" "in-place: в выводе case.json и .gitignore"
|
||
sync 1 "in-place: повтор после защиты .gitignore остаётся 1" --in-place --host-dir "$FR" --ref origin/test-guards
|
||
check "$(has case.json && has .gitignore && echo 0 || echo 1)" "in-place: повтор — снова case.json и .gitignore"
|
||
rm "$FR/.gitignore"
|
||
echo "# /Users/someone" >> "$SRC/arm_statements/steps.py"
|
||
commit_push "$SRC" "S4 путь" test-guards
|
||
sync 1 "in-place: содержимое для контура" --in-place --host-dir "$FR" --ref origin/test-guards
|
||
check "$(has '/Users/' && echo 0 || echo 1)" "in-place: в выводе /Users/"
|
||
sync 1 "in-place: повтор после защиты путей остаётся 1" --in-place --host-dir "$FR" --ref origin/test-guards
|
||
check "$(has '/Users/' && echo 0 || echo 1)" "in-place: повтор — снова /Users/"
|
||
git -C "$SRC" checkout -q main
|
||
|
||
# --- sync-statements.sh --dry-run (обычный режим без issue и PR) --------------------------------------------------
|
||
S27=${S2:0:7}
|
||
git -C "$SRC" checkout -q main
|
||
rm_wt() { # rm_wt <хост-каталог> <имя хоста>: убрать worktree и ветку синхронизации
|
||
git -C "$1" worktree remove --force "$WORK/wt/statements-sync-$S27/$2" 2>/dev/null || true
|
||
git -C "$1" branch -D "tmp/statements-sync-$S27" >/dev/null 2>&1 || true
|
||
}
|
||
WTC="$WORK/wt/statements-sync-$S27/arm-core"
|
||
sync 0 "dry-run: arm-core" --dry-run --host-dir "$WORK/arm-core"
|
||
check "$([ -d "$WTC" ] && git -C "$WORK/arm-core" rev-parse -q --verify "tmp/statements-sync-$S27" >/dev/null && [ -f "$WTC/.bounded" ] && echo 0 || echo 1)" "dry-run: worktree, ветка и .bounded"
|
||
check "$([ "$(tr -d '\n' < "$WTC/api/arm_statements/VERSION")" = "$S2" ] && echo 0 || echo 1)" "dry-run: VERSION = S2"
|
||
rm -rf "$WORK/arc"; mkdir -p "$WORK/arc"; git -C "$SRC" archive "$S2" arm_statements | tar -x -C "$WORK/arc"
|
||
check "$(diff -r -x VERSION "$WORK/arc/arm_statements" "$WTC/api/arm_statements" >/dev/null && echo 0 || echo 1)" "dry-run: копия равна git archive S2"
|
||
check "$(has 'dry-run: issue, проверки, коммит и PR не выполнялись' && echo 0 || echo 1)" "dry-run: сообщение и команды удаления"
|
||
check "$([ -z "$(git -C "$WORK/arm-core" status --porcelain)" ] && [ "$(tr -d '\n' < "$AC/arm_statements/VERSION")" = "$S1" ] && echo 0 || echo 1)" "dry-run: хост не тронут"
|
||
sync 2 "dry-run: повтор" --dry-run --host-dir "$WORK/arm-core"
|
||
check "$(has 'уже существует' && echo 0 || echo 1)" "dry-run: повтор — уже существует"
|
||
rm_wt "$WORK/arm-core" arm-core
|
||
check "$([ ! -d "$WTC" ] && ! git -C "$WORK/arm-core" rev-parse -q --verify "tmp/statements-sync-$S27" >/dev/null && echo 0 || echo 1)" "dry-run: worktree и ветка удалены"
|
||
|
||
sync 0 "dry-run: сначала ядро" --dry-run --host-dir "$WORK/tabular-parser"
|
||
check "$(has 'сначала ядро' && echo 0 || echo 1)" "dry-run: предупреждение «сначала ядро»"
|
||
rm_wt "$WORK/tabular-parser" tabular-parser
|
||
|
||
# arm-core на S2 закоммичена и запушена -> раскладывать нечего
|
||
"$SYNC" "${COMMON[@]}" --in-place --host-dir "$WORK/arm-core" >/dev/null
|
||
commit_push "$WORK/arm-core" "copy S2" main
|
||
sync 0 "dry-run: уже синхронно" --dry-run --host-dir "$WORK/arm-core"
|
||
check "$(has 'раскладывать нечего' && [ ! -e "$WTC" ] && echo 0 || echo 1)" "dry-run: уже синхронно — worktree не создан"
|
||
|
||
# прямая правка на origin/main хоста -> отказ 20
|
||
echo "# прямая правка" >> "$WORK/tabular-parser/api/arm_statements/steps.py"
|
||
commit_push "$WORK/tabular-parser" "прямая правка" main
|
||
sync 20 "dry-run: прямая правка на origin/main" --dry-run --host-dir "$WORK/tabular-parser"
|
||
check "$(has steps.py && [ ! -e "$WORK/wt/statements-sync-$S27/tabular-parser" ] && echo 0 || echo 1)" "dry-run: отказ — steps.py, worktree не создан"
|
||
|
||
# хост без копии
|
||
sync 2 "dry-run: хост без копии" --dry-run --host-dir "$FR"
|
||
check "$(has -- '--in-place' && echo 0 || echo 1)" "dry-run: хост без копии — подсказка --in-place"
|
||
|
||
# tea: флаги только после подкоманды
|
||
check "$(grep -nE '(^|[^[:alnum:]_-])tea[[:space:]]+-' "$SYNC" >/dev/null && echo 1 || echo 0)" "tea: флаги после подкоманды"
|
||
|
||
# недостижимые прежде ветки: заглушки tea и make в PATH (обычный режим, scan-gateway: копия S1, ядро на S2)
|
||
STUB="$WORK/stub"; mkdir -p "$STUB"
|
||
printf '#!/bin/sh\nexit 0\n' > "$STUB/make"
|
||
printf '#!/bin/sh\nexit 1\n' > "$STUB/tea"
|
||
chmod +x "$STUB/make" "$STUB/tea"
|
||
OUT=$(PATH="$STUB:$PATH" "$SYNC" "${COMMON[@]}" --host-dir "$WORK/scan-gateway" 2>&1) && rc=0 || rc=$?
|
||
check "$([ "$rc" = 1 ] && has 'не удалось создать issue' && echo 0 || echo 1)" "tea упал на issue: сообщение и код 1 (rc=$rc)"
|
||
rm_wt "$WORK/scan-gateway" scan-gateway
|
||
printf '#!/bin/sh\nif [ "$1" = issues ]; then echo https://git.example/RSHB/arm-scan-gateway/issues/77; exit 0; fi\nexit 1\n' > "$STUB/tea"
|
||
OUT=$(PATH="$STUB:$PATH" "$SYNC" "${COMMON[@]}" --host-dir "$WORK/scan-gateway" 2>&1) && rc=0 || rc=$?
|
||
check "$([ "$rc" = 1 ] && has 'PR не создан' && has 'tea pulls create' && has 'feat/77-statements-sync' && echo 0 || echo 1)" "tea упал на PR: итог и ручная команда, код 1 (rc=$rc)"
|
||
rm_wt "$WORK/scan-gateway" scan-gateway
|
||
git -C "$WORK/scan-gateway" branch -D "feat/77-statements-sync-$S27" >/dev/null 2>&1 || true
|
||
|
||
[ "$fail" = 0 ] || exit 1
|
||
echo "ok: sync-statements.sh — все сценарии пройдены"
|