Разработка¶
Что нужно¶
- macOS
- CocoaPods
- Android Studio
- Python 3 с
lxml— для справочника MapKit
Справочник MapKit¶
В ymk-docs/ лежит офлайн-копия справочника Яндекс MapKit — источник истины по сигнатурам, которые
повторяет обёртка. Копия генерируется и в репозитории не хранится, поэтому после клонирования её
нужно собрать:
python3 ymk-docs/_tools/bootstrap.py
Скрипт скачивает около 2000 страниц с yandex.ru/maps-api/docs/mapkit и конвертирует их в Markdown —
это пара минут. Он идемпотентен: если копия уже собрана, ничего не делает. --validate добавляет
проверки покрытия и ссылок, --force пересобирает заново, --refresh качает страницы вместо того,
чтобы брать кеш из ymk-docs/_tools/cache/.
Пересборка под новый релиз MapKit описана в ymk-docs/_tools/README.md.
Пример¶
Примеру нужен ваш API-ключ в local.properties:
MAPKIT_API_KEY=<API-KEY>
Ветки¶
main — единственная долгоживущая ветка. Ответвляйтесь от неё, открывайте pull request обратно в
неё и дайте проверкам отработать. Ветки release/X.Y.x появляются только тогда, когда исправление
нужно выпустить без всего остального, что уже попало в main.
Проверки¶
На каждый pull request параллельно запускаются четыре задачи — lint, test-android, test-ios и
api-check, — и все их можно воспроизвести локально:
./gradlew spotlessApply
./gradlew libraryAssemble libraryTests -PskipIosTarget=true
./gradlew libraryCompileIosArm64 libraryIosTests
./gradlew libraryApiCheck
Задачи library* разворачиваются на четыре публикуемых модуля. iOS-задачам нужен CocoaPods, и
libraryApiCheck тоже — дампы покрывают iOS-таргеты, поэтому он запускается только на macOS.
Тесты отрисовки Compose ждут настоящий кадр (GraphicsLayer → ImageBitmap), который JVM не
выдаёт, поэтому они исключены из Android-прогона на хосте и покрываются симулятором iOS плюс
отдельной задачей на эмуляторе. Эта задача запускается при пушах в main и ещё раз перед каждым
релизом:
./gradlew :yandex-mapkit-kmp-compose:connectedAndroidDeviceTest
Публичный API¶
Четыре публикуемых модуля хранят по два дампа своего публичного API в <module>/api. Любое
изменение публичного объявления валит libraryApiCheck, пока оба дампа не обновлены:
./gradlew libraryApiDump
Запускайте на macOS — дамп, сгенерированный без iOS-таргетов, неполон — и коммитьте результат вместе с изменением. Просмотр этого диффа — самый простой способ понять, меняет ли pull request API намеренно.
<module>.klib.api — klib-дамп от Kotlin ABI validator, он покрывает commonMain и iosMain.
Валидатор не подхватывает Android-таргет у com.android.kotlin.multiplatform.library, поэтому
<module>.android.api создаётся отдельно задачей dumpAndroidAbi: она прогоняет javap -public по
классам основной Android-компиляции и стережёт объявления, существующие только в androidMain, —
такие как MapKit.initialize(Context) и фабрики ImageProvider. Поскольку это дамп javap, он
чувствителен к JDK, которой был сгенерирован — используйте ту же версию JDK, что и CI.
Документация¶
Сайт — это MkDocs Material. Он собирается из docs/ и деплоится CI вместе с KDoc, который Dokka
рендерит в docs/kdoc.
pip install -r docs/requirements.txt
mkdocs serve
./gradlew :dokkaGenerate
Два языка¶
Каждая страница существует дважды, в
раскладке с суффиксом от mkdocs-static-i18n:
wrapper/overview.md — английская, wrapper/overview.ru.md — русская. Английский — язык по
умолчанию, за ним остаются «голые» URL; русский обслуживается по пути /ru/.
Страница без своего двойника .ru.md откатывается к английскому тексту, а не отдаёт 404, так что
новая страница может приехать на одном языке и быть переведённой позже — но pull request, который её
добавляет, должен добавлять обе. Заголовки разделов в nav переводятся в mkdocs.yml в блоке
nav_translations; новому пункту навигации нужна строка и там.
Версии подставляются, а не пишутся руками¶
Никогда не пишите номер версии в страницу. docs_hooks/versions.py читает gradle.properties и
gradle/libs.versions.toml во время сборки и заменяет такие подстановки:
| Подстановка | Источник |
|---|---|
{{ version }} |
library_version в gradle.properties |
{{ mapkit_version }} |
yandex-mapkit из каталога версий |
{{ kotlin_version }} |
kotlin из каталога версий |
{{ compose_version }} |
compose-plugin из каталога версий |
{{ min_sdk }} |
android-minSdk из каталога версий |
Неизвестная подстановка остаётся как есть, поэтому {{ something }} в примере кода уцелеет; а
известную можно экранировать ведущим обратным слешем — именно так написана эта таблица.
README не собирается MkDocs, поэтому его версии синхронизирует Gradle:
./gradlew updateDocumentedVersions
./gradlew checkDocumentedVersions
Проверка выполняется в задаче lint, поэтому поднятый library_version с устаревшим README валит
CI.
Совместимость¶
В пределах 1.x модули гарантируют совместимость исходников, а не бинарную совместимость.
Обёртка следует за MapKit, а MapKit добавляет поля в свои структуры и константы в свои перечисления
в минорных релизах. Обёртка отражает эти структуры как data class, поэтому новое поле меняет
componentN и copy$default, а новая константа перечисления ломает компиляцию исчерпывающего
when по нему. И то, и другое ломает бинарную совместимость, а отказ от них означал бы заморозку
обёртки на той версии MapKit, с которой вышла 1.0.0.
На практике это значит: пересобирайте под ту версию, от которой зависите, не смешивайте версии
обёртки в одном графе зависимостей и ждите, что после обновления when по перечислению обёртки
потребует новой ветки. Переименования, удаления и изменения сигнатур по-прежнему остаются за
мажорным релизом.
Релизы¶
Релизы описаны в RELEASING.md.
Заметные изменения попадают в раздел Unreleased файла
CHANGELOG.md в том же pull
request, который их вносит.