feat(scripts): sync-statements.sh — worktree хоста, issue, make check и PR; --dry-run; предупреждение «сначала ядро» (#120)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
97777cbd7a
commit
17c0fd20f9
@ -13,7 +13,9 @@
|
||||
# 20 — расхождение (прямая правка копии, чужая версия, нет копии, нет зависимости, код вне перечня)
|
||||
# --in-place разложить копию в рабочее дерево хоста (без git-операций); 1 — защиты (.gitignore хоста, пути для контура),
|
||||
# 20 — отказ (правка копии, чужая версия, нет зависимости, код вне перечня)
|
||||
# --dry-run worktree хоста без issue и PR (режим пока не реализован); вместе с --in-place — код 2
|
||||
# (без режима) worktree хоста от --host-ref, issue, make check хоста, коммит и PR; 20 — отказ до worktree, 2 — копии нет
|
||||
# на --host-ref или worktree уже есть, 0 — копия уже на --ref
|
||||
# --dry-run то же до раскладки включительно, без issue, проверок, коммита и PR (worktree остаётся); с --in-place — код 2
|
||||
# --host arm-core | tabular-parser | scan-gateway; по умолчанию — по origin хоста (arm-core, arm-tabular-parser,
|
||||
# arm-scan-gateway), иначе по имени каталога
|
||||
# --host-dir каталог хоста (корень репозитория)
|
||||
@ -59,7 +61,7 @@ while [ $# -gt 0 ]; do
|
||||
--docs) [ $# -ge 2 ] || die "--docs требует значение" 2; DOCS=$2; shift ;;
|
||||
--core-dir) [ $# -ge 2 ] || die "--core-dir требует значение" 2; CORE_DIR=$2; shift ;;
|
||||
--wt-root) [ $# -ge 2 ] || die "--wt-root требует значение" 2; WT_ROOT=$2; shift ;;
|
||||
-h|--help) sed -n "2,24p" "$0"; exit 0 ;;
|
||||
-h|--help) sed -n "2,26p" "$0"; exit 0 ;;
|
||||
*) die "неизвестный аргумент $1" 2 ;;
|
||||
esac
|
||||
shift
|
||||
@ -329,4 +331,179 @@ if [ "$MODE" = in-place ]; then
|
||||
exit "$EVAL_CODE"
|
||||
fi
|
||||
|
||||
die "режим не реализован" 1
|
||||
# --- обычный режим и --dry-run: worktree хоста, issue, проверки, PR ------------------------------------------------
|
||||
TARGET=$REF_SHA
|
||||
T7=${TARGET:0:7}
|
||||
case "$HOST_NAME" in
|
||||
arm-core) GITEA_REPO=RSHB/arm-core ;;
|
||||
tabular-parser) GITEA_REPO=RSHB/arm-tabular-parser ;;
|
||||
scan-gateway) GITEA_REPO=RSHB/arm-scan-gateway ;;
|
||||
esac
|
||||
|
||||
# 1. хост
|
||||
if ! git -C "$HOST_DIR" fetch -q origin 2>/dev/null; then
|
||||
echo "sync-statements: fetch хоста не удался, работаю с локальным $HOST_REF" >&2
|
||||
fi
|
||||
git -C "$HOST_DIR" rev-parse -q --verify "$HOST_REF^{commit}" >/dev/null || die "в хосте нет $HOST_REF" 2
|
||||
|
||||
# 2. состояние хоста на --host-ref
|
||||
git -C "$HOST_DIR" rev-parse -q --verify "$HOST_REF:api/arm_statements" >/dev/null 2>&1 \
|
||||
|| die "копии нет на $HOST_REF: подключение хоста — вручную, --in-place в worktree задачи подключения (docs/dev/checks.md)" 2
|
||||
HT="$TMPD/host-tree"; mkdir -p "$HT"
|
||||
git -C "$HOST_DIR" archive "$HOST_REF" api | tar -x -C "$HT"
|
||||
HLINES=""
|
||||
if [ "$HOST_NAME" = arm-core ] && [ -f "$HT/api/rules/statement_lines.yaml" ]; then HLINES="$HT/api/rules/statement_lines.yaml"; fi
|
||||
evaluate "$HT/api/arm_statements" "$HT/api/requirements.txt" "$HLINES" "$HOST_NAME"
|
||||
if [ "$EVAL_CODE" = 20 ]; then
|
||||
echo "statements-check $HOST_NAME: 20 — отказ: копия на $HOST_REF правлена, чужая или несовместима, worktree не создан"
|
||||
exit 20
|
||||
fi
|
||||
HOST_WARNS=$EVAL_WARNS
|
||||
OLD=$(tr -d ' \t\r\n' < "$HT/api/arm_statements/VERSION")
|
||||
OLD7=${OLD:0:7}
|
||||
|
||||
# 3. зависимости и словарь имён против TARGET
|
||||
refuse=""
|
||||
git -C "$SRC" show "$TARGET:pyproject.toml" > "$TMPD/ref-pyproject.toml" 2>/dev/null || : > "$TMPD/ref-pyproject.toml"
|
||||
helper deps "$TMPD/ref-pyproject.toml" "$HT/api/requirements.txt"
|
||||
if [ "$HELPER_RC" = 20 ]; then refuse=$HELPER_OUT; fi
|
||||
if [ -n "$HLINES" ]; then
|
||||
git -C "$SRC" show "$TARGET:arm_statements/rules/statement_code_orders.yaml" > "$TMPD/ref-orders.yaml" 2>/dev/null \
|
||||
|| : > "$TMPD/ref-orders.yaml"
|
||||
helper lines "$HLINES" "$TMPD/ref-orders.yaml"
|
||||
if [ "$HELPER_RC" = 20 ]; then refuse="${refuse:+$refuse
|
||||
}$HELPER_OUT"; fi
|
||||
fi
|
||||
if [ -n "$refuse" ]; then
|
||||
echo "$refuse"
|
||||
echo "statements-check $HOST_NAME: 20 — отказ: $REF несовместим с хостом, worktree не создан"
|
||||
exit 20
|
||||
fi
|
||||
|
||||
# 4. уже на TARGET
|
||||
if [ "$OLD" = "$TARGET" ]; then
|
||||
echo "копия уже на $T7, раскладывать нечего"
|
||||
[ -z "$HOST_WARNS" ] || echo "предупреждение: $HOST_WARNS"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 5. «сначала ядро»
|
||||
CORE_WARN=""
|
||||
if [ "$HOST_NAME" != arm-core ]; then
|
||||
CORE_VER=""
|
||||
if [ -d "$CORE_DIR" ]; then
|
||||
git -C "$CORE_DIR" fetch -q origin 2>/dev/null || true
|
||||
CORE_VER=$(git -C "$CORE_DIR" show origin/main:api/arm_statements/VERSION 2>/dev/null | tr -d ' \t\r\n' || true)
|
||||
fi
|
||||
if [ -z "$CORE_VER" ] || { [ "$CORE_VER" != "$TARGET" ] && ! git -C "$SRC" merge-base --is-ancestor "$TARGET" "$CORE_VER" 2>/dev/null; }; then
|
||||
CORE_WARN="ядро (arm-core@origin/main) ещё не на $T7: по порядку выкладки сначала ядро"
|
||||
echo "предупреждение: $CORE_WARN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 6. worktree хоста
|
||||
TMP_BRANCH="tmp/statements-sync-$T7"
|
||||
WT="$WT_ROOT/statements-sync-$T7/$HOST_NAME"
|
||||
[ ! -e "$WT" ] || die "worktree уже существует: $WT — завершите или удалите предыдущую синхронизацию" 2
|
||||
if git -C "$HOST_DIR" rev-parse -q --verify "$TMP_BRANCH" >/dev/null; then
|
||||
die "ветка $TMP_BRANCH уже существует в $HOST_NAME — завершите или удалите предыдущую синхронизацию" 2
|
||||
fi
|
||||
mkdir -p "$(dirname "$WT")"
|
||||
git -C "$HOST_DIR" worktree add -q -b "$TMP_BRANCH" "$WT" "$HOST_REF"
|
||||
touch "$WT/.bounded"
|
||||
echo "worktree: $WT ($TMP_BRANCH от $HOST_REF)"
|
||||
|
||||
# 7. issue и ветка (не в dry-run)
|
||||
# tea 0.16+ принимает --login/--repo только после подкоманды (arm-ka-docs#110)
|
||||
TEA_FLAGS=(--login home --repo "$GITEA_REPO")
|
||||
COMMITS=$(git -C "$SRC" log --format='%h %s' --no-merges "$OLD..$TARGET" 2>/dev/null || true)
|
||||
N_COMMITS=$(printf '%s\n' "$COMMITS" | grep -c . || true)
|
||||
ISSUE=""; ISSUE_URL=""
|
||||
BRANCH=$TMP_BRANCH
|
||||
if [ "$MODE" = sync ]; then
|
||||
TITLE="arm_statements: копия пакета arm-statements@$T7"
|
||||
BODY="Копия пакета \`api/arm_statements\` в \`$HOST_NAME\` была на \`$OLD7\`, станет \`$T7\` (источник — \`RSHB/arm-statements@${REF#origin/}\`).
|
||||
Коммиты arm-statements \`$OLD7..$T7\` ($N_COMMITS):
|
||||
$(printf '%s\n' "$COMMITS" | sed 's/^/- /')
|
||||
|
||||
Bounded-задача, выполнена \`docs/scripts/sync-statements.sh\`: копия раскладывается из \`git archive\`, не правится."
|
||||
ISSUE_URL=$(tea issues create "${TEA_FLAGS[@]}" --title "$TITLE" --description "$BODY" | grep -o 'https://[^ ]*/issues/[0-9]*' | tail -1)
|
||||
ISSUE=${ISSUE_URL##*/}
|
||||
[ -n "$ISSUE" ] || die "не удалось создать issue через tea (worktree оставлен: $WT)"
|
||||
BRANCH="feat/$ISSUE-statements-sync-$T7"
|
||||
git -C "$WT" branch -m "$TMP_BRANCH" "$BRANCH"
|
||||
echo "issue: $ISSUE_URL; ветка: $BRANCH"
|
||||
fi
|
||||
|
||||
# 8. раскладка и проверка результата
|
||||
lay_copy "$WT" "$TARGET" || die "раскладка выполнена, но копию нельзя коммитить (см. выше); worktree оставлен: $WT" 1
|
||||
evaluate "$WT/api/arm_statements" "$WT/api/requirements.txt" "$([ -n "$HLINES" ] && echo "$WT/api/rules/statement_lines.yaml")" "$HOST_NAME"
|
||||
if [ "$EVAL_CODE" = 20 ]; then
|
||||
echo "statements-check $HOST_NAME: 20 — после раскладки расхождение; worktree оставлен: $WT" >&2
|
||||
exit 1
|
||||
fi
|
||||
SC_LINE=$(summary)
|
||||
echo "перенесено: api/arm_statements = arm-statements@$T7"
|
||||
echo "$SC_LINE"
|
||||
|
||||
# 9. dry-run
|
||||
if [ "$MODE" = dry ]; then
|
||||
echo "dry-run: issue, проверки, коммит и PR не выполнялись. Посмотреть: git -C $WT status; убрать:"
|
||||
echo " git -C $HOST_DIR worktree remove --force $WT && git -C $HOST_DIR branch -D $TMP_BRANCH"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 10. проверки хоста
|
||||
run_make() { # run_make <имя> <цель>: хвост вывода при ошибке, worktree остаётся
|
||||
local log; log=$(mktemp)
|
||||
if make -C "$WT" "$2" >"$log" 2>&1; then rm -f "$log"; return 0; fi
|
||||
echo "sync-statements: проверка «$1» не прошла; worktree оставлен для разбора: $WT" >&2
|
||||
tail -40 "$log" >&2; rm -f "$log"; exit 1
|
||||
}
|
||||
run_make "make venv" venv
|
||||
run_make "make check" check
|
||||
echo "проверки хоста: make check зелёный"
|
||||
|
||||
# 11. коммит, push, PR
|
||||
git -C "$WT" add -A api/arm_statements
|
||||
git -C "$WT" -c commit.gpgsign=false commit -q -F - <<EOF
|
||||
chore(arm_statements): копия arm-statements@$T7 (#$ISSUE)
|
||||
|
||||
Копия api/arm_statements: $OLD7..$T7 ($N_COMMITS коммитов), скрипт docs/scripts/sync-statements.sh.
|
||||
Коммиты arm-statements:
|
||||
$(printf '%s\n' "$COMMITS" | sed 's/^/- /')
|
||||
|
||||
$SC_LINE
|
||||
|
||||
Co-Authored-By: sync-statements.sh <noreply@aepif.ru>
|
||||
EOF
|
||||
COMMIT=$(git -C "$WT" rev-parse --short=7 HEAD)
|
||||
git -C "$WT" push -q -u origin "$BRANCH"
|
||||
PR_BODY="Закрывает #$ISSUE.
|
||||
|
||||
Копия \`api/arm_statements\` в \`$HOST_NAME\` обновлена скриптом \`docs/scripts/sync-statements.sh\`: \`$OLD7\` -> \`$T7\` (источник — \`RSHB/arm-statements@${REF#origin/}\`).
|
||||
|
||||
Коммиты arm-statements ($N_COMMITS):
|
||||
$(printf '%s\n' "$COMMITS" | sed 's/^/- /')
|
||||
|
||||
Проверки: \`make check\` в worktree зелёный; $SC_LINE
|
||||
${CORE_WARN:+
|
||||
Предупреждение: $CORE_WARN
|
||||
}
|
||||
## Rulings I made
|
||||
- R-1 — копия не правится: перенос проревьюенного в arm-statements кода, содержимое равно \`git archive\` коммита \`$T7\`.
|
||||
- R-2 — bounded-задача без OpenSpec change.
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)"
|
||||
PR_URL=$(tea pulls create "${TEA_FLAGS[@]}" --head "$BRANCH" --base "${HOST_REF#origin/}" \
|
||||
--title "chore(arm_statements): копия arm-statements@$T7 (#$ISSUE)" --description "$PR_BODY" \
|
||||
| grep -o 'https://[^ ]*/pulls/[0-9]*' | tail -1)
|
||||
|
||||
# 12. итог
|
||||
echo
|
||||
echo "готово: коммит $COMMIT, ветка $BRANCH"
|
||||
echo "issue: $ISSUE_URL"
|
||||
echo "PR: ${PR_URL:-создать вручную: tea pulls create ${TEA_FLAGS[*]} --head $BRANCH --base ${HOST_REF#origin/}}"
|
||||
[ -z "$CORE_WARN" ] || echo "предупреждение: $CORE_WARN"
|
||||
echo "исполнителю: ревью диапазона не нужно — код проревьюен в arm-statements; merge и «закрывай» по команде человека."
|
||||
echo "worktree $WT и .bounded остаются до закрытия."
|
||||
|
||||
@ -296,5 +296,48 @@ sync 1 "in-place: повтор после защиты путей остаётс
|
||||
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: флаги после подкоманды"
|
||||
|
||||
[ "$fail" = 0 ] || exit 1
|
||||
echo "ok: sync-statements.sh — все сценарии пройдены"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user