Всем привет! Меня зовут Даниил Хейфец, и я QA Lead мобильного направления в hh.ru. В этой статье я расскажу, как мы автоматизировали flow релиза мобильных приложений, как разбили его разработку на этапы, какие инструменты использовали и с какими проблемами столкнулись.
Это текстовая расшифровка видео вышедшего на нашем канале, посему если вам удобнее смотреть, а не читать, добро пожаловать на наш Youtube-канал.
В предыдущих сериях я уже рассказывал, как мы улучшали процессы релизов мобильных приложений, какие практики вводили, с какими проблемами сталкивались и к чему в итоге пришли.
В предыдущей серии
Мы перешли на GitHub flow, написали автотесты и запустили их на CI, запустили Release Train и ввели практику дежурства. Таким образом, мы добились стабильных, регулярных, еженедельных релизов. Но оставалось множество рутины, от которой нам бы хотелось избавиться.
Рутина
Всю рутину по релизу мобильных приложений можно разделить на две части: техническую и менеджерскую.
Техническая рутина:
создание ветки релиза
инкремент версии
выкладка в сторы
запуск автотестов
запуск сборки
Менеджерская рутина:
описание состава релиза
о чем надо написать в разделе «Что нового» в сторах
заведение задачи на маркетинг для написания текстов “Что нового”
Хоть всё это и несложные операции, они требуют человеческого участия. Соответственно, не исключены и самые обычные человеческие ошибки: кто-то что-то забыл, не сделал и тому подобное. Конечно, у нас были чек-листы и всяческие инструкции для таких ситуаций. Однако и это не спасало нас от маленьких, но неприятных проблем.
Чтобы исключить человеческий фактор, мы решили автоматизировать этот процесс, и задача показалась нам интересной.
Планирование работ
Прежде чем автоматизировать, мы решили визуализировать весь процесс нашего релиза: как он выглядит, какие принимает статусы, что приводит к изменению статусов.
Этапы, из которых состоит наш релизный флоу:
Создание релиза
Запуск автотестов
Запуск сборки (какой, кстати, сборки-то - релизной?)
Выкладка в Google Play / App Gallery / Apple Store
Закрытие релиза
Между этапами есть переходы и события, которые приводят к изменению статусов релиза. Здесь могут происходить как относительно безобидные события, так и настоящая беда. Например, если на проде нашёлся баг/выстрелил краш, нам нужно его исправить, снова прогнать автотесты, запустить пересборку приложения и заново его выложить. А ещё нас могут отклонить на ревью в сторе, и тогда снова придется проходить точно такой же цикл проверок и пересборок.
Наш план оказался достаточно универсальным, чтобы мы смогли описать его сразу для всех наших приложений (соискательское/работодательское), платформ (Android iOS) и сторов (Google Play/App Store/Huawei App Gallery).
Детализация работ
После описания процесса релиза мы решили детально проанализировать, какие конкретно действия будут выполняться на каждом из этапов. Покопались в наших чек-листах, инструкциях, ̶п̶о̶з̶в̶а̶л̶и̶ ̶ш̶а̶м̶а̶н̶а̶ ̶с̶ ̶б̶у̶б̶н̶о̶м̶ ̶п̶о̶к̶а̶м̶л̶а̶т̶ь̶ ̶ и описали все это на большой и подробной схеме.
Присмотревшись к схеме, мы поняли, что на каждом этапе выполняется определённый набор атомарных действий, которые по большей части не зависят друг от друга.
Например, на этапе создания релиза мы:
создаём отдельную ветку для будущего релиза
выполняем инкремент версии приложения
ищем список выполненных с момента прошлого релиза задач
просим маркетинг написать текст для будущего релиза на основе списка выполненных задач.
Каждому шагу мы присвоили свой приоритет: что-то мы хотели автоматизировать в первую очередь, что-то могло подождать, а что-то мы может и хотели бы автоматизировать, но пока что у нас не было возможности.
Отлично: этапы релиза понятны, действия на каждом этапе ясны, пора составить план, как это всё реализовать.
Начали мы с объяснения менеджменту, для чего нам нужна эта задача. Если мы сделаем эту задачу, это сэкономит нам кучу времени и избавит от ошибок при ручном управлении релизом. Мы чётко обозначили дедлайны для автоматизации каждого этапа. Это всё помогло нам увеличить приоритет задачи на автоматизацию, и мы наконец-то получили "добро".
За работу!
Реализация
Структура данных
В первую очередь мы определились, как собираемся хранить все данные. Мы решили, что опишем простую PostgreSQL-базу данных из двух таблиц: основная, в которой хранятся все данные о релизе (номер релиза, название ветки, дата создания, ссылка на тикет в Jira, статус релиза и т.п.), и вспомогательная — для информации о задачах маркетинга.
Окей, мы придумали, как будем хранить данные, теперь решим, как с ними взаимодействовать.
Визуализация данных
Типичный вторник в команде hh до автоматизаций релиза:
"А релизную ветку создали?"
"Автотесты прогнали?"
"А какая сейчас версия актуальная, памагите!"
"Где тексты для стора?!"
Как вы поняли, у нас была проблема — никто никогда не понимал, в каком статусе сейчас находится тот или иной релиз. Выложили ли приложения в стор? Раскатили ли уже старый релиз? Где актуальные тексты? Так много вопросов, так мало ответов.
Благодаря созданной нами БД у нас появился источник правды о релизах, но не ходить же в базу каждый раз, когда захочется посмотреть, что там происходит?
Так мы решили, что для визуализации данного процесса будем использовать тот инструмент, с которым обычно и работаем — Jira. Мы сделали доску, где каждая колонка символизировала тот или иной этап в нашем процессе релиза. Как то: запуск автотестов, что автотесты прошли, выкладка в сторы или раскатка на пользователей.
А также мы завели для этой доски специальный тип задач – "релиз". В эту задачу мы привязывали всю необходимую информацию, которую хотели бы знать о релизе: какой у него статус, прошли ли автотесты, ссылка на прогон этих автотестов, а также задачи, которые в него вошли.
Кроме этого, в задаче отображаются даты каждого этапа. Поэтому мы легко можем посмотреть, какого числа и в какое время был пройден каждый из них.
Таким образом, мы смогли визуализировать всю самую важную информацию о нашем релизе и нам не нужно для этого руками делать запросы к БД. Любой заинтересованный человек теперь может просто открыть доску в Jira и посмотреть, в каком статусе у нас тот или иной этап.
Как рулить релизом?
Но отображать состояние БД в Jira — это лишь часть задачи. Надо ещё и модифицировать её, а для этого нужно придумать схему, которая будет всем этим управлять.
Мы решили управлять нашими релизами всё из той же Jira. Передвигая тикет там, мы можем запускать тот или иной этап нашей автоматизации. При смене статуса задачи релиза, мы стартанем работу специального плана на CI, который и начнёт выполнять всю нужную работу.
Так как нашим CI-сервером является Bamboo от Atlassian, нам было довольно легко заставить всё это работать.
Остался лишь один вопрос – на чем писать скрипты автоматизации?
Мы изучили существующие инструменты и пришли к выводу, что удобнее всего нам будет использовать fastlane. Причин для такого выбора было несколько.
Во-первых, fastlane является, пожалуй, единственным удобным способом релизить и автоматизировать всё, что связано с приложениями под iOS. Кроме того, этот инструмент использовала iOS-команда в своих уже существующих автоматизациях.
Во-вторых, в fastlane существует много реализованных плагинов, action-ов, которые нужны для наших задач, а значит нам не придется писать всё с нуля.
В-третьих, fastlane умеет работать как с iOS-приложениями, так и с Android. Это позволит не писать автоматизацию под каждую платформу, а просто использовать единый инструмент, не дублировать код и в принципе сделать всё намного быстрее. Про использование fastlane-а для Android-а можно посмотреть нашу охэхэнную историю.
Что под капотом у релизного поезда
В нашей системе автоматизации получились четыре основные части: база данных PostgreSQL, CI-сервер Bamboo, сам fastlane и Jira.
Как я уже писал выше, благодаря легкой интеграции Jira и Bamboo мы сделали так, что при переносе тикета релизов Jira из одного статуса в другой, у нас запускается специальный план на Bamboo. А запускает его особый lane fastlane-а.
Каждый этап релиза в коде выглядит как отдельный lane fastlane, в котором определено всё, что нужно сделать на данном этапе релиза. Скрипт идёт в БД и определяет, в каком статусе находится последний существующий релиз. Статусов всего два: это EXIST или RELEASED. Если статус самого последнего релиза у нас – RELEASED, значит сейчас нет никакого релиза и надо создать новый. Если статус последнего релиза – EXIST, значит прямо сейчас идет процесс релиза. И нам необходимо сходить в Jira, чтобы уточнить этап.
Описание действий для каждого этапа релиза в коде выглядит как отдельный lane fastlane-а.
Все действия за время релиза можно разбить на четыре большие группы:
Работа с БД;
Работа с Jira;
Работа с GitHub;
Какие-то вспомогательные утилиты.
Для каждого типа задач мы описали в коде классы-обертки на Ruby. Для работы с Jira мы используем библиотеку Jira-ruby, а для работы с базой — стандартную библиотеку для работы с Postgres. Также написали свой небольшой клиент для отправки запросов в базу и обработки ошибок. Еще описали необходимые команды для гита и прочие утилиты. Например, код для отправки уведомлений в Slack.
Получился такой универсальный набор функций, который мы вынесли в общий репозиторий, и используем как в iOS, так и в Android. Мы создали такой подключаемый плагин, который используем при разработке в iOS-репозитории или в Android, чтобы избежать дублирования кода.
Что в итоге
Мы проделали довольно большую работу над автоматизацией нашего релиза, и у нас многое получилось.
Убрали все ручные действия по созданию ветки релиза, увеличению номера версии, запуску автотестов, сборке и выкладке в сторы.
Избавились от рутины описания состава релиза: наши скрипты автоматически анализируют merge-коммиты в develop-ветку и формируют список задач, попавших в релиз. Все необходимые задачи в Jira, связанные с работой других отделов, также создаются автоматически.
Добавили множество уведомлений об изменении статусов релиза для всех заинтересованных лиц: для менеджеров мы присылаем уведомления о выкатке релизов в прод, тестировщикам — о готовности сборок к регрессу, об успешных (и не очень) прогонах автотестов.
И, самое главное, мы визуализировали весь наш процесс релиза. Теперь Jira — это единый источник правды о релизе, теперь ни у кого не возникает вопросов, что же происходит с релизом.
Решение, конечно, далеко от идеального — где-то случаются технические ошибки, зато мы шаг за шагом избавляемся от человеческого фактора в важных этапах наших релизов.
Стало ли лучше?
Стало ли лучше после внедрения наших автоматизаций? Однозначно да: нам теперь гораздо проще и удобнее дропать релизы. Но всегда остаётся место для роста.
Мы сделали основу, на которую можно и дальше нанизывать множество других автоматизаций, которые могут появиться в дальнейшем. У нас уже сейчас есть несколько задач, которые ждут своего часа:
Мы хотим научиться менять статусы разных продуктовых задач, в зависимости от статуса релиза. Сейчас мы периодически забываем проставлять разные метки к задачам в Jira, или же переводить их в конечный статус рабочего flow.
Хотим автоматически раскатывать приложения не только в App Distribution, но и в сами сторы, включая Huawei App Gallery для Android. При этом мы хотим выкатывать приложения и в internal, и в beta, и в release-треки.
Было бы здорово научиться автоматически заводить в Jira задачки на новые краши и баги после появления их в проде, а также какие-то массовые жалобы пользователей.
На этом у меня всё. Автоматизируйте рутину, комментируйте, делитесь своими находками. Пока!