Repository navigation
Testing and the Gate ru
English · Русский
kotlin("test") на бэкенде JUnit 5. Ни Kotest, ни MockK, ни ktlint — фейки написаны руками, а
роль линта играет Android lint внутри ./gradlew build. Покрытие — Kover
(./gradlew koverHtmlReport).
./gradlew test allTests # один `test` пропускает мультиплатформенные модулиТесты живут в commonTest, если поведение не по-настоящему платформенное; UI-тесты используют
оболочку-харнесс из Слоя UI и требуют дисплея (в CI — xvfb-run --auto-servernum).
- RED — сначала падающий тест, и убедиться, что он падает по задуманной причине, а не на ошибке компиляции.
-
GREEN — минимальная реализация: контракты в
commonMain, платформенные библиотеки заexpect/actual, осиротевший код удалён тем же коммитом. - Гейт — стадии, которые изменение реально должно.
- Ревью — фан-аут агентов.
Новый тест перепрогоняется с откаченным фиксом — доказать, что он действительно ловит регрессию.
tools/harness/ не доверяет циклу, а обеспечивает его:
tools/harness/gate.py status # что это за изменение и что оно ещё должно
tools/harness/gate.py run # прогнать ровно то, что должно, по порядку
tools/harness/gate.py red --tests '*Pattern*' --file path/to/Test.kt
tools/harness/gate.py task bug 133 # переопределить автоопределённый вид
tools/harness/gate.py reviewers # какие ревьюверы нужны этому изменениюЧто изменение должно, зависит от того, что оно такое:
| Вид | Как определяется | Что должен |
|---|---|---|
docs |
в диффе нет кода | ничего |
refactor |
ветка refactor/ chore/ perf/
|
checks · tests · build · detekt · ревьюверы |
feature |
ветка feat/ или безымянная ветка с кодом |
то же плюс тронутый тест |
bug |
ветка fix/ bug/ hotfix/ либо объявлено |
то же плюс тест, записанный падающим до фикса |
Области добавляют стадии: UI или Android в диффе подтягивают :androidApp:compileDebugKotlin,
серверная работа — java-ревьювера, терминальная — ревьювера производительности. Объявление может
сделать гейт строже, но никогда — слабее.
Раннер выполняет стадию, читает код возврата и пришпиливает результат к дайджесту дерева, на котором он выполнялся. Ручной прогон Gradle не записывается — не потому, что ручные прогоны запрещены, а потому, что ничто вне раннера не может доказать, какому коду принадлежал код возврата. Любая правка после этого переоткрывает гейт, потому что дайджест сдвинулся; коммит не переоткрывает, а откат изменения возвращает то зелёное состояние, которое было.
Стадии: checks (детерминированные правила проекта), tests, build (с линтом), detekt и
android, когда дифф трогает UI. Логи — в .git/skerry-gate/<стадия>.log.
detekt валится только на новых находках; существующие лежат в gradle/detekt-baseline-*.xml, и
перебазировать их, чтобы заглушить собственную находку, нельзя.
Осознанный обход — SKERRY_GATE_OVERRIDE=1, и он означает, что причина проговаривается вслух. От
защиты main он не освобождает.
У самой обвязки есть тесты: python3 tools/harness/selftest.py (~70 случаев, две секунды, без
Gradle). Меняешь правило — меняешь и их.
tools/harness/checks.py блокирует коммит на правилах, не требующих суждения: переводы полны в
en + ru + zh, нет захардкоженного текста UI, Txt/Sym вместо сырых Text/Icon, дизайн-токены
вместо hex, нет Kotest и MockK, зависимости через version catalog, atomicWriteUtf8 на путях с
секретами, у нового хоткея есть строка в настройках.
Когда ветка зелёная, ревьюверы идут параллельно по git diff main...HEAD плюс рабочее дерево:
| Ревьювер | Что ищет |
|---|---|
skerry-reviewer |
собственные правила проекта — паритет, примитивы, хранилище, каталог абстракций |
skerry-kotlin-reviewer |
структурная конкурентность, рекомпозиция Compose, идиомы Kotlin для этого стека |
skerry-security-reviewer |
хранилище и его криптография, недоверенный ввод протоколов, граница sync/команд |
silent-failure-hunter |
проглоченные исключения, плохие фолбэки, ошибки, которые никуда не всплывают |
pr-test-analyzer |
покрывают ли тесты поведение, а не строки |
Первые три лежат в .claude/agents/, поэтому фан-аут приезжает вместе с клоном. Правила:
ревьюверы только читают, никогда не переключают ветки, каждая находка либо чинится, либо явно
отклоняется с причиной, фикс, меняющий поведение, возвращается к шагу 1, и два круга на ветку —
третий запрашивает мейнтейнер. Находки складываются в .git/skerry-gate/reviews/.
| Workflow | Триггер | Что делает |
|---|---|---|
ci.yml |
пуши и PR | JDK 21, Android SDK, test allTests под xvfb-run, detekt, выгрузка отчётов |
release.yml |
тег v* (или вручную) |
собирает .deb/.rpm/.AppImage (x64 + arm64), .msi, .dmg (arm64 + x64), подписанный .apk и SHA256SUMS.txt, публикует черновик релиза |
server-image.yml |
тег server-v*
|
собирает мультиархитектурный образ сервера, дымовым тестом проверяет, что контейнер стал healthy, пушит в Docker Hub |
codeql.yml |
по расписанию и на PR | сканирование кода |
CI не заменяет локальный гейт: он гоняет те же тесты, но именно гейт связывает зелёный результат с тем самым деревом, которое коммитится.
User guide
- Installation
- Getting started
- Hosts and connections
- Vault and credentials
- Terminal
- Files (SFTP)
- Port forwarding
- Remote desktops
- Snippets and runbooks
- Monitoring and guard
- AI assistant
- Sync and devices
- Teams and sharing
- Settings and shortcuts
- Android
- Troubleshooting
Development
- Architecture
- Building and running
- Connections and transports
- Terminal engine
- Vault and crypto
- Sync protocol
- Remote desktop stacks
- UI layer
- Testing and the gate
- Contributing and releases
Русский — оглавление