Как Selbi должна обеспечивать непрерывную доставку нашего приложения React Native?

Задний план

Джордан и я работали над Selbi пару месяцев и только что выпустили бета-версию (🎉🎉…🔥😮…🎉).

До Selbi я работал в Palantir, и одна из вещей, по которым я больше всего скучаю, — это большое количество умных и готовых помочь людей, которые находятся на расстоянии слышимости. Эта статья — моя попытка собрать технический обзор процесса выпуска Selbi.

Посмотрим, как пойдет!

Обзор

Этот обзор разбит на несколько разделов.

  • Постановка задачи, включая ограничения, созданные нашей архитектурой.
  • Предлагаемое решение.
  • Краткое описание других рассмотренных решений.
  • Открытые вопросы.

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

Постановка задачи

Нам нужна система, определяющая, как код переходит от ноутбука для разработки к стадии подготовки и производства.

Приоритетные цели

  • Развертывание должно быть быстрым и воспроизводимым локально. Система должна облегчать рутинные задачи, но никогда не мешать, когда требуется скорость.
  • Система должна описывать поток git для управления несколькими версиями.

Неприоритетные цели

  • Полная автоматизация. Запуск скрипта или двух локально — это нормально. Это может быть конечная цель, но не является непосредственным приоритетом.

Существующая архитектура

Приложение Selbi написано на React Native. Бэкенд — Firebase с сервис-воркером. Клиенты общаются напрямую с Firebase, и любые более сложные задачи (например, Stripe или Twilio) ставятся в очередь для обработки серверной службой. Это паттерн 2 в этой статье.

Это означает, что мы развертываем код в 3 местах:

  1. Телефоны пользователей.
  2. Наша схема Firebase.
  3. Сервер приложения, работающий в облаке Google.

Это на самом деле очень важно, потому что это означает, что мы не можем объявить устаревшей версию API. Это исключает возможность выполнения selbi.io/v1 и selbi.io/v2. Наш API это схема Firebase.

Существующие этапы

Selbi развертывается на 3 этапах (разработка, подготовка и производство), каждый из которых соответствует экземпляру Firebase.

Существующая настройка проекта

Весь код Selbi находится в одном репозитории на Github. Service Worker, бэкэнд-схема и само приложение имеют свой собственный каталог, который является проектом NodeJS.

Предложенное решение

Соответствующие технологии:

  • CodePush — отправьте Javascript в ваше мобильное приложение.
  • Fastlane — инструменты автоматизации выпуска приложений для Android и iOS.
  • CircleCI — Платформа непрерывной интеграции.

Обзор

В этом решении мы заставляем пользователей обновляться, когда они используют старую версию приложения, и обновляем номер версии только в том случае, если есть собственное изменение.

Это кажется выгодным, потому что большинство изменений будет ограничено javascript, поэтому мы не будем форсировать слишком много обновлений. Это также означает, что нам не нужно сталкиваться с головной болью тестирования различных версий JS в сравнении с различными нативными версиями. Отбрасываем идею бэкпорта все вместе.

Псевдокод

Code up feature locally and push to Github.
When feature is complete, merge feature into develop.
Upon ready to release:
  if native changes:
    create new feature branch to bump version
    merge version bump to develop
  merge develop into staging
  if JS only:
    include #jsonly in merge commit message
  run regression pass
Upon bugs are found in staging:
  patch on develop and merge to staging
  if entire release is still JS only:
    include #jsonly in merge commit message
Upon staging is stable:
  create branch for old version from production
  merge staging into production
  if JS only:
    include #jsonly in merge commit message
Upon any branch updates:
  run all unit tests and block other action if failing
Upon merging to 'production':
  if JS only change:
    firebase deploy
    gcloud deploy
    CodePush deploy
  else:
    build Production archive and send to ItunesConnect
    submit for approval with Apple for manual release
    await approval from Apple:
      release version (manually in app store)
      // All of this would be done by running a script locally. 
      CodePush to old versions requiring native update
      firebase deploy
      gcloud deploy
Upon merging to 'staging':
  if JS only change:
    firebase deploy (to Selbi-Staging)
    gcloud deploy (to Selbi-Staging)
    CodePush deploy (to Selbi-Staging)
  else:
    build Staging archive and send to ItunesConnect
    set new Staging build for Internal Test flight
    firebase deploy (to Selbi-Staging)
    gcloud deploy (to Selbi-Staging)

