From 685916c4bd0948e309483b28db9e793fee769825 Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Wed, 28 Oct 2026 20:11:14 +0300 Subject: [PATCH] =?UTF-8?q?ci:=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=20merge=20gate=20=D0=BD=D0=B0=20Gitea=20+=20?= =?UTF-8?q?Woodpecker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .woodpecker/check.yaml, smoke.yaml, release.yaml - local-backend агент: Java 21, Docker Compose v2, Python 3, Node/Playwright - concurrency lms-ci, чтобы smoke/release не занимали порты одновременно - deploy/WOODPECKER.md: server, OAuth Gitea, systemd-агент, security note - удалён .gitlab-ci.yml --- .gitlab-ci.yml | 87 -------------- .woodpecker/check.yaml | 18 +++ .woodpecker/release.yaml | 16 +++ .woodpecker/smoke.yaml | 18 +++ README.md | 15 +-- deploy/DEPLOY.md | 16 ++- deploy/WOODPECKER.md | 164 +++++++++++++++++++++++++++ docs/08-groups-courses-plan.md | 18 +-- docs/16-stage6-report.md | 35 +++--- docs/17-handoff.md | 31 ++--- docs/evidence/README.md | 10 +- docs/evidence/baseline-2026-10-27.md | 28 ++--- scripts/ci-preflight.sh | 15 ++- 13 files changed, 310 insertions(+), 161 deletions(-) delete mode 100644 .gitlab-ci.yml create mode 100644 .woodpecker/check.yaml create mode 100644 .woodpecker/release.yaml create mode 100644 .woodpecker/smoke.yaml create mode 100644 deploy/WOODPECKER.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index ac21f56..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,87 +0,0 @@ -# Единый merge gate: тесты, ktlint и detekt. -# Testcontainers поднимает PostgreSQL 18 через Docker-in-Docker, поэтому runner -# должен разрешать privileged-сервисы (docker:dind) и сеть до docker:2375. -stages: - - check - - smoke - - release-evidence - -variables: - GRADLE_OPTS: "-Dorg.gradle.daemon=false" - GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle" - DOCKER_HOST: "tcp://docker:2375" - DOCKER_TLS_CERTDIR: "" - TESTCONTAINERS_HOST_OVERRIDE: "docker" - -check: - stage: check - image: eclipse-temurin:21-jdk - services: - - name: docker:27-dind - alias: docker - cache: - key: "gradle-$CI_COMMIT_REF_SLUG" - paths: - - .gradle/caches - - .gradle/wrapper - script: - - ./gradlew --no-daemon test ktlintCheck detekt evidenceCheck - artifacts: - when: always - paths: - - build/reports/evidence/index.md - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - - if: '$CI_COMMIT_BRANCH' - -# Дымовой тест на каждый push/MR: полный стек на одноразовой БД, health, -# вход и один доменный сценарий. Полный release gate — ниже. -smoke: - stage: smoke - # Shell-runner: скрипт поднимает реальный стек на localhost и проверяет его. - # На runner нужны Java 21, Docker Compose v2, Python 3 и bash. - tags: [lms-shell] - before_script: - - ./scripts/ci-preflight.sh - cache: - key: "gradle-$CI_COMMIT_REF_SLUG" - paths: - - .gradle/caches - - .gradle/wrapper - script: - - ./scripts/ldd-smoke.sh - artifacts: - when: always - paths: - - build/evidence/smoke.json - rules: - - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - - if: '$CI_COMMIT_BRANCH' - -# Ручной release gate: runtime, mutation и browser evidence. -# Нужен privileged docker:dind; Chromium/Firefox/WebKit и Node ставятся в before_script. -release-evidence: - stage: release-evidence - # Shell-runner с Java 21, Docker Compose v2, Node 22, браузерами Playwright. - tags: [lms-release] - before_script: - - cd e2e && npm ci && cd .. - - ./scripts/ci-preflight.sh --release - - cd e2e && npx playwright install --with-deps chromium firefox webkit && cd .. - cache: - key: "gradle-$CI_COMMIT_REF_SLUG" - paths: - - .gradle/caches - - .gradle/wrapper - script: - - ./scripts/ldd-release.sh - artifacts: - when: always - paths: - - build/evidence/ - - build/reports/evidence/ - rules: - - if: '$CI_COMMIT_TAG' - when: on_success - - if: '$CI_COMMIT_BRANCH' - when: manual diff --git a/.woodpecker/check.yaml b/.woodpecker/check.yaml new file mode 100644 index 0000000..3f0b9fa --- /dev/null +++ b/.woodpecker/check.yaml @@ -0,0 +1,18 @@ +# Merge gate: тесты, линтеры и evidence. +# Выполняется на Woodpecker-агенте с local backend: нужны Java 21, Docker +# (Testcontainers), Docker Compose v2, Python 3 и bash. +when: + - event: [push, pull_request] + +steps: + - name: check + image: bash + commands: + - ./scripts/ci-preflight.sh + - ./gradlew --no-daemon test ktlintCheck detekt evidenceCheck + +# Один общий слот: smoke/release поднимают реальный стек на localhost, +# параллельный запуск занял бы порты 8080–8090. +concurrency: + limit: 1 + group: lms-ci diff --git a/.woodpecker/release.yaml b/.woodpecker/release.yaml new file mode 100644 index 0000000..8a064c5 --- /dev/null +++ b/.woodpecker/release.yaml @@ -0,0 +1,16 @@ +# Полный release gate: тесты, миграции, mutation, runtime/scale и +# Chromium/Firefox/WebKit E2E. Запускается на тег или вручную. +when: + - event: [tag, manual] + +steps: + - name: release + image: bash + commands: + - cd e2e && npm ci && cd .. + - ./scripts/ci-preflight.sh --release + - ./scripts/ldd-release.sh + +concurrency: + limit: 1 + group: lms-ci diff --git a/.woodpecker/smoke.yaml b/.woodpecker/smoke.yaml new file mode 100644 index 0000000..760f887 --- /dev/null +++ b/.woodpecker/smoke.yaml @@ -0,0 +1,18 @@ +# Дымовой тест на каждый push/MR: полный стек, health, вход админа, +# один доменный сценарий. Полный release gate — в release.yaml. +when: + - event: [push, pull_request] + +depends_on: + - check + +steps: + - name: smoke + image: bash + commands: + - ./scripts/ci-preflight.sh + - ./scripts/ldd-smoke.sh + +concurrency: + limit: 1 + group: lms-ci diff --git a/README.md b/README.md index 4e91aad..6e1486e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`. ./gradlew ktlintCheck detekt test # линтеры (строгий режим) + тесты ./gradlew evidenceCheck # LDD: P0-claims должны иметь зелёные свидетельства ./gradlew ktlintFormat # автоформат Kotlin -./scripts/ldd-smoke.sh # быстрый smoke полного стека (как CI job smoke) +./scripts/ldd-smoke.sh # быстрый smoke полного стека (как CI workflow smoke) ./scripts/ldd-runtime.sh # runtime-smoke полного стека + scale load ./scripts/ldd-migration-upgrade.sh # upgrade с master-схемы ./scripts/ldd-mutation.sh # PIT: mutation strength критичных P0-компонентов @@ -84,12 +84,13 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`. P0 без зелёного теста валит `./gradlew evidenceCheck`. Runtime, migration, mutation, browser E2E и smoke — скрипты из `scripts/`; baseline — `docs/evidence/baseline-2026-10-27.md`. -- CI merge gate — `.gitlab-ci.yml`: `test ktlintCheck detekt evidenceCheck` и - job `smoke` (`scripts/ldd-smoke.sh`) на каждом push/MR. Полный - `release-evidence` (`scripts/ldd-release.sh`) обязателен для тегов и - запускается вручную для веток. `check` требует privileged `docker:dind` - для Testcontainers; `smoke`/`release-evidence` — shell-runner с Java 21, - Docker Compose v2, Python 3 и (для release) Node + Chromium/Firefox/WebKit. +- CI merge gate — `.woodpecker/` (Gitea + Woodpecker 3.x): + workflow `check` (`test ktlintCheck detekt evidenceCheck`) и `smoke` + (`scripts/ldd-smoke.sh`) на каждом push/MR; полный `release` — + `scripts/ldd-release.sh` — на тег или вручную. Smoke/release идут на + Woodpecker-агенте с local backend: Java 21, Docker Compose v2, Python 3, + Node и Chromium/Firefox/WebKit. Установка — + [`deploy/WOODPECKER.md`](deploy/WOODPECKER.md). Baseline: **51 claim, 346 тестов, 18/18 browser E2E**. ## Запуск в Docker (для сервера) diff --git a/deploy/DEPLOY.md b/deploy/DEPLOY.md index 78892c9..70e5509 100644 --- a/deploy/DEPLOY.md +++ b/deploy/DEPLOY.md @@ -144,16 +144,14 @@ progress `V13`. `scripts/legacy-assets.sh`: файлы без привязки к статье больше не публичны (`404` для обычных пользователей), их нужно привязать или удалить. -CI (`.gitlab-ci.yml`) на каждом push/MR выполняет -`./gradlew --no-daemon test ktlintCheck detekt evidenceCheck` и job `smoke` -(`./scripts/ldd-smoke.sh`: полный стек, health, вход админа, один курс). -Полный job `release-evidence` (`./scripts/ldd-release.sh`) обязателен для тегов -и запускается вручную для веток. `smoke` и release запускают +CI (`.woodpecker/`, Gitea + Woodpecker 3.x) на каждом push/MR выполняет +workflow `check` (`./gradlew --no-daemon test ktlintCheck detekt evidenceCheck`) +и `smoke` (`./scripts/ldd-smoke.sh`: полный стек, health, вход админа, один +курс). Полный workflow `release` (`./scripts/ldd-release.sh`) обязателен для +тегов и запускается вручную для веток. Smoke/release начинаются с `scripts/ci-preflight.sh`, который проверяет Java 21, Docker Compose v2, -Python 3, Node и Playwright. `check` использует privileged `docker:dind` -для Testcontainers; `smoke`/`release-evidence` выполняются на shell-runner -с Java 21, Docker Compose v2, Python 3, Node и браузерами -Chromium/Firefox/WebKit. +Python 3, Node и Playwright. Агент — local backend на хосте с Docker: +установка и systemd-юнит — [`WOODPECKER.md`](WOODPECKER.md). ## 8. Резервное копирование diff --git a/deploy/WOODPECKER.md b/deploy/WOODPECKER.md new file mode 100644 index 0000000..34c91a6 --- /dev/null +++ b/deploy/WOODPECKER.md @@ -0,0 +1,164 @@ +# CI на Gitea + Woodpecker + +Репозиторий использует **Woodpecker CI 3.x**. Конфигурация лежит в +`.woodpecker/`: + +| Workflow | Событие | Что делает | +|---|---|---| +| `check` | push, pull_request | `ci-preflight.sh`, `test ktlintCheck detekt evidenceCheck` | +| `smoke` | push, pull_request | после `check`: полный стек, health, вход админа, один курс | +| `release` | tag, manual | `npm ci`, preflight, полный `ldd-release.sh` (миграции, mutation, load, Chromium/Firefox/WebKit) | + +Все три workflow используют `concurrency: {limit: 1, group: lms-ci}`: smoke и +release поднимают реальный стек на портах 8080–8090, параллельный запуск занял +бы порты. + +## Почему local backend + +`check` может работать в Docker-бэкенде, но `smoke`/`release` запускают +`docker compose` и Java-процессы на `localhost`, поэтому им нужен доступ к +Docker и портам хоста. Проще всего один агент с **local backend** на том же +сервере, где стоит Docker. + +> **Безопасность.** Local backend выполняет пайплайн прямо на хосте без +> изоляции. Он допустим только для **приватного** репозитория с доверенными +> авторами. Не включайте публичные форки/PR от недоверенных пользователей на +> этом агенте: код пайплайна сможет прочитать окружение агента. Если появится +> публичный контур — вынесите `check` на отдельный Docker-backend агент, а +> smoke/release оставьте на изолированной машине. + +## 1. Требования к серверу агента + +- Java 21 в `PATH` (не Java 25 — см. README). +- Docker Engine + Compose v2, пользователь агента в группе `docker`. +- Python 3, bash, git, curl, `ss` (`iproute2`), Node.js 22 + npm. +- Системные библиотеки для Chromium/Firefox/WebKit. На Fedora проще один раз + выполнить `sudo npx playwright install-deps`; WebKit при их отсутствии + автоматически запускается в Docker-образе Playwright. +- Свободные порты 8080–8090 на время smoke/release. +- Достаточно места: Gradle-кэш, Docker-образы, Playwright-браузеры. + +Проверка окружения: + +```bash +./scripts/ci-preflight.sh # для smoke/check +./scripts/ci-preflight.sh --release +``` + +## 2. Woodpecker server + +Удобно запустить server в Docker рядом с Gitea. Пример +`docker-compose.woodpecker.yml` (не коммитьте секреты): + +```yaml +services: + woodpecker-server: + image: woodpeckerci/woodpecker-server:v3 + restart: unless-stopped + ports: + - "127.0.0.1:8000:8000" # UI за nginx + - "127.0.0.1:9000:9000" # gRPC для агента + environment: + WOODPECKER_OPEN: "false" + WOODPECKER_HOST: ${WOODPECKER_HOST:?https://ci.example.ru} + WOODPECKER_GITEA: "true" + WOODPECKER_GITEA_URL: ${GITEA_URL:?https://git.example.ru} + WOODPECKER_GITEA_CLIENT: ${GITEA_CLIENT:?} + WOODPECKER_GITEA_SECRET: ${GITEA_SECRET:?} + WOODPECKER_AGENT_SECRET: ${WOODPECKER_AGENT_SECRET:?} + WOODPECKER_ADMIN: ${WOODPECKER_ADMIN:?admin} + volumes: + - woodpecker-data:/var/lib/woodpecker + +volumes: + woodpecker-data: +``` + +1. В Gitea создайте OAuth2-приложение: + redirect URI `https://ci.example.ru/authorize`. +2. Заполните `GITEA_CLIENT`, `GITEA_SECRET`, `WOODPECKER_AGENT_SECRET` + (например, `openssl rand -hex 32`), `WOODPECKER_HOST`, `GITEA_URL`. +3. Если Gitea и Woodpecker на одном хосте, разрешите webhook на loopback в + `/etc/gitea/conf/app.ini`: + ```ini + [webhook] + ALLOWED_HOST_LIST = external,loopback + ``` + Также проверьте, что Gitea отдаёт API-страницы не меньше 50 элементов + (значение по умолчанию подходит). +4. Поднимите server и зайдите в UI через Gitea-аккаунт. +5. Включите репозиторий LMS в Woodpecker (Settings → Repositories). + +## 3. Агент на хосте + +Server в контейнере, агент — **на хосте**, иначе local backend не увидит +Java/Docker/Node хоста. + +```bash +sudo useradd --system --create-home --shell /bin/bash woodpecker +sudo usermod -aG docker woodpecker +sudo install -m 0755 woodpecker-agent /usr/local/bin/woodpecker-agent +``` + +`woodpecker-agent` скачивается из релизов Woodpecker (Linux amd64): +`https://github.com/woodpecker-ci/woodpecker/releases`. + +`/etc/woodpecker-agent.env` (права `0600`, владелец `root`): + +```dotenv +WOODPECKER_SERVER=localhost:9000 +WOODPECKER_AGENT_SECRET=тот-же-секрет-что-у-server +WOODPECKER_BACKEND=local +WOODPECKER_MAX_WORKFLOWS=1 +# Кэш Gradle и браузеров Playwright переживает запуски. Допустимо только для +# приватного репозитория с доверенными авторами (см. предупреждение выше). +WOODPECKER_BACKEND_LOCAL_ISOLATED_HOME=false +``` + +`/etc/systemd/system/woodpecker-agent.service`: + +```ini +[Unit] +Description=Woodpecker CI agent (LMS) +After=network-online.target docker.service +Wants=network-online.target + +[Service] +User=woodpecker +EnvironmentFile=/etc/woodpecker-agent.env +ExecStart=/usr/local/bin/woodpecker-agent +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +``` + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now woodpecker-agent +journalctl -u woodpecker-agent -f +``` + +В UI агент появится через несколько секунд. Репозиторий должен быть помечен +как trusted, если вы захотите использовать volumes/privileged (текущему +конфигу они не нужны). + +## 4. Первый прогон + +1. Push в ветку или MR → pipeline `check` → `smoke`. +2. Убедиться, что зелёные оба workflow. +3. Проверить ручной запуск: UI → Run pipeline → event `manual` → workflow + `release`. +4. Для релиза: `git tag vX.Y.Z && git push origin vX.Y.Z` → workflow + `release`; полный отчёт печатается в лог, файлы остаются в + `build/evidence/` рабочей копии агента. + +Если pipeline не появляется: + +- проверьте, что репозиторий включён в Woodpecker; +- проверьте `WOODPECKER_SERVER` и общий `WOODPECKER_AGENT_SECRET`; +- проверьте, что агент видит Docker (`docker compose version` от пользователя + `woodpecker`) и Java 21; +- проверьте, что путь конфигурации в настройках проекта — `.woodpecker/` + (по умолчанию). diff --git a/docs/08-groups-courses-plan.md b/docs/08-groups-courses-plan.md index 172e32d..3761149 100644 --- a/docs/08-groups-courses-plan.md +++ b/docs/08-groups-courses-plan.md @@ -196,12 +196,12 @@ привязка групп, авторские материалы курса. - Полная security-матрица и negative-тесты «свой/чужой курс». - Upgrade-тест миграций. -- Индексы; пагинация аудита и bulk-выдача групп с именами — выполнены; - оставшийся N+1 в отдельных лабораторных списках — follow-up (§ 9.1). +- Индексы; keyset-пагинация аудита, bulk-выдача групп и пакетные детали + лабораторных — выполнены. - Аудит скачиваний и чувствительных действий (`identity.audit_events`, `/admin/audit`). -- CI merge gate: `test ktlintCheck detekt evidenceCheck` и smoke полного стека - на каждом push/MR; полный `release-evidence` — для тегов/вручную. +- CI на Gitea + Woodpecker: `check` (`test ktlintCheck detekt evidenceCheck`) + и `smoke` на каждом push/MR; полный `release` — для тегов/вручную. - Проверка backup: создание, retention, `verify`, restore на staging. - Документация, deploy/runbook, smoke. @@ -357,8 +357,9 @@ identity V13, **academic V12**, progress V13. - **Сессии.** Web-сессия скользящая 7 дней, абсолютный потолок 30 дней (`LMS_SESSION_ABSOLUTE_TIMEOUT`); истёкшие refresh-токены чистит ночная задача (`LMS_REFRESH_TOKEN_RETENTION`). -- **CI.** Конфигурация и `ci-preflight.sh` готовы; первый реальный pipeline - на GitLab shell-runners ещё нужно подтвердить. +- **CI.** Конфигурация `.woodpecker/` и `ci-preflight.sh` готовы; Woodpecker + server/agent и первый реальный pipeline ещё нужно развернуть и подтвердить + (`deploy/WOODPECKER.md`). - **Внешняя интеграция «Контингент»/`next.uniyar.ac.ru` исключена из плана** до появления нового ТЗ и доступа к API. @@ -378,7 +379,8 @@ identity V13, **academic V12**, progress V13. 7 дней sliding с абсолютным потолком 30 дней; logout, смена пароля и закрытие доступа отзывают refresh. - Security-матрица и миграционный upgrade-тест зелёные (identity до `V13`). -- CI на каждом push/MR прогоняет `test ktlintCheck detekt evidenceCheck` и - smoke полного стека; полный release-evidence обязателен для тегов. +- CI (Gitea + Woodpecker) на каждом push/MR прогоняет + `test ktlintCheck detekt evidenceCheck` и smoke полного стека; полный + `release` обязателен для тегов. - Backup перед деплоем обязателен; restore проверен на staging. - Документация, deploy/runbook и smoke обновлены. diff --git a/docs/16-stage6-report.md b/docs/16-stage6-report.md index f89ec55..c104c4d 100644 --- a/docs/16-stage6-report.md +++ b/docs/16-stage6-report.md @@ -76,8 +76,8 @@ После закрытия рисков актуальный LDD-baseline — **346 тестов, 0 failures** (см. раздел 7). `ktlintCheck` и `detekt` прошли без замечаний. У gateway теперь есть unit-тесты публичных auth-путей и 401; маршрутизация gateway дополнительно проверена конфигурацией и security-матрицей ниже. -Тот же набор команд выполняет `.gitlab-ci.yml`; на каждый push/MR добавлен -smoke-job, полный release-evidence обязателен для тегов. +Тот же набор команд выполняет `.woodpecker/` (Gitea + Woodpecker 3.x); на +каждый push/MR добавлен smoke-workflow, полный release обязателен для тегов. ### 2.2. Upgrade-тест миграций @@ -186,13 +186,12 @@ legacy-активов на production, сдачи по выбранной лаб Там же задан `LMS_DB_PASSWORD`; `.env.prod` не коммитится. - [ ] Проверить, что на сервере нет незакоммиченных изменений и выполнен `git pull` нужной ветки/тега. -- [ ] **CI зелёный.** `.gitlab-ci.yml` на каждом push/MR выполняет - `test ktlintCheck detekt evidenceCheck` и job `smoke` - (`scripts/ldd-smoke.sh`: полный стек, health, вход админа, один курс). - Полный `release-evidence` обязателен для тегов и запускается вручную для - веток. `check` использует privileged-сервисы `docker:dind` для Testcontainers; - `smoke`/`release-evidence` — shell-runner с Java 21, Docker Compose v2, - Python 3, Node и Chromium Playwright. +- [ ] **CI зелёный.** `.woodpecker/` (Gitea + Woodpecker 3.x) на каждом + push/MR выполняет workflow `check` (`test ktlintCheck detekt evidenceCheck`) + и `smoke` (`scripts/ldd-smoke.sh`: полный стек, health, вход админа, один + курс). Полный `release` обязателен для тегов и запускается вручную для + веток. Агент — local backend с Java 21, Docker Compose v2, Python 3, Node и + Chromium/Firefox/WebKit; установка — [`deploy/WOODPECKER.md`](../deploy/WOODPECKER.md). - [ ] Заданы сроки сессии: `LMS_ACCESS_TOKEN_TTL=15m`, `LMS_REFRESH_TOKEN_TTL=7d`, `LMS_SESSION_TIMEOUT=7d`, `LMS_SESSION_ABSOLUTE_TIMEOUT=30d`, `LMS_REFRESH_TOKEN_RETENTION=30d` @@ -306,9 +305,9 @@ legacy-активов на production, сдачи по выбранной лаб WebKit = 18/18, но нет screenshot-diff и полного набора мобильных страниц. На Fedora WebKit запускается через Docker-образ Playwright, потому что системных Ubuntu-библиотек нет. -5. **Первый реальный CI-прогон не подтверждён.** Конфигурация, smoke и - `scripts/ci-preflight.sh` готовы, но наличие GitLab shell-runners с тегами - `lms-shell`/`lms-release` и первый tag-job нужно проверить в GitLab. +5. **Первый реальный CI-прогон не подтверждён.** Конфигурация `.woodpecker/`, + smoke и `scripts/ci-preflight.sh` готовы, но Woodpecker-сервер и агент на + сервере ещё нужно развернуть и проверить первый push-MR pipeline и tag-job. 6. **Внешняя интеграция «Контингент» исключена из плана.** Отдельного anti-corruption слоя, синхронизации и внешних идентификаторов не будет без нового ТЗ и доступа к API. @@ -324,10 +323,10 @@ legacy-активов на production, сдачи по выбранной лаб 1. **Прогнать инвентаризацию legacy-активов на production/staging** через `/admin/legacy-assets` или `scripts/legacy-assets.sh`, привязать нужные файлы к статьям, остальные удалить. -2. **Проверить CI на реальном runner.** Убедиться, что есть shell-runners - `lms-shell`/`lms-release` с Java 21, Docker Compose v2, Python 3, - Node/Chromium/Firefox/WebKit; дождаться зелёного push-MR pipeline и - tag-job `release-evidence`. +2. **Развернуть Woodpecker и проверить CI.** Поднять server и local-backend + агент по [`deploy/WOODPECKER.md`](../deploy/WOODPECKER.md), включить + репозиторий, дождаться зелёных `check`/`smoke` на push-MR и `release` на + теге. 3. **Дальнейшее расширение E2E** — визуальная регрессия и остальные мобильные страницы, если UI продолжит расти. 4. **Пакетные сдачи ведомости**, если появятся курсы, где открытие ведомости @@ -348,13 +347,13 @@ web-сессия с отзывом и абсолютным потолком, key После этапа 6 и закрытия рисков текущая функциональность проверена через LDD-контур: реестр `docs/evidence/claims.json` (**51 claims, 25 P0 / 26 P1**), -gate `./gradlew evidenceCheck`, upgrade-скрипт, runtime-smoke, smoke-job, +gate `./gradlew evidenceCheck`, upgrade-скрипт, runtime-smoke, smoke-workflow, mutation testing и браузерный Playwright E2E. Результат: **51/51 claims proven, P0 gaps = 0, 346 тестов, 0 failures**; mutation strength `CourseAccessService` 75%, `PromotionPlanner` 69%; browser E2E 18/18 (6 сценариев × Chromium/Firefox/WebKit); конкурентные apply/rollback и масштабный нагрузочный smoke (100 групп / 1000 студентов, 125 параллельных чтений, 0 ошибок, p95 < 1 с) зелёные. -Smoke-job выполняется на каждом push/MR, полный `release-evidence` обязателен +Workflow `smoke` выполняется на каждом push/MR, полный `release` обязателен для тегов и доступен вручную для веток. E2E нашёл и закрыл реальный дефект Jackson 3/Kotlin defaults. Подробности и остаточные ограничения — [`docs/evidence/baseline-2026-10-27.md`](evidence/baseline-2026-10-27.md). diff --git a/docs/17-handoff.md b/docs/17-handoff.md index 1d82785..32f79c8 100644 --- a/docs/17-handoff.md +++ b/docs/17-handoff.md @@ -2,7 +2,8 @@ **Дата:** 2026-10-28. **Ветка:** `feature/groups-courses` (последняя история — `git log --oneline`). -**Последний коммит перед этой итерацией:** `3aae2b8` (`docs: handoff после закрытия продуктовых рисков`). +**HEAD до переделки CI:** `d98c3b0` (`feat: закрыть остаточный backlog`); +история CI-правки — следующий коммит в `git log`. **Пуш:** не выполнялся. **Рабочее дерево:** чистое. `exports/` и `texput.log` игнорируются и в коммиты не входят. @@ -122,13 +123,15 @@ инвентаризация активов). - Runtime/load: 100 групп / 1000 студентов, 125 параллельных чтений, 0 ошибок, p95 < 1 c. -- CI: +- CI: Gitea + Woodpecker 3.x, конфигурация в `.woodpecker/`: - `check` на push/MR: тесты, ktlint, detekt, `evidenceCheck`; - - `smoke` на push/MR: preflight + полный стек, health, вход админа, один курс; - - `release-evidence` обязателен для тегов, вручную для веток: тесты, - миграции, mutation, runtime/load, browser E2E, финальный evidence. + - `smoke` на push/MR: после `check` — preflight + полный стек, health, + вход админа, один курс; + - `release` на тег или вручную: тесты, миграции, mutation, runtime/load, + browser E2E, финальный evidence. - `scripts/ci-preflight.sh` проверяет Java 21, Docker Compose v2, Python 3, - Node и Playwright; первый реальный GitLab pipeline ещё не подтверждён. + Node и Playwright. Установка server/agent — `deploy/WOODPECKER.md`. + - Первый реальный Woodpecker pipeline ещё не подтверждён. - Полный `./scripts/ldd-release.sh` локально прошёл; browser E2E — 18/18. ### 1.9. Миграции @@ -172,7 +175,7 @@ # 2. Полный LDD release (долго, нужны Docker/Java/Node + Chromium/Firefox/WebKit) ./scripts/ldd-release.sh -# 3. Быстрый smoke (то же, что CI smoke) +# 3. Быстрый smoke (то же, что workflow smoke) ./scripts/ldd-smoke.sh # 4. Отдельные проверки @@ -208,11 +211,11 @@ cat build/reports/evidence/index.md у обычных пользователей. 2. **Первый реальный CI-прогон.** - Конфиг, smoke и `scripts/ci-preflight.sh` готовы, но нужно убедиться, что в - GitLab есть shell-runners с тегами `lms-shell` (smoke) и `lms-release` - (полный release), Java 21, Docker Compose v2, Python 3, Node и браузерами - Chromium/Firefox/WebKit. `check` использует privileged `docker:dind`. - Дождаться зелёного push-MR pipeline и первого tag-job `release-evidence`. + Развернуть Woodpecker server и local-backend агент по + `deploy/WOODPECKER.md`, включить репозиторий в Woodpecker и дождаться + зелёных workflow `check`/`smoke` на push-MR и `release` на теге. Агенту + нужны Java 21, Docker Compose v2, Python 3, Node и браузеры + Chromium/Firefox/WebKit. 3. **Визуальная регрессия и мобильный набор E2E.** Сейчас 6 сценариев × 3 браузера, без screenshot-diff. Добавлять по мере @@ -297,4 +300,6 @@ cat build/reports/evidence/index.md - `web/.../admin/AdminAuditController.kt`, `LegacyAssetsController.kt`. - `services/gateway/.../JwtAuthenticationFilter.kt`. - `scripts/ldd-*.sh`, `scripts/ci-preflight.sh`, `scripts/legacy-assets.sh`. -- `deploy/backup.sh`, `deploy/deploy.sh`, `deploy/DEPLOY.md`. +- `.woodpecker/{check,smoke,release}.yaml` — CI на Gitea + Woodpecker. +- `deploy/backup.sh`, `deploy/deploy.sh`, `deploy/DEPLOY.md`, + `deploy/WOODPECKER.md`. diff --git a/docs/evidence/README.md b/docs/evidence/README.md index 56d7ff9..54541d2 100644 --- a/docs/evidence/README.md +++ b/docs/evidence/README.md @@ -14,7 +14,7 @@ блокирует сборку. - **runtime** — проверка на реально поднятом стеке. Быстрый smoke (`scripts/ldd-smoke.sh`) выполняется в CI на каждом push/MR; полный - runtime/scale — в `release-evidence` и обязателен перед релизом. + runtime/scale — в workflow `release` и обязателен перед релизом. ## Реестр @@ -40,7 +40,7 @@ # 2. Гейт свидетельств (P0 без evidence = fail) ./gradlew evidenceCheck -# 3. Быстрый smoke полного стека (то же, что CI job smoke) +# 3. Быстрый smoke полного стека (то же, что workflow smoke) ./scripts/ldd-smoke.sh # 4. Полный runtime-smoke + scale load на одноразовой БД @@ -101,9 +101,9 @@ LDD-циклы выполнены 2026-10-27/28; последний — посл все зелёные; - масштабный load: 100 групп / 1000 студентов, 125 параллельных чтений, 0 ошибок, p95 < 1 с (порог p95 < 2 с); -- CI: job `smoke` (`ldd-smoke.sh`) на каждом push/MR; полный - `release-evidence` (`ldd-release.sh`) обязателен для тегов и ручной для - веток. +- CI: Gitea + Woodpecker, workflow `smoke` (`ldd-smoke.sh`) на каждом push/MR; + полный `release` (`ldd-release.sh`) обязателен для тегов и ручной для веток. + Установка — `deploy/WOODPECKER.md`. В ходе E2E найден и исправлен реальный дефект: Jackson 3 не применял Kotlin-модуль, поэтому DTO с default-значениями требовали все поля JSON diff --git a/docs/evidence/baseline-2026-10-27.md b/docs/evidence/baseline-2026-10-27.md index 1838b4a..ae7b1f0 100644 --- a/docs/evidence/baseline-2026-10-27.md +++ b/docs/evidence/baseline-2026-10-27.md @@ -87,7 +87,7 @@ identity `V4–V13`, academic `V6–V12`, progress `V13`. ```bash ./scripts/ldd-runtime.sh -./scripts/ldd-smoke.sh # то же, что CI job smoke +./scripts/ldd-smoke.sh # то же, что CI workflow smoke ``` Сценарий: одноразовая БД, `bootJar`, запуск identity/academic/progress/gateway/web, @@ -106,8 +106,9 @@ identity `V4–V13`, academic `V6–V12`, progress `V13`. материалы анонимно — `401`. `ldd-smoke.sh` выполняет тот же полный стек, health, вход админа и один -доменный сценарий; это обязательный job `.gitlab-ci.yml` на каждом push/MR, -поэтому базовый runtime-контур проверяется до merge, а не только перед релизом. +доменный сценарий; это обязательный workflow `.woodpecker/smoke.yaml` на +каждом push/MR, поэтому базовый runtime-контур проверяется до merge, а не +только перед релизом. Результат: **PASS**, evidence: `build/evidence/runtime.json` и `build/evidence/smoke.json`. @@ -232,17 +233,17 @@ advisory lock): два одновременных apply идемпотентны `./scripts/ldd-release.sh` последовательно запускает тесты/линтеры, upgrade, mutation, runtime + scale и browser E2E, затем финальный `evidenceCheck`. -В `.gitlab-ci.yml`: +В `.woodpecker/` (Gitea + Woodpecker 3.x): - `check` — `test ktlintCheck detekt evidenceCheck` на push/MR; - `smoke` — `ldd-smoke.sh` (полный стек, health, вход админа, один курс) - на каждом push/MR; -- `release-evidence` — полный `ldd-release.sh` с Chromium/Firefox/WebKit и - Node: обязателен для тегов, для веток запускается вручную. + на каждом push/MR, после `check`; +- `release` — полный `ldd-release.sh` с Chromium/Firefox/WebKit и Node: + обязателен для тегов, для веток запускается вручную. - smoke/release начинаются с `scripts/ci-preflight.sh`, который проверяет Java 21, Docker Compose v2, Python 3, Node и Playwright. -- Первый реальный прогон на GitLab shell-runners ещё не подтверждён; локальные - скрипты и конфигурация проверены. +- Первый реальный прогон на Woodpecker-агенте ещё не подтверждён; локальные + скрипты и конфигурация проверены, установка — `deploy/WOODPECKER.md`. ### 2.12. Найденный дефект @@ -291,9 +292,10 @@ optional json fields`. это не N+1 по студентам, но и не пакетная выборка. 6. **Инвентаризация legacy-активов на production не выполнена.** UI, API и скрипт готовы, но реальные файлы нужно привязать или удалить вручную. -7. **Первый CI-прогон не подтверждён.** Конфигурация и preflight готовы, но - наличие shell-runners `lms-shell`/`lms-release` проверяется в GitLab. -8. **Полный release-evidence не на каждом коммите.** На push/MR идёт smoke, +7. **Первый CI-прогон не подтверждён.** Конфигурация `.woodpecker/` и + preflight готовы, но Woodpecker-сервер и local-backend агент ещё нужно + развернуть и проверить на первом push-MR и теге. +8. **Полный release не на каждом коммите.** На push/MR идёт smoke, а mutation/browser/scale — для тегов или вручную. 9. **Интеграция «Контингент» исключена из плана** — без нового ТЗ и доступа к API она не проверялась и не реализуется. @@ -312,7 +314,7 @@ optional json fields`. 1. прогнать инвентаризацию legacy-активов на production/staging через `/admin/legacy-assets` или `scripts/legacy-assets.sh` и привязать/удалить найденные файлы; -2. подтвердить первый реальный CI-прогон на shell-runners и tag-job; +2. развернуть Woodpecker и подтвердить первый push-MR pipeline и tag-job; 3. при необходимости расширить E2E на визуальную регрессию и остальные мобильные страницы; 4. пакетно отдавать сдачи в ведомости, если появятся медленные курсы. diff --git a/scripts/ci-preflight.sh b/scripts/ci-preflight.sh index c4fdaad..da79cdf 100755 --- a/scripts/ci-preflight.sh +++ b/scripts/ci-preflight.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -# Проверка окружения shell-runner перед smoke/release. Ничего не устанавливает. +# Проверка окружения Woodpecker-агента (local backend) перед check/smoke/release. +# Ничего не устанавливает. set -euo pipefail cd "$(dirname "$0")/.." @@ -75,6 +76,18 @@ else fail "python3: не найден в PATH" fi +if command -v git >/dev/null 2>&1; then + ok "git: $(git --version 2>&1 | head -n 1)" +else + fail "git: не найден в PATH" +fi + +if command -v ss >/dev/null 2>&1; then + ok "ss: $(ss -V 2>&1 | head -n 1)" +else + fail "ss: не найден в PATH (установите iproute2)" +fi + if ((release)); then if command -v node >/dev/null 2>&1; then ok "node: $(node --version 2>&1 | head -n 1)"