Merge pull request 'docs(dev): гайд переноса сервисов в контур и скрипт подготовки снимка' (#35) from docs/34-contour-transfer into main
Reviewed-on: #35
This commit is contained in:
commit
cfe47b16ff
@ -8,6 +8,8 @@
|
|||||||
Для ручного тестирования стенда (установка ПО, запуск, чек-лист сценариев по ролям) — [`qa-guide.md`](qa-guide.md).
|
Для ручного тестирования стенда (установка ПО, запуск, чек-лист сценариев по ролям) — [`qa-guide.md`](qa-guide.md).
|
||||||
Разработчику фронта: как устроены вход и права `arm-core`, какие ручки когда дёргать, семантика 401/403/404 —
|
Разработчику фронта: как устроены вход и права `arm-core`, какие ручки когда дёргать, семантика 401/403/404 —
|
||||||
[`frontend-auth-guide.md`](frontend-auth-guide.md); контракт API консолидации — [`api-contract-slice-4.md`](api-contract-slice-4.md).
|
[`frontend-auth-guide.md`](frontend-auth-guide.md); контракт API консолидации — [`api-contract-slice-4.md`](api-contract-slice-4.md).
|
||||||
|
Перенос сервисов в контур банка (снимки без истории, что вырезается, скрипт подготовки, проверки в контуре) —
|
||||||
|
[`contour-transfer-guide.md`](contour-transfer-guide.md).
|
||||||
|
|
||||||
## Предварительные требования
|
## Предварительные требования
|
||||||
|
|
||||||
|
|||||||
180
dev/contour-transfer-guide.md
Normal file
180
dev/contour-transfer-guide.md
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
# Перенос сервисов АРМ КА в контур банка: гайд для разработчика
|
||||||
|
|
||||||
|
Разработка ведётся **снаружи** (workspace `awp-ca`, Gitea проекта). В контур банка (GitLab платформы РАИСА и его CI/CD;
|
||||||
|
Gitea в контуре нет)
|
||||||
|
уезжают только три сервисных репозитория — `arm-core`, `tabular-parser`, `scan-gateway` — **снимками дерева, без
|
||||||
|
истории**. Репозитории `docs` и `fixtures` в контур не переносятся: решение владельца 06.10.2026. Этот документ — что
|
||||||
|
именно уезжает, чего в платформе нет, как подготовить снимок скриптом и как его положить в контур.
|
||||||
|
|
||||||
|
Соглашения платформы, от которых всё отталкивается, — `context/03-architecture.md`, разделы «Соглашения шаблона команды»
|
||||||
|
и «Что ожидаем от платформы». Проверки качества — `dev/checks.md`.
|
||||||
|
|
||||||
|
## 1. Что переносится и что нет
|
||||||
|
|
||||||
|
| Что | В контур | Почему |
|
||||||
|
|---|---|---|
|
||||||
|
| `api/` (код, тесты, `contracts/`, `rules/`, `alembic/`, `scripts/`), `web/` (arm-core), `README.md`, `Makefile`, `setup/`, `raisa_config.yml`, `api/.env.example`, `api/.env.test` | да | это и есть сервис по шаблону платформы |
|
||||||
|
| `openspec/specs/`, `openspec/changes/archive/`, `openspec/config.yaml` | да | спецификация системы и журнал решений (`design.md`); без них код в контуре нечем объяснять |
|
||||||
|
| `.claude/`, `CLAUDE.md` | **нет** | инструкции и skills AI-агента, инструментарий внешней разработки |
|
||||||
|
| `docs/superpowers/` (планы, ledger) | **нет** | рабочие артефакты процесса, содержат локальные пути разработчика |
|
||||||
|
| `Dockerfile`, `.dockerignore` | **нет** | образ для локального `make check-full`; в контуре образ собирает платформа своим CI (шаблон держит `Dockerfile` в `.gitignore`) |
|
||||||
|
| История коммитов | **нет** | снимок одним коммитом; в истории снаружи — трейлеры `Co-Authored-By: Claude …`, `Claude-Session`, ссылки на внешний Gitea |
|
||||||
|
| Репозиторий `docs` | **нет** | контекст, модель, контракты, экспорт ТЗ — остаются снаружи; копия контракта лежит в `api/contracts/` каждого сервиса |
|
||||||
|
| Репозиторий `fixtures` | **нет** | реальная отчётность для регрессии парсера; тесты с маркером `fixtures` в контуре пропускаются |
|
||||||
|
| `reference-old-arm` | **нет** | старый репозиторий банка, читался только для справки |
|
||||||
|
|
||||||
|
Снимок получает файл `SNAPSHOT.md` с хешем коммита-источника и датой: по нему потом сверяется, что уже перенесено.
|
||||||
|
|
||||||
|
## 2. Чего в платформе нет и что есть
|
||||||
|
|
||||||
|
**Нет в контуре (всё это скрипт вырезает или заменяет):**
|
||||||
|
|
||||||
|
- `uv` — `make venv` снаружи ставит окружение через `uv venv --python 3.11` и `uv pip`. В снимке цель `venv` переписана
|
||||||
|
на `python3.11 -m venv` + `pip` с `setup/pip.conf` (Nexus), как делает `setup/setup.sh` шаблона.
|
||||||
|
- Docker и `docker compose` — локальная инфраструктура (`docs/dev/docker-compose.yml`) живёт в `docs`, которого в контуре
|
||||||
|
нет. Цели `make up`, `test-integration`, `check-full` в контуре не запускаются; `docker-build` удалена из `Makefile`.
|
||||||
|
- `docs` и `fixtures` рядом с сервисом — тесты идентичности контракта и тесты на реальных данных пропускаются
|
||||||
|
(раздел 5), сверка ORM с DBML (`make dbml-check` в arm-core) не выполняется.
|
||||||
|
- `tea`, `codegraph`, `openspec` (CLI), хуки `.claude/hooks` — инструментарий процесса; в снимке только их следы в
|
||||||
|
`openspec/config.yaml` (контекст для агента, безвреден).
|
||||||
|
- Внешний Gitea `git.aepif.ru` — ссылки вида `https://git.aepif.ru/RSHB/arm-core/pulls/19` в архивах change'ей
|
||||||
|
скрипт превращает в `RSHB/arm-core#19` (номера относятся к внешнему Gitea, в контуре их нет).
|
||||||
|
|
||||||
|
**Есть только в контуре (снаружи заменено заглушками, в снимке остаётся как есть):**
|
||||||
|
|
||||||
|
- Nexus `nexus.dev.raisa.go.rshbank.ru` (`setup/pip.conf`, `setup/.npmrc`) и пакеты `raisa_fastapi_protected_api`
|
||||||
|
(`api/requirements.txt` arm-core), `raisa-fastapi-protected-web`, `raisa-ui` (`web/package.json`, `optionalDependencies`).
|
||||||
|
Снаружи `make venv` их пропускает (`grep -v '^raisa_'`), импорт `raisa_fastapi_protected_api` условный — только при
|
||||||
|
`DEBUG=false`. В контуре всё ставится штатно.
|
||||||
|
- Запуск платформой: `api/run_server.py`, `SERVER__HOST`/`SERVER__PORT`, ресурсы `raisa_config.yml`, секреты `OPENBAO__*`
|
||||||
|
из OpenBao, Python 3.11 в базовом образе.
|
||||||
|
- PostgreSQL 16 (схема `dkb`), NATS без JetStream (nkeys/JWT), S3-совместимое хранилище, JWT РАИСА для входа.
|
||||||
|
|
||||||
|
## 3. Подготовка снимка: `scripts/prepare-contour-snapshot.sh`
|
||||||
|
|
||||||
|
Запуск из workspace, по одному репозиторию:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docs/scripts/prepare-contour-snapshot.sh arm-core /tmp/contour
|
||||||
|
docs/scripts/prepare-contour-snapshot.sh tabular-parser /tmp/contour
|
||||||
|
docs/scripts/prepare-contour-snapshot.sh scan-gateway /tmp/contour
|
||||||
|
# третий аргумент — ref; по умолчанию origin/main (снимок всегда с сервера, не из рабочего дерева)
|
||||||
|
```
|
||||||
|
|
||||||
|
Что делает скрипт (репозиторий-источник не меняется):
|
||||||
|
|
||||||
|
1. `git archive <ref>` → `/tmp/contour/<repo>/` — дерево коммита без `.git` и без игнорируемых файлов.
|
||||||
|
2. Удаляет `.claude/`, `CLAUDE.md`, `docs/superpowers/`, `Dockerfile`, `.dockerignore`.
|
||||||
|
3. Правит `Makefile`: цель `venv` → `python3.11 -m venv` + `pip install -r requirements-dev.txt` с `setup/pip.conf`
|
||||||
|
(переменная `PYTHON`, по умолчанию `python3.11`); удаляет цель `docker-build` и её упоминания в `check-full`, `.PHONY`,
|
||||||
|
`help`.
|
||||||
|
4. Заменяет ссылки на внешний Gitea на `RSHB/<repo>#<n>`.
|
||||||
|
5. Пишет `SNAPSHOT.md` (источник, хеш, дата, что вырезано).
|
||||||
|
6. Проверяет: нет `.claude`/`CLAUDE.md`/планов/`Dockerfile`, нет локальных путей (`/Users/…`, `/home/…`), нет `uv` и
|
||||||
|
`git.aepif.ru`, на месте платформенные файлы (`raisa_config.yml`, `setup/`, `run_server.py`, `requirements.txt`,
|
||||||
|
`.env.test`, `contracts/`). Любая проблема — код возврата 1 и список.
|
||||||
|
|
||||||
|
Проверено 06.10.2026: снимки arm-core@1d7f2c8, tabular-parser@3b32462, scan-gateway@dffc18a проходят `make check` без
|
||||||
|
`docs` и `fixtures` (1084 / 1087 / 726 passed, пропуски только по причинам из раздела 5).
|
||||||
|
|
||||||
|
## 4. Как положить снимок в контур
|
||||||
|
|
||||||
|
Репозитории контура — проекты GitLab, по одному на сервис, имена как снаружи. Первый перенос и каждый следующий делаются
|
||||||
|
одинаково (вместо PR в GitLab — merge request, в остальном git тот же):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <url контура>/arm-core contour-arm-core
|
||||||
|
cd contour-arm-core && git switch -c sync/arm-core-1d7f2c8 # ветка по правилам контура
|
||||||
|
rsync -a --delete --exclude .git /tmp/contour/arm-core/ ./ # дерево = снимок, удалённые снаружи файлы исчезают
|
||||||
|
git status --short # прочитать diff: он должен совпадать с изменениями снаружи
|
||||||
|
git add -A
|
||||||
|
git commit -m "sync: arm-core@1d7f2c8 (2026-10-06)" # хеш и дата — из SNAPSHOT.md
|
||||||
|
git push -u origin sync/arm-core-1d7f2c8 # дальше merge request и мерж по регламенту GitLab контура
|
||||||
|
```
|
||||||
|
|
||||||
|
`--delete` обязателен: иначе файлы, удалённые или переименованные снаружи, останутся в контуре. Если в контуре делали
|
||||||
|
локальные правки (раздел 7), сначала вернуть их наружу, иначе `rsync --delete` их перезапишет.
|
||||||
|
|
||||||
|
Порядок сервисов при одной синхронизации: `arm-core` → `tabular-parser` → `scan-gateway` (ядро — потребитель контракта,
|
||||||
|
его копия схемы должна быть не старше копий сервисов). Если снаружи поднималась версия контракта (`api/contracts/*.json`,
|
||||||
|
`CONTRACT_VERSION` в `api/src/contract/common.py`), переносить все три сервиса одним заходом.
|
||||||
|
|
||||||
|
## 5. Проверка в контуре перед merge request
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make venv # python3.11 -m venv + pip через Nexus (вместо setup/setup.sh; тот ставит только прод-зависимости)
|
||||||
|
make check # ruff, mypy, pytest без интеграционных тестов
|
||||||
|
```
|
||||||
|
|
||||||
|
Ожидаемые пропуски (`pytest -rs` покажет причины), это **не** ошибки:
|
||||||
|
|
||||||
|
| Сервис | Пропускается | Причина |
|
||||||
|
|---|---|---|
|
||||||
|
| все | тест идентичности `api/contracts/` с `docs/contracts/` | `docs` нет; идентичность проверена снаружи перед снимком |
|
||||||
|
| все | тесты с маркером `fixtures` (golden-снимки, property-тесты на реальных ОСВ/формах, покрытие словарей) | `fixtures` нет; регрессия на реальных данных — снаружи |
|
||||||
|
| arm-core | сверка ORM с DBML в тестах | DBML в `docs` |
|
||||||
|
| scan-gateway | тесты с реальными ответами ИС Сканирование (`fixtures/ocr`) | то же |
|
||||||
|
|
||||||
|
Не запускать в контуре: `make up`, `make test-integration`, `make check-full`, `make dbml-check`, `make e2e` — им нужны
|
||||||
|
compose из `docs` либо Docker. Интеграционные тесты против PostgreSQL/NATS/MinIO прогоняются снаружи перед каждым снимком;
|
||||||
|
пайплайну платформы отдаётся `make check`.
|
||||||
|
|
||||||
|
Фронт arm-core: `make web-check` (`npm install` через `.npmrc` Nexus, biome, tsc, `npm run build`). В контуре
|
||||||
|
`raisa-fastapi-protected-web` и `raisa-ui` ставятся штатно, снаружи они в `optionalDependencies` и пропускаются.
|
||||||
|
`web/package-lock.json` снаружи не коммитится (OQ-63) — в контуре lock-файл появится при первом `npm install`, решение о его
|
||||||
|
коммите за контуром.
|
||||||
|
|
||||||
|
## 6. Что нужно от платформы для запуска
|
||||||
|
|
||||||
|
Переменные окружения — `api/.env.example` каждого сервиса (имена и смысл), секреты под префиксом `OPENBAO__*`.
|
||||||
|
Минимум для arm-core:
|
||||||
|
|
||||||
|
- `OPENBAO__DATABASE__DATABASE_URL` (asyncpg, схема `dkb`), `OPENBAO__MINIO__{MINIO_URL, MINIO_ADMIN_LOGIN,
|
||||||
|
MINIO_ADMIN_PASSWORD, MINIO_BUCKET}` (`MINIO_SECURE=true` по умолчанию), `OPENBAO__NATS__{NATS_URL, NATS_SEED, NATS_JWT}`.
|
||||||
|
- `DEBUG=false` (включает middleware РАИСА, выключает `/docs` и dev-токены), `CORS_ORIGINS` (явный список; пусто —
|
||||||
|
кросс-доменные запросы запрещены), `FORWARDED_ALLOW_IPS` (адреса прокси платформы, иначе IP в аудите — адрес прокси),
|
||||||
|
`AUTH_JWKS_URL` или `AUTH_PUBLIC_KEY` + `AUTH_ISSUER`, `AUTH_AUDIENCE`, `AUTH_EMAIL_CLAIM` — параметры JWT РАИСА (открытый
|
||||||
|
вопрос OQ в `context/07-open-questions.md`). `AUTH_DEV_ISSUER`/`AUTH_DEV_SECRET` в проде не задавать.
|
||||||
|
- Миграции и seed при деплое: из `api/` — `alembic upgrade head`, затем `python -m scripts.seed` (справочники: план счетов,
|
||||||
|
правила элиминации, роли и права; `--dev` только для стенда разработки). Те же команды — цели `make migrate` и `make seed` (`README.md` arm-core,
|
||||||
|
«Быстрый старт», шаг 4 «Миграции и справочники»).
|
||||||
|
|
||||||
|
`tabular-parser` и `scan-gateway`: только `OPENBAO__MINIO__*`, `OPENBAO__NATS__*`, `DEBUG`, `NATS_ENABLED=true`; у парсера
|
||||||
|
`PARSE_MAX_BYTES`, `PARSE_TIMEOUT_SECONDS`; у шлюза `SCAN_HOTFOLDER_MODE=smb` и `OPENBAO__SMB__{SMB_HOST, SMB_PATH,
|
||||||
|
SMB_LOGIN, SMB_PASSWORD}` (режим `local` и эмулятор `make emulator` — только для разработки). Subjects NATS, схема ключей S3
|
||||||
|
и ресурсы — `context/03-architecture.md`.
|
||||||
|
|
||||||
|
## 7. Правки внутри контура и обратный поток
|
||||||
|
|
||||||
|
Правило: источник истины — репозитории снаружи. Любая правка в контуре (чаще всего под пайплайн платформы: пути, переменные,
|
||||||
|
`raisa_config.yml`) возвращается наружу до следующей синхронизации:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd contour-arm-core
|
||||||
|
git diff <коммит sync> HEAD -- . ':!SNAPSHOT.md' > /tmp/contour-arm-core.patch # база — коммит последнего sync
|
||||||
|
```
|
||||||
|
|
||||||
|
Патч применяется снаружи в ветку и проходит обычный PR; после его мержа следующий снимок уже содержит правку, и
|
||||||
|
`rsync --delete` ничего не потеряет. Если правка касается только контура (например, секретов платформы), её место — вне
|
||||||
|
репозитория: переменные окружения OpenBao, а не код.
|
||||||
|
|
||||||
|
## 8. Чек-лист одной синхронизации
|
||||||
|
|
||||||
|
1. Снаружи: нужные PR слиты в `main` трёх сервисов; `make check-full` зелёный в каждом; контракт в `docs/contracts` и копии
|
||||||
|
`api/contracts` идентичны.
|
||||||
|
2. Правки из контура (раздел 7) возвращены наружу и слиты.
|
||||||
|
3. `prepare-contour-snapshot.sh` по каждому сервису; скрипт завершился словами «снимок готов».
|
||||||
|
4. В контуре: клон, ветка, `rsync --delete`, просмотр `git status`, коммит `sync: <repo>@<hash> (<дата>)`, `make venv`,
|
||||||
|
`make check` (пропуски — только из раздела 5), для arm-core `make web-check`, merge request по регламенту GitLab контура.
|
||||||
|
5. Порядок мержа при смене версии контракта: arm-core → tabular-parser → scan-gateway.
|
||||||
|
6. Снаружи в `context/09-delivery-plan.md` или в issue синхронизации отметить, какие хеши перенесены.
|
||||||
|
|
||||||
|
## 9. Известные неточности снимка
|
||||||
|
|
||||||
|
- `README.md` сервисов описывают `make venv` через `uv` и ссылаются на `../docs`, `../fixtures`, `docs/dev/qa-guide.md`;
|
||||||
|
скрипт их не переписывает. Ориентир для контура — этот документ и `SNAPSHOT.md`.
|
||||||
|
- В `openspec/changes/archive/*/` остаются относительные пути вида `../docs/openspec/...` и `../fixtures/...`: это
|
||||||
|
ссылки на внешний workspace, в контуре они никуда не ведут.
|
||||||
|
- `openspec/config.yaml` содержит контекст для AI-агента (упоминает `../docs`, фикстуры, стек); на сборку не влияет.
|
||||||
|
- Тесты, которые снаружи пропускаются без `fixtures`, в контуре не выполняются никогда. Поэтому перед каждым снимком снаружи
|
||||||
|
обязателен `make check-full` с доступными `docs` и `fixtures` (`dev/checks.md`, раздел «Порядок перед PR»).
|
||||||
159
scripts/prepare-contour-snapshot.sh
Executable file
159
scripts/prepare-contour-snapshot.sh
Executable file
@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Снимок сервисного репозитория АРМ КА для переноса в контур банка (dev/contour-transfer-guide.md).
|
||||||
|
#
|
||||||
|
# Что делает: берёт дерево коммита (`git archive`, без истории), вырезает то, чего в контуре нет или что ему не нужно
|
||||||
|
# (AI-инструментарий, планы, Dockerfile для локальной сборки), переводит `make venv` с uv на `python -m venv` + pip через
|
||||||
|
# Nexus (как `setup/setup.sh` шаблона), убирает цель docker-build, заменяет ссылки на внешний Gitea, пишет SNAPSHOT.md с
|
||||||
|
# провенансом и проверяет результат. Репозиторий-источник не меняется.
|
||||||
|
#
|
||||||
|
# Запуск из workspace: docs/scripts/prepare-contour-snapshot.sh <каталог репозитория> <каталог вывода> [ref]
|
||||||
|
# ref по умолчанию — origin/main (снимок всегда с сервера, не с рабочего дерева).
|
||||||
|
# Пример: docs/scripts/prepare-contour-snapshot.sh tabular-parser /tmp/contour
|
||||||
|
# Результат: <каталог вывода>/<имя репозитория>/ — готовое дерево для rsync в клон репозитория контура.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() { echo "usage: $0 <repo-dir> <out-dir> [ref]" >&2; exit 2; }
|
||||||
|
[ $# -ge 2 ] || usage
|
||||||
|
|
||||||
|
REPO=$(cd "$1" && pwd)
|
||||||
|
mkdir -p "$2"
|
||||||
|
OUT=$(cd "$2" && pwd)
|
||||||
|
REF=${3:-origin/main}
|
||||||
|
NAME=$(basename "$REPO")
|
||||||
|
DEST="$OUT/$NAME"
|
||||||
|
|
||||||
|
case "$NAME" in
|
||||||
|
arm-core|tabular-parser|scan-gateway) ;;
|
||||||
|
*) echo "ошибка: $NAME — не сервисный репозиторий (ожидаются arm-core, tabular-parser, scan-gateway); docs и fixtures в контур не переносятся" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
if [ -e "$DEST" ]; then
|
||||||
|
echo "ошибка: $DEST уже существует — удалите или укажите другой каталог вывода" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$REPO" fetch -q origin
|
||||||
|
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")
|
||||||
|
|
||||||
|
mkdir -p "$DEST"
|
||||||
|
git -C "$REPO" archive "$REF" | tar -x -C "$DEST"
|
||||||
|
|
||||||
|
# --- 1. Вырезать то, чего в контуре нет ------------------------------------------------------------------------
|
||||||
|
# .claude/, CLAUDE.md — инструкции и skills AI-агента; docs/superpowers/ — планы и ledger (в них локальные пути);
|
||||||
|
# Dockerfile/.dockerignore — локальная сборка образа, платформа собирает образ своим CI. openspec/ остаётся:
|
||||||
|
# это спецификация проекта и решения (design.md).
|
||||||
|
rm -rf "$DEST/.claude" "$DEST/CLAUDE.md" "$DEST/docs/superpowers" "$DEST/Dockerfile" "$DEST/.dockerignore"
|
||||||
|
rmdir "$DEST/docs" 2>/dev/null || true
|
||||||
|
|
||||||
|
# --- 2. Makefile: venv через python -m venv + pip с Nexus, без uv; без docker-build --------------------------------
|
||||||
|
python3 -I - "$DEST/Makefile" <<'PY'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
lines = path.read_text(encoding="utf-8").splitlines()
|
||||||
|
out: list[str] = []
|
||||||
|
i = 0
|
||||||
|
venv_patched = False
|
||||||
|
while i < len(lines):
|
||||||
|
line = lines[i]
|
||||||
|
# рецепт venv: все строки с uv заменяются одним рецептом на pip
|
||||||
|
if line.startswith("venv:"):
|
||||||
|
comment_start = len(out)
|
||||||
|
while comment_start > 0 and out[comment_start - 1].startswith("#"):
|
||||||
|
comment_start -= 1
|
||||||
|
del out[comment_start:]
|
||||||
|
out.append("# Контур банка: Python 3.11 платформы, pip через Nexus (setup/pip.conf), как в setup/setup.sh; dev-зависимости")
|
||||||
|
out.append("# тянут requirements.txt. PYTHON переопределяется: make venv PYTHON=/usr/bin/python3.11")
|
||||||
|
out.append("PYTHON ?= python3.11")
|
||||||
|
out.append("venv:")
|
||||||
|
out.append("\tcd api && $(PYTHON) -m venv .venv")
|
||||||
|
out.append("\tcp setup/pip.conf api/.venv/pip.conf")
|
||||||
|
out.append("\tcd api && .venv/bin/pip install -r requirements-dev.txt")
|
||||||
|
i += 1
|
||||||
|
while i < len(lines) and lines[i].startswith("\t"):
|
||||||
|
i += 1
|
||||||
|
venv_patched = True
|
||||||
|
continue
|
||||||
|
# цель docker-build и комментарий над ней удаляются
|
||||||
|
if line.startswith("docker-build:"):
|
||||||
|
comment_start = len(out)
|
||||||
|
while comment_start > 0 and out[comment_start - 1].startswith("#"):
|
||||||
|
comment_start -= 1
|
||||||
|
del out[comment_start:]
|
||||||
|
i += 1
|
||||||
|
while i < len(lines) and lines[i].startswith("\t"):
|
||||||
|
i += 1
|
||||||
|
if i < len(lines) and lines[i] == "" and out and out[-1] == "":
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if line.startswith("check-full:"):
|
||||||
|
line = re.sub(r"\s+docker-build\b", "", line)
|
||||||
|
if line.startswith("\t$(MAKE) docker-build"):
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if line.startswith(".PHONY:"):
|
||||||
|
line = re.sub(r"\s+docker-build\b", "", line)
|
||||||
|
if line.startswith('\t@echo "docker-build'):
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
line = line.replace(" + docker-build", "")
|
||||||
|
out.append(line)
|
||||||
|
i += 1
|
||||||
|
if not venv_patched:
|
||||||
|
sys.exit("Makefile: цель venv не найдена — скрипт устарел относительно репозитория")
|
||||||
|
path.write_text("\n".join(out) + "\n", encoding="utf-8")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# --- 3. Ссылки на внешний Gitea → имя репозитория и номер ---------------------------------------------------------
|
||||||
|
# В openspec-архивах и README встречаются ссылки вида https://git.aepif.ru/RSHB/<repo>/issues/5 и pulls/7.
|
||||||
|
while IFS= read -r file; do
|
||||||
|
[ -n "$file" ] || continue
|
||||||
|
python3 -I - "$file" <<'PY'
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path(sys.argv[1])
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
text = re.sub(r"https?://git\.aepif\.ru/(RSHB/[\w.-]+)/(issues|pulls)/(\d+)", r"\1#\3", text)
|
||||||
|
text = re.sub(r"https?://git\.aepif\.ru/?", "внешний Gitea проекта", text)
|
||||||
|
path.write_text(text, encoding="utf-8")
|
||||||
|
PY
|
||||||
|
done < <(grep -rIl "git.aepif.ru" "$DEST" 2>/dev/null || true)
|
||||||
|
|
||||||
|
# --- 4. Провенанс ---------------------------------------------------------------------------------------------------
|
||||||
|
cat > "$DEST/SNAPSHOT.md" <<EOF
|
||||||
|
# Снимок $NAME для контура
|
||||||
|
|
||||||
|
Источник: внешний репозиторий проекта \`RSHB/$NAME\`, коммит \`$HASH\` ($DATE, «${SUBJECT}»).
|
||||||
|
Снимок без истории; подготовлен \`prepare-contour-snapshot.sh\` ($(date +%Y-%m-%d)).
|
||||||
|
|
||||||
|
Чего здесь нет по сравнению с источником: \`.claude/\`, \`CLAUDE.md\`, \`docs/superpowers/\` (инструментарий и планы
|
||||||
|
разработки снаружи), \`Dockerfile\`/\`.dockerignore\` (образ собирает платформа). Соседних репозиториев \`docs\` и
|
||||||
|
\`fixtures\` в контуре нет: тесты идентичности контракта и тесты с маркером \`fixtures\` пропускаются — это ожидаемо.
|
||||||
|
Копия контракта — \`api/contracts/\`, спецификация — \`openspec/specs/\`, решения — \`openspec/changes/archive/*/design.md\`.
|
||||||
|
|
||||||
|
Разработка ведётся снаружи; правки в контуре возвращаются в источник вручную (см. dev/contour-transfer-guide.md в docs).
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# --- 5. Проверки ----------------------------------------------------------------------------------------------------
|
||||||
|
fail=0
|
||||||
|
for p in .claude CLAUDE.md docs/superpowers Dockerfile .dockerignore; do
|
||||||
|
if [ -e "$DEST/$p" ]; then echo "ошибка: в снимке остался $p" >&2; fail=1; fi
|
||||||
|
done
|
||||||
|
if grep -rIn "/Users/\|/home/[a-z]" "$DEST" >/dev/null 2>&1; then
|
||||||
|
echo "ошибка: в снимке есть локальные пути:" >&2; grep -rIn "/Users/\|/home/[a-z]" "$DEST" >&2; fail=1
|
||||||
|
fi
|
||||||
|
if grep -rIn "git.aepif.ru\|uv venv\|uv pip" "$DEST" >/dev/null 2>&1; then
|
||||||
|
echo "ошибка: остались ссылки на внешний Gitea или uv:" >&2; grep -rIn "git.aepif.ru\|uv venv\|uv pip" "$DEST" >&2; fail=1
|
||||||
|
fi
|
||||||
|
for p in raisa_config.yml setup/setup.sh setup/pip.conf api/run_server.py api/requirements.txt api/.env.test api/contracts; do
|
||||||
|
if [ ! -e "$DEST/$p" ]; then echo "ошибка: платформенный файл $p отсутствует" >&2; fail=1; fi
|
||||||
|
done
|
||||||
|
[ "$fail" = 0 ] || exit 1
|
||||||
|
|
||||||
|
echo "снимок готов: $DEST"
|
||||||
|
echo "источник: $NAME@${HASH:0:7} ($DATE); файлов: $(find "$DEST" -type f | wc -l | tr -d ' ')"
|
||||||
Loading…
x
Reference in New Issue
Block a user