GitHub Actions как CI/CD для mobile-проектов

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Меня зовут Валерий Кузнецов и я работаю Senior Android Engineerом в ThredUP. Хочу рассказать почему и как мы переезжали с Jenkins на GitHub Actions в качестве CI/CD системы для Android-приложения и как мы сделали автоматизацию, которая экономит нам время и силы на проверку и релиз наших приложений.

Статья будет полезна тем, кто хостит исходный код проектов на GitHub и хотел бы попробовать или перейти на новый инструмент для сборки и релиза своих приложений.

Наше приложение развивалось, команда расширялась, и мы стали планировать большое количество улучшений и автоматизации наших рабочих процессов: от проверки кода до релиза в продакшен. Исторически сложилось, что сборка нашего Android-приложения была настроена на Jenkins и работала на self-hosted машинах, но из-за ограничений внешних ресурсов для обновления машин, Jenkins-версий, билд-скриптов, мы решили посмотреть на облачные альтернативы. Как раз в тот момент GitHub выпустил продукт под названием GitHub Actions в Beta-доступ.

Почему GitHub Actions?

На тот момент уже было довольно много других облачных альтернатив CI/CD ч (Bitrise, CircleCI, Travis), даже с фокусом на мобильную разработку, но GitHub Actions показался нам привлекательным по двум простым причинам:

  1. В Enterprise-план GitHub уже включено 50,000 минут. Никаких дополнительных оплат или согласований не надо.
  2. Actions являются частью большой GitHub-экосистемы, что несет за собой дополнительные преимущества в виде защищенности, поддержки, открытости исходного кода для некоторых частей системы.

Компоненты

Github Actions работает, используя следующие основные компоненты:

  • Workflows — самый высокоуровневый компонент, содержащий всю необходимую информацию о работе, которую нужны выполнить (и после каких событий).
  • Events — это конкретное событие, запускающее workflow. Например, создание pull request, issue в репозитории, git push в конкретную ветку репозитория или же веб-хук, вызванный сторонним сервисом.
  • Jobs — это набор шагов, которые выполняться на одной билд-машине.
  • Steps — исполняемая часть в рамках Job. В качестве исполняемого шага может быть actions или простой сценарий командной строки. Все шаги внутри одной Job выполняются в рамках одной билд-машины, и это позволяет им обмениваться данными друг с другом.
  • Actions — это самый маленький исполнимый и переиспользуемый блок workflow.

Иерархия компонентов

WorkFlows

Для того, чтобы начать работу GitHub Actions, требуется создать файл workflow в формате .yml или .yaml в папке проекта .github/workflows/. В этих файлах содержаться все настройки и шаги, необходимые для выполнения автоматизации. Workflow можно использовать для сборки, тестирования, релиза ваших проектов, а также любых других автоматизаций работы, связанных проектом на GitHub (например, при создании issue автоматически ответить каким-то шаблоном). Вот простой пример того, как может выглядеть workflow для сборки Android-приложения:

Actions

Actions — это особый тип шагов, которые помогают нам автоматизировать CI/CD. Кто угодно может опубликовать свои Actions с открытым исходным кодом, и их можно просматривать через GitHub или же создать приватные и использовать их в рамках одной организации.

Редактор

WorkFlow в GitHub Actions используют YAML в качества основного языка для конфигураций. Есть веб-редактор с поддержкой подсказок для автозаполнения.

Все workflow хранятся .github/workflows-папке в репозитории проекта, что удобно с точки зрения контроля-версий, но и создает некоторые трудности, когда надо обновить файл workflow во всех актуальных ветках.

Гиф редактора с примером автозаполнения

Также есть неофициальный VS-плагин для работы с GitHub Actions.

Наш WorkFlow

Исходный код WorkFlow для сборки на каждый Pull Request:

name: PR
on:
  push:
    branches: [ dev ]
  pull_request:
    branches: [ '**' ]
jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-go@v2
        with:
          go-version: '^1.14.7'
      - run: go version
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: '11'
     - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.7.1
      - name: Install Dependencies
        run: gem install bundler && bundle install
      - uses: reviewdog/action-setup@v1
        with:
          reviewdog_version: latest
      - name: Build with Fastlane
        run: fastlane dev
      - name: Run reviewdog
        if: ${{ failure() }}
        continue-on-error: true
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: reviewdog -f=checkstyle -name="ktlint" -reporter=github-pr-review < thredUP/build/reports/ktlint/ktlintMainSourceSetCheck/ktlintMainSourceSetCheck.xml

WorkFlow состоит из следующих частей:

  • Name — название WorkFlow для отображения в истории, может отличаться от названия файла worfklow.
  • On — события, при которых запускается данный workflow. В нашем случае — это push кода в git dev ветку и push кода для созданных pull requests в любую git-ветку проекта.
  • Jobs — список задач на выполнение. В нашем случае — всего одна задача build, состоящая из:
    • Выбор виртуальной машины на которой будет происходить сборка проекта. Мы для сборки Android-проектов сейчас используем образ ubuntu-18.04. Нам нет необходимости собирать Android-проект на macOS, и Linux VM потребляют минуты без дополнительного коэффициента.
    • runs-on: ubuntu-18.04
  • Настройки окружения для сборки проекта:
steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-go@v2
        with:
          go-version: '^1.14.7'
      - run: go version
      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: '11'
     - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.7.1
      - name: Install Dependencies
        run: gem install bundler && bundle install
      - uses: reviewdog/action-setup@v1
        with:
          reviewdog_version: latest
  • Запуск сборки проекта с помощью Fastlane.
      - name: Build with Fastlane
        run: fastlane dev
  • В случае ошибки сборки проекта запускаем ReviewDog для того, чтобы отправить ошибки, связанные со стилем кода в качестве комментариев на Pull Request.
- name: Run reviewdog
        if: ${{ failure() }}
        continue-on-error: true
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: reviewdog -f=checkstyle -name="ktlint" -reporter=github-pr-review < thredUP/build/reports/ktlint/ktlintMainSourceSetCheck/ktlintMainSourceSetCheck.xml

Почему Fastlane

Несмотря на то что GitHub Actions уже могут полностью заменить все, что у нас используется в рамках Fastlane для сборки проекта, запуска тестов и деплоя на Google Play, мы остались на нем по следующим причинам:

  • При первой настройке CI/CD на GitHub Actions они были еще в Beta-статусе и не хотелось тратить рерурсы по настройке CI впустую, поэтому решили использовать Fastlane: его скрипты можно было бы переиспользовать в рамках любого облачного CI, который поддерживает Ruby.
  • Fastlane по личным ощущениям все еще более ориентирован полностью на мобильную платформу, и новые скрипты ориентированные именно на Android/iOS. Их обновления выходят чаще в рамках Fastlane, чем GitHub Actions.

GitHub Community

В рамках первой настройки GitHub Actions я попробовал обратиться в GitHub Community (StackOverflow + обсуждения, ориентированные на GitHub экосистему) и на удивление получил довольно таки детальный и быстрый ответ в течении пару часов. Судя по истории постов большинство вопросов получают ответ в течении дня или переростают в детальные обсуждения с потенциалом реализации нового функционала в рамках GitHub Actions.

Виртуальные машины

GitHub Actions работает на базе вирутальных окружений и предоставляет следующие готовые окружения:

GitHub Actions использует Standard_DS2_v2 машины с 2 vCPU и 7 Гб оперативной памяти в рамках Microsoft Azure. Также есть возможность собрать свое окружение и запускать workflow в рамках собственных локальных машин, подключаемых к GitHub Actions с целью кастомизации программного обеспечения и оборудования.

Стоимость

Источник: github.com/features/actions