Каждый приведенный выше блок псевдокода может быть довольно легко написан сценарием, за исключением ожидания одобрения Apple. Вероятно, мы могли бы автоматизировать и это, дождавшись оповещения по электронной почте от Apple, но это кажется слишком сложным.

Скрипты реализации

В этом разделе представлена ​​документация по использованию ряда скриптов, которые задействуют этот рабочий процесс. Ниже представлена ​​структура проекта.

$ tree -L 1 selbi-v2
selbi-v2
├── README.md
├── Selbi // react native app
├── circle.yml
├── selbi-backend // firebase schema + validation unit tests
├── selbi-web
└── selbi-stripe-worker // backend worker
$ selbi-v2/Selbi/deploy -h
Deploys the Selbi app. It can be used to either deploy native or javascript only changes.
Usage: ./deploy <stage> <type>
- stage: One of 'production' or 'staging'
- type: One of 'native' or 'js'
./deploy production native - Build and publish the 'Selbi-Production' scheme to ItunesConnect. Submits the app for review.
./deploy production js - CodePush deploy to apps in the production environment at the current version.
./deploy staging native - Build and publish the 'Selbi-Staging' scheme at the current version and build number to ItunesConnect Internal Test Flight.
./deploy staging js - CodePush deploy to app in the staging environment at the current version.
Note that this will modify your local file structure to put all necessary config files in place for which ever stage you choose.
$ selbi-v2/selbi-backend/deploy -h
Deploys the Selbi Firebase backend schema to a specific stage or to a user owned Firebase instance.
Usage: ./deploy <stage>
- stage: One of 'production', 'staging', 'develop' or the name of a Firebase environment of the owner.

Обратите внимание, что этот скрипт позволяет развернуть схему в среде Firebase, принадлежащей пользователю. Это удобство, позволяющее каждому разработчику иметь собственный экземпляр Firebase для разработки.

$ selbi-v2/selbi-stripe-worker/deploy -h
Deploys the Selbi backend service worker. If you want to run the service worker for development, use 'npm start'.
Usage: ./deploy <stage>
- stage: One of 'production', 'staging'
$ selbi-v2/release -h
Releases and manages Selbi branches for the release flow.
Usage:
./release cut test js - Create a pull request from develop to staging with #jsonly in the request title.
./release cut test native <version> - Push a commit setting the version to develop and open a pull request from develop to staging.
./release cut prod js - Create a pull request from staging to production with #jsonly in the request title.
./release cut prod native - Create branch from production for current version and push to Github. Create a pull request from staging to production.
./release to staging js - Deploy javascript immediately to Selbi-Staging for entire system.
./release to staging native - Build and deploy Selbi-Staging to ItunesConnect Internal Test Flight as well as deploying the entire backend.
./release to production js - Deploy Selbi, selbi-backend and selbi-stripe-worker javascript immediately to Selbi-Production.
./release to production native - Deploy javascript forcing native update to versions besides the current one and deploy backend services. You must manually release the newest version from ItunesConnect

Эти сценарии предназначены для предоставления простого способа управления развертыванием из командной строки, а также основных инструментов автоматизации от CircleCI.

Другие рассматриваемые решения

Еще один технический стек

Другим основным претендентом, на которого я смотрел, была Битрисе. Bitrise предоставляет инфраструктуру CI и интерфейс сборки из командной строки. Это довольно мило, за исключением того, что я не уверен, что хочу связать эти две вещи вместе. Кроме того, у Fastlane огромное количество поклонников и отличная документация.

Не принудительное обновление

Принудительное обновление немного пугает, потому что это может означать, что люди удалят приложение. Однако значительное увеличение сложности поддержки различных версий и обратного переноса только обновлений JS слишком велико. Компромисс означает, что мы можем сосредоточиться на стабильности новых версий, а не распылять ресурсы для проверки старых версий.

Открытые вопросы

Это не обязательно вопросы, на которые нужно отвечать, но они интересны, и я хотел бы получить обратную связь. 😍

  • Есть ли другие лучшие практики, которые мы упускаем?
  • Как это повлияет на нас, когда мы добавим Android?
  • Как правильно (и эффективно) тестировать версии + CodePush?
  • Как мы будем управлять ограничением доступа позже, когда не все, у кого есть доступ к репозиторию, должны иметь доступ к развертыванию?

Спасибо за чтение! Если вы хотите узнать, что происходит с Selbi, загляните к нам в Medium, Instagram или Facebook.