The release job now creates the Gitea release right after verification with generated notes: Android build status, changes grouped by Conventional Commit type with commit links, server update steps and APK install/check notes. The android job attaches the APK and .sha256 and rewrites only the status block (building / built with size, versionCode and SHA-256 / failed with a log link). scripts/release.mjs is idempotent on re-runs and unit-tested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.1 KiB
CI/CD (Gitea Actions)
Workflows лежат в .gitea/workflows/. Синтаксис совместим с GitHub Actions; runner — существующий act_runner
с доступом к Docker.
Сборке APK нужно ~15 ГБ свободного места на хосте раннера (Android SDK, NDK ~2.5 ГБ, кэш Gradle,
C++-сборка React Native). APK собирается только под arm64-v8a. Если job падает с No space left on device,
освободите место на хосте раннера: docker system prune -af и старые кэши act в ~/.cache/act.
Версионирование
- SemVer, тег
vMAJOR.MINOR.PATCH(предрелизы:v1.2.0-rc.1— помечаются как pre-release, мобильное их предлагает только при включённой настройке «бета-версии»). - Одна версия на весь продукт: образы, APK и веб собираются с одним номером.
- Android
versionCode = MAJOR·1 000 000 + MINOR·10 000 + PATCH·100 + (99 для релиза | N для -rc.N), так что1.2.0-rc.1 < 1.2.0-rc.2 < 1.2.0 < 1.2.1; MINOR и PATCH ≤ 99. Считаетscripts/version.mjs(тесты —pnpm test:scripts). - Changelog —
git-cliffиз Conventional Commits.
ci.yml — на каждый push и PR
on:
push: { branches: [main] }
pull_request:
jobs:
changes: # фильтр путей: api / recommender / web / mobile / packages / docs
contract: # spectral lint openapi.yaml; регенерация Go + TS клиентов; git diff --exit-code
api: # go vet, golangci-lint, go test -race ./... (testcontainers), покрытие
recommender: # uv sync; ruff; mypy --strict; pytest (вкл. оффлайн-оценку качества)
ts: # pnpm install --frozen-lockfile; turbo lint typecheck test; i18n:check
web-build: # vite build, проверка размера бандла
docker: # сборка всех Docker-образов без push (сервер собирает их сам — ADR-013)
mobile-check: # tsc, jest, expo prebuild + ./gradlew assembleDebug (только если менялся mobile/)
e2e: # needs: api, web-build; docker compose -f deploy/compose.test.yaml up; playwright test
- Кэши: Go modules / build cache, pnpm store, uv cache, Gradle, сгенерированные тестовые аудио.
- Ветка
mainзащищена: обязательныcontract,api,recommender,ts,e2e. - Ночью (
schedule) — Maestro E2E на эмуляторе и полный прогон без фильтров путей.
release.yml — по тегу
on:
push:
tags: ['v*.*.*']
jobs:
verify: # все проверки ci.yml
release: # needs: verify — сразу создаёт Gitea Release (scripts/release.mjs create)
android: # needs: verify, release — собирает APK и докладывает его в релиз
Релиз появляется сразу после проверок, не дожидаясь APK. Текст строит scripts/release.mjs:
- статус Android вверху: «⏳ собирается» со ссылкой на ход сборки → «✅ собран» (имя файла, размер, versionCode, SHA-256; предупреждение, если подпись отладочная) или «❌ не удалась» со ссылкой на лог;
- изменения — коммиты (Conventional Commits) с прошлого тега по разделам «Новое», «Исправления»,
«Сборка и CI» и т. д., отдельно — несовместимые (
feat!:); для финального релиза отсчёт от прошлого финального, а не от последнего-rc; ссылка на полный diff; - обновление сервера — бэкап,
./update.sh vX.Y.Z, проверка версии; установка APK и проверка SHA-256.
Job android: Android SDK, expo prebuild, ./gradlew assembleRelease (только arm64-v8a), подпись apksigner,
затем release.mjs android success <apk> прикладывает APK и .sha256 и меняет статус. При любом сбое —
release.mjs android failure. Перезапуск job безопасен: статус снова «собирается», файлы заменяются.
Перезапуск всего workflow обновляет текст существующего релиза, а не создаёт второй.
Docker-образы не публикуются: сервер собирает их сам из клонированного репозитория (ADR-013).
Чтобы сборка на сервере не ломалась, job docker в ci.yml собирает все образы без push на каждый PR.
Секреты
| Секрет | Назначение |
|---|---|
RELEASE_TOKEN |
Создание и редактирование релиза, загрузка ассетов (scope write:repository) |
ANDROID_KEYSTORE_BASE64, ANDROID_KEYSTORE_PASSWORD, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD |
Подпись APK. Ключ один на всю жизнь приложения — хранить резервную копию вне Gitea. Без них финальный релиз падает; -rc собирается с отладочной подписью. |
Деплой
Автодеплой не обязателен. На сервере в клоне репозитория: deploy/update.sh [vX.Y.Z] — checkout тега,
docker compose build и up -d; миграции применяются при старте api (install-guide.md).
Опционально — job deploy в release.yml по SSH на сервер для не-pre-release тегов (с ручным approval через environment).