Нам вполне хватает 50 000 минут работы на Linux-машинах, но в случае, если захотим подключить Windows или macOS-машины, то минуты начнут потребляться с повышенным коэффициентом — x2 за Windows, x10 за macOS.

Мы проводили базовое сравнение с альтернативой, которую рассматривали, — Bitrise, и аналогичное количество минут (50 000) на Linux-билд машинах стоило бы нам порядка $1755 в месяц со всеми скидками.

Значок статуса

Также можно добавить значок статуса выполнения автоматизации, если открыть детали workflow -> настройки -> создать значок статуса.

Заключение

Подведем итоги плюсов и минусов, с которыми мы столкнулись во время интеграции и которые всплыли спустя 10000 запусков наших автоматизаций:

Плюсы

  • Довольно простая первичная настройка за счет интеграции с GitHub-экосистемой, хорошей документацией и возможности просмотреть workflow проектов с открытым исходным кодом.
  • Большое и постоянно растущее количество actions с открытым кодом, покрывающее совершенно различные сценарии использования. На момент написания статьи их 10334.
  • Версионирование workflow, так как они являются частью git-репозитория и помогают с откатом настроек. Есть возможность иметь разные настройки workflow в разных git-ветках.
  • Возможность переиспользовать приватные workflow в рамках организации в разных репозиториях.
  • Высокий uptime.

Минусы

  • В качестве облачного CI комфортно использовать, только если кодовая база хостится на GitHub.
  • Нет возможности выбрать более мощные облачные машины.
  • Накладные расходы в случае, если необходимо обновить workflow во всех актуальных ветках.
  • UI для просмотра логов на больших объемах начинает сильно подтормаживать. Проще смотреть сырые логи.
  • Артефакты сборки прикрепляются как архив ко всему workflow и нет возможности просмотреть содержимое, не скачивая архив целиком.

GitHub Actions — еще один сервис для CI/CD на рынке. В случае, если GitHub уже заинтегрирован в ваши рабочие процессы, то GitHub Actions с большой вероятностью подойдут большинству проектов. Его легко запустить и настроить, простое и хорошо документированное API для создания ваших собственных actions и использование уже существующих actions, доступных на площадке GitHub. Я считаю, что это удобное решение, отвечающее широкому кругу требований и буду рад обсудить ваш опыт или вопросы, связанные с GitHub Actions в комментариях.

Ссылки:

  1. github.com/features/actions
  2. docs.github.com/en/actions
  3. github.com/marketplace?type=actions
  4. fastlane.tools/
👍НравитсяПонравилось5
В избранноеВ избранном7
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
В качестве облачного CI комфортно использовать, только если кодовая база хостится на GitHub.

Если Github будет лежать, Actions будут лежать тоже — их просто нет смысла использовать, если код не на Github. Этот минус сомнительный.

С другой строны вы совершенно не раскрыли удовольствие от тестирования/отладки workflow. Есть act но это не 100% решение.

У меня нет опыта с GitHub Actions, но большой опыт с Circle CI. Также переходила с Jenkins. Сначала было непривычно работать с YAML файлами и долго не могла понять как писать конфигурацию так, чтоб не дублировать кучу кода. Потом уже руку набила и привыкла и сейчас Circle CI очень нравится. Хотя первые пару месяцев вообще не нравился. «Скучала» по красивому Jenkins. Не хватало возможности прикрутить ЛЮБОЙ дашборд, любой плагин, сделать вообще все, что я хочу. Сейчас уже привыкла и понимаю(принимаю), что в компании, где много сборок и много проектов это хорошо, когда все унифицировано, поскольку все понимают где что происходит.

На CircleCI macOS так же само самый дорогой executor.

Ещё была какая-то проблема с Android эмуляторами. Уже точно не помню ошибку, но ошибок было много. То не стартовали эмуляторы, то каждый раз эмуляторы отваливалось с разными ошибками. Причём долго пробовали много способов и разные executor-ы и разные docker images. Все никак.. Потом решили запускать на Firebase, и все сразу запустилось и работает прекрасно уже больше года.

