CI/CD
Overview
Этот репозиторий рассматривается как frontend-only Kotlin Multiplatform проект.
- единственный Gradle module в репозитории:
:composeApp; - CI валидирует Android app и shared KMP code;
- backend checkout не требуется для обычной CI-сборки клиента;
- для сборки используются временные stub config files вместо локальных developer secrets.
Workflow
Главный workflow:
.github/workflows/mobile-app-ci-cd.yml
В нем четыре job:
Android CIiOS Kotlin ValidationPublish App Showcase ImagePublish Android Update Release
Отдельный workflow для документации:
.github/workflows/docs-site-pages.yml
Он:
- собирает Docusaurus site из
website/; - публикует
website/buildв GitHub Pages; - срабатывает на push в
mainпри изменениях вwebsite/**,README.mdили самом workflow.
Production URL документации:
https://citec-spbu.github.io/itClinicApp/
Pull Requests
На pull request запускается Android CI на ubuntu-latest.
Шаги:
./gradlew :composeApp:lintDebug --stacktrace./gradlew :composeApp:testDebugUnitTest --stacktrace./gradlew :composeApp:clean :composeApp:assembleDebug
Артефакты:
- Android lint reports;
- Android unit test reports;
- delivery artifacts из
release-artifacts/.
Main and develop
Push в default branch продолжает запускать Android CI.
Push в default branch и develop также запускает:
iOS Kotlin Validation
Эта job выполняет:
./gradlew :composeApp:compileKotlinIosSimulatorArm64 --stacktrace
Это держит KMP iOS target компилируемым без code signing, Xcode automation и backend runtime.
Push в default branch дополнительно запускает:
Publish App Showcase ImagePublish Android Update Release
Tags and releases
Теги вида v* запускают:
Android CIiOS Kotlin ValidationPublish App Showcase ImagePublish Android Update Release
Release job создает или обновляет GitHub Release для тега и публикует:
release-artifacts/itclinicapp-release.apkrelease-artifacts/android-update.jsonstable.jsonchannel manifest в веткуandroid-updates
Android update delivery
CD-путь публикует:
- signed release APK;
android-update.json;- channel manifest (
beta.jsonилиstable.json); - rolling prerelease для main builds или полноценный tagged release.
Android-клиент:
- считывает manifest для канала;
- сравнивает
versionCode; - скачивает APK;
- проверяет SHA-256 checksum;
- передает файл системному инсталлеру.
GHCR showcase image
Image публикуется как:
ghcr.io/<owner>/itclinicapp-showcase
Image содержит:
- lightweight static landing page;
- CI-собранный APK;
android-update.json.
Secrets and variables
Обязательные GitHub Secrets:
ANDROID_RELEASE_KEYSTORE_BASE64ANDROID_RELEASE_STORE_PASSWORDANDROID_RELEASE_KEY_ALIASANDROID_RELEASE_KEY_PASSWORD
Используемый built-in token:
GITHUB_TOKEN
Он нужен для:
- публикации GHCR image;
- создания и обновления GitHub Releases;
- загрузки release assets;
- обновления ветки
android-updates.
Опциональные GitHub Variables:
ANDROID_BETA_MIN_SUPPORTED_VERSION_CODEANDROID_BETA_FORCE_UPDATEANDROID_STABLE_MIN_SUPPORTED_VERSION_CODEANDROID_STABLE_FORCE_UPDATE
CI helper scripts
Workflow опирается на:
scripts/prepare_ci_stubs.shscripts/prepare_mobile_showcase.shscripts/generate_android_update_manifest.shscripts/resolve_android_update_changelog.sh
Поведение changelog:
- если
release-notes/android-update-notes.txtизменился относительноHEAD^, каждая непустая строка становится changelog item; - пустые строки и строки с
#игнорируются; - если файл не менялся в текущем commit, published changelog будет пустым.
Local commands that mirror CI
./gradlew :composeApp:lintDebug
./gradlew :composeApp:testDebugUnitTest
./gradlew :composeApp:clean :composeApp:assembleDebug
./gradlew :composeApp:compileKotlinIosSimulatorArm64
Local config in CI context
Ожидаемые локальные файлы:
composeApp/src/commonMain/kotlin/com/spbu/projecttrack/BuildConfig.ktcomposeApp/src/commonMain/kotlin/com/spbu/projecttrack/MailConfig.kt
Они:
- игнорируются Git;
- принадлежат разработчику;
- не должны быть обязательны для прохождения CI.
Шаблоны:
composeApp/src/commonMain/kotlin/com/spbu/projecttrack/BuildConfig.example.ktcomposeApp/src/commonMain/kotlin/com/spbu/projecttrack/MailConfig.example.kt
Важное поведение scripts:
prepare_ci_stubs.shне должен перетирать локальные конфиги вне CI;prepare_mobile_showcase.shвременно генерирует CI-safe stubs для artifact preparation и затем восстанавливает существующие локальные конфиги.
Docker image usage
Pull:
docker pull ghcr.io/<owner>/itclinicapp-showcase:latest
Run:
docker run --rm -p 8080:80 ghcr.io/<owner>/itclinicapp-showcase:latest
Специфичный tag:
docker run --rm -p 8080:80 ghcr.io/<owner>/itclinicapp-showcase:<tag>
После старта контейнера доступны:
http://localhost:8080/http://localhost:8080/release-artifacts/itclinicapp-release.apkhttp://localhost:8080/release-artifacts/android-update.json
Если GHCR package private:
echo <PAT> | docker login ghcr.io -u <github_username> --password-stdin
Токену нужен scope:
read:packages
Troubleshooting
Missing BuildConfig or MailConfig
Если сборка в CI падает с unresolved references на BuildConfig или MailConfig, проверьте:
scripts/prepare_ci_stubs.sh- step
Prepare CI stubsв workflow
Duplicate dex classes during assembleDebug
Если Android packaging падает на duplicate dex entries вроде *.dex и * 2.dex, локальный build directory stale.
Используйте:
./gradlew :composeApp:clean :composeApp:assembleDebug
GHCR unauthorized
Типовые причины:
- image еще не публиковался;
- GHCR package private.
GHCR no matching manifest for linux/arm64/v8
Новые публикации поддерживают:
linux/amd64linux/arm64
Если старый tag не тянется на Apple Silicon, скорее всего он был выпущен до multi-arch support.
Android in-app update check does not show anything
Проверьте, что CD действительно опубликовал:
itclinicapp-release.apkandroid-update.json- нужный channel manifest в
android-updates
Также важно:
- repo должен быть публично читаемым для anonymous checks;
- versionCode установленного APK должен быть ниже manifest versionCode;
- update checks throttled и не дергают GitHub на каждой recomposition;
- update APK должен быть подписан тем же release keystore.
Frontend-only limitations
- workflow не клонирует и не собирает backend repository;
- backend containers не нужны для CI;
- APK из CI собран со stub config, а не с developer secrets;
- iOS artifacts не превращаются в signed app bundle или TestFlight package;
- Android updates завязаны на GitHub metadata, а не на отдельный backend.
Manual setup that still remains
- Android release signing
- Play Store publishing
- iOS code signing and distribution
- making GHCR package public if needed
- keeping repository or release channel public for anonymous Android update checks
- replacing CI stub config with real runtime config в local developer environments