ప్రోహోస్టర్ > బ్లాగ్ > పరిపాలన > మొబైల్ CICD అనుభవం: అనేక మొబైల్ అప్లికేషన్ల కోసం ఒక ఫాస్ట్లేన్ ప్రమాణం
మొబైల్ CICD అనుభవం: అనేక మొబైల్ అప్లికేషన్ల కోసం ఒక ఫాస్ట్లేన్ ప్రమాణం
Я бы хотела поговорить о непрерывной интеграции и доставке для мобильных приложений с помощью fastlane. Как мы внедряем CI/CD на все мобильные приложения, как мы к этому шли и что получилось в итоге.
В сети уже достаточно материала по инструменту, которого так не хватало нам на старте, поэтому я намеренно не буду подробно описывать инструмент, а лишь сошлюсь на то, что было у нас тогда:
Техническое решение раскатки CI/CD на N-приложений
Первая часть — больше ностальгия по былым временам, а вторая же — опыт, который можно применить у себя.
Так исторически сложилось
సంవత్సరం 2015
Мы только начали заниматься разработкой мобильных приложений, тогда еще мы ничего не знали про непрерывную интеграцию, про DevOps и другие модные штуки. Каждое обновление приложения выкатывал сам разработчик со своей машины. И если для Android это достаточно просто — собрал, подписал .apk и закинул в Google Developer Console, то для iOS тогдашний инструмент дистрибуции через Xcode оставлял нам шикарные вечера — попытки загрузить архив часто заканчивались ошибками и приходилось пробовать еще раз. Получалось, что самый прокачанный разработчик несколько раз в месяц не пишет код, а занимается релизом приложения.
సంవత్సరం 2016
Мы подросли, за плечами уже были мысли о том, как освободить разработчиков от целого дня для релиза, а так же появилось второе приложение, что только сильнее нас подталкивало к автоматизации. В тот же год мы впервые поставили Jenkins и написали кучку страшненьких скриптов, очень похожих на те, что показывает fastlane в своей документации.
К сожалению, о том как эти скрипты работают и для чего нужна эта нескончаемая пачка ключей до сих пор знали только наши разработчики, а когда что-то в очередной раз ломалось, «шикарные вечера» для разборов логов им же и доставались.
సంవత్సరం 2017
В этот год мы узнали, что есть такая штука как fastlane. Было не так много информации, как сейчас — как завести, как использовать. Да и сам инструмент был тогда еще сыроват: постоянные ошибки, только разочаровывали нас и в волшебную автоматизацию, которую они обещали, верилось с трудом.
Однако основные утилиты, входящие в ядро fastlane, — gym и pilot, у нас получилось завести.
Облагородились хотя бы потому, что не все параметры, необходимые для xcodebuild, нужно указывать — gym самостоятельно поймет где и что лежит. А для более тонкой настройки можно указать те же самые ключи, что и в xcodebuild, только нейминг ключей понятнее.
На этот раз, благодаря gym и встроенному форматеру xcpretty, логи сборки стали намного разборчивее. Это стало экономить время на починку сломанных сборки, а иногда в этом могла самостоятельно разобраться релиз-команда.
К сожалению, замеров по скорости сборки xcodebuild и gym мы не сделали, но будем верить документации — до 30% ускорения.
Единый процесс на все приложения
Год 2018 и настоящее время
К 2018 году сам процесс сборки и выкатки приложений полностью переехал на Jenkins, разработчики перестали релизить со своих машин, право на релиз имела только релиз-команда.
Нам уже захотелось докрутить запуск тестов и статический анализ, а наши скрипты росли и росли. Росли и менялись вместе с нашими приложениями. На тот момент приложений было около 10. Учитывая, что платформы у нас две — это порядка 20 «живущих» скриптов.
Каждый раз, когда мы хотели добавить новый шаг в скрипт, приходилось копипастить кусочки во все shell-скрипты. Возможно, можно было работать и поаккуратнее, но часто такие изменения заканчивались опечатками, которые уже превращались в вечера релиз-команды на починку скриптов и выяснения, кто из умников добавил эту команду и что она вообще делает. В целом, нельзя сказать что скрипты для сборки под одну платформу были хоть сколько-нибудь похожими. Хотя безусловно делали одно и тоже.
Для того чтобы завести процесс для нового приложения — нужно было потратить день, чтобы подобрать «свежую» версию из этих скриптов, отладить и сказать что «да, работает».
Летом 2018 мы еще раз посмотрели в сторону все еще развивающегося fastlane.
Задача №1: обобщить все шаги скриптов и переписать их в Fastfile
Когда мы начинали, наши скрипты выглядели портянкой из всех шагов и костылей в одном shell-скрипте в Jenkins. Мы еще не перешли на pipeline и деление по stage.
Посмотрели на то что есть и выделили 4 шага, подходящих под описание нашего CI/CD:
build — установка зависимостей, сборка архива,
test — запуск unit-тестов разработчика, подсчет покрытия,
sonar — запуск всех линтеров и отправка отчетов в SonarQube,
deploy — отправка артефакта в альфу (TestFlight).
И если не вдаваться в подробности, опустить используемые ключи у actions, получится вот такой Fastfile:
default_platform(:ios)
platform :ios do
before_all do
unlock
end
desc "Build stage"
lane :build do
match
prepare_build
gym
end
desc "Prepare build stage: carthage and cocoapods"
lane :prepare_build do
pathCartfile = ""
Dir.chdir("..") do
pathCartfile = File.join(Dir.pwd, "/Cartfile")
end
if File.exist?(pathCartfile)
carthage
end
pathPodfile = ""
Dir.chdir("..") do
pathPodfile = File.join(Dir.pwd, "/Podfile")
end
if File.exist?(pathPodfile)
cocoapods
end
end
desc "Test stage"
lane :test do
scan
xcov
end
desc "Sonar stage (after run test!)"
lane :run_sonar do
slather
lizard
swiftlint
sonar
end
desc "Deploy to testflight stage"
lane :deploy do
pilot
end
desc "Unlock keychain"
private_lane :unlock do
pass = ENV['KEYCHAIN_PASSWORD']
unlock_keychain(
password: pass
)
end
end
На самом деле, первый Fastfile у нас получился монструозным, учитывая некоторые костыли, которые нам все еще были нужны, и количество параметров, которые мы подставляли:
lane :build do
carthage(
command: "update",
use_binaries: false,
platform: "ios",
cache_builds: true)
cocoapods(
clean: true,
podfile: "./Podfile",
use_bundle_exec: false)
gym(
workspace: "MyApp.xcworkspace",
configuration: "Release",
scheme: "MyApp",
clean: true,
output_directory: "/build",
output_name: "my-app.ipa")
end
lane :deploy do
pilot(
username: "[email protected]",
app_identifier: "com.example.app",
dev_portal_team_id: "TEAM_ID_NUMBER_DEV",
team_id: "ITS_TEAM_ID")
end
На примере выше, только часть параметров, которые нам нужно указать: это параметры сборки — схема, конфигурация, названия Provision Profile, а также параметры дистрибуции — Apple ID аккаунта разработчика, пароль, идентификатор приложения и так далее. В первом приближении, мы положили все эти ключи в специальные файлы — Gymfile, Matchfile и Appfile.
Теперь в Jenkins можно вызывать короткие команды, которые не «замыливают» взгляд и хорошо считываются глазом:
Что получили? Понятные команды для каждого шага. Причесанные скрипты, аккуратно разложенные в файлы fastlane. Обрадовавшись, мы было побежали к разработчикам с просьбой добавить все что нужно в свои репозитории.
Но вовремя осознали, что столкнемся с теми же сложностями — у нас все еще будет 20 скриптов сборки, которые так или иначе начнут жить своей жизнью, править их будет сложнее, так как скрипты переедут в репозитории, а у нас доступа туда нет. И, в общем, решить нашу боль таким образом не получится.
Задача №2: получить единый Fastfile для N-приложений
Сейчас уже кажется, что решить задачу не так уж и сложно — задайте переменные, и поехали. Да, собственно, так задачу и решили. Но в тот момент, когда мы это вкручивали, у нас не было ни экспертизы в самом fastlane, ни в Ruby, на котором написан fastlane, ни полезных примеров в сети — каждый, кто писал про fastlane тогда, ограничивался примером для одно приложения для одного разработчика.
Fastlane умеет в переменные окружения, и это мы уже попробовали, задав пароль от Keychain:
ENV['KEYCHAIN_PASSWORD']
Посмотрев на наши скрипты, мы выделили общие части:
#for build, test and deploy
APPLICATION_SCHEME_NAME=appScheme
APPLICATION_PROJECT_NAME=app.xcodeproj
APPLICATION_WORKSPACE_NAME=app.xcworkspace
APPLICATION_NAME=appName
OUTPUT_IPA_NAME=appName.ipa
#app info
APP_BUNDLE_IDENTIFIER=com.example.appName
[email protected]
TEAM_ID=ABCD1234
FASTLANE_ITC_TEAM_ID=123456789
Теперь для того, чтобы начать использовать эти ключи в файлах fastlane’а, нужно было придумать как их туда доставлять. У Fastlane есть для этого решение: загрузка переменных через dotenv. В документации сказано, если вам важно подгружать ключи для разных целей, наплодите в директории fastlane несколько конфигурационных файлов .env, .env.default, .env.development.
И тогда мы решили использовать эту библиотеку немного по-другому. Поместим в репозитории разработчиков не скрипты fastlane и его мета информацию, а уникальные ключи этого приложения в файле .env.appName.
తాము Fastfile, Appfile, Matchfile и Gymfile, мы спрятали в отдельный репозиторий. Туда же спрятали дополнительный файл с ключами-паролями от других сервисов — .env.
Пример, можно посмотреть ఇక్కడ.
На CI вызов не сильно поменялся, добавился ключ конфигурации конкретного приложения:
Пока оставили это решение, хотя у Fastlane есть решение для загрузки Fastfile через చర్యimport_from_git, но он работает только для Fastfile, для остальных же файлов — нет. Если хочется «прям совсем красиво», можно написать свой action.
Аналогичный набор сделали для Android приложений и ReactNative, файлы лежат в одном репозитории, но в разных ветках iOS, android и react_native.
Когда релиз команда хочет добавить какой-нибудь новый шаг, изменения в скрипте фиксируются через MR в git, больше не надо искать виновников поломанных скриптов, да и в целом — сломать теперь, это надо постараться.
Теперь точно все
Раньше мы тратили время на поддержку всех скриптов, их обновление и починку всех последствий обновлений. Было очень обидно, когда причины ошибок и простоев релизов были простыми опечатками, за которыми так сложно уследить в мешанине shell-скрипта. Теперь же такие ошибки сведены к минимуму. Изменения накатываются сразу на все приложения. А новое приложение завести в процесс стоит 15 минут — настроить шаблонный pipeline на CI и добавить ключи в репозиторий разработчика.
Кажется, остался неосвещенным пункт с Fastfile для Android и подпись приложений, если статья будет интересна, напишу продолжение. Буду рада вашим вопросам или предложениям «как бы вы решили эту задачу» в комментариях или в Telegram bashkirova.