Ещё конечно удобно когда код и CI работает как одна экосистема, поскольку не нужно настраивать отдельно вебхуки и какие-то придумывать нотификейшены. Тесты упали, все это сразу видно в PR. Разработчик даже физически не сможет залить код в мастер, если тесты упали. Очень удобно. Все пишут и обновляют тесты.

Также по другому воспринимается подход к написанию тестов и вообще к культуре автоматизации. Одно дело, когда тесты пишет Automation QA , который запускает это все где-то на Jenkins. Только он знает, где посмотреть эти тесты и никто кроме него вообще в это все не вникает. Другое дело, когда автоматические тесты ( юнит-тесты, интеграционные, end2end — это часть кода и часть общего pipeline) То-есть команда даже не сможет зарелизиться, если с тестами что-то не так, потому-что даже сам билд не задеплоится. Это в корни меняет отношение команды к автоматизации и меняются подходы к разработке и процессам в команде.

В двух словах: я очень-очень-очень люблю Jenkins, но конечно стоит переходить на облачные альтернативы 🙏🙏

Про минусы, точнее их часть:
— уменьшить дупликацию кода (workflow) и их поддержку помогут docs.github.com/...​actions/reusing-workflows и docs.github.com/...​eating-a-composite-action
— разные VM можно решить используя self-hosted ранеры (имея опыт поддержки Jenkins вашим девопсам будет не сложно) или же дождаться «premium» ранеров от GitHub github.com/...​github/roadmap/issues/161

Да, все прикольно, но только для Android.

Самое главное — цена вопроса:
github.com/pricing

Потому что, для не Enterprise, но для Team пакета вы получаете 5000 минут билда.

А теперь самое интересное — для MacOS счетчик минут идет на X10.

Пруфы:
docs.github.com/...​illing-for-github-actions

Minute multiplier — MacOS — 10

То есть — 5000 / 10 = 500 минут.

А если учесть что билд + выливка занимает в среднем 30-40 минут — вы получаете аж целых 12 попыток выливки в месяц за 4$.

Сойдет для маленьких проектов с 1-2 девами + QA в лице кастомера (типичный фриланс)

И это в случае если вы не хотите отправлять Release Notes (What to Test) в TestFlight — для этого нужно подождать пока билд не запроцессится, и только потом Fastlane добаляет к нему описание для тестирования.
В случае с регулярными билдами для QA — What To Test — очень полезная секция для тестировщиков.
Можно сделать через автоматический сбор commit messages в гите и слать их как заметки для тестирования.

Тут уже время выливки увеличивается до 1-2 часов — то есть для iOS — совсем печально.

Для Enterprise соответственно — 120 билдов, но и ценник уже не столь демократичный — 21$ в месяц человека.

Так что в случае с iOS билдами лучше иметь выделенный CI / CD сервер (Jenkins либо TeamCity) на самом простеньком MacMini — если есть желание не сильно тратиться.

Автору статьи спасибо, но тема денежных затрат на CI/CD не раскрыта.

Я не понял, у вас нет возможности платить $21 в месяц за Enterprise? это же пшик для IT

Тут уже время выливки увеличивается до 1-2 часов

Можно сделать интеграцию с слаком/тимсами/что там используете и по успешному билду генерировать туда сообщение. Ну и процессинг на аппсторе в среднем все же значительно быстрее чем полтора часа.

Ещё GitHub actions значительно шустрее чем тот же BitRise, но если планируете билдить под iOS часто, то может выйти ну очень дорого.

На Bitrise тоже количество минут (5000) было бы дополнительные 500$ в сравнению с GitHub Enterprise, но дальше ценник бы действительно рос так как разница в коэфициентах потребления GitHub x10 , Bitrise x2. Как альтернативу можно держать self-hosted mac mini (~1000$) + GitHub Actions (бесплатно) и он окупится за пару месяцев, а то и быстрее если много собирать.

Подписаться на комментарии