В преддверии старта курса "iOS Developer. Basic" традиционно подготовили для вас интересный перевод, а также приглашаем записаться на бесплатный вебинар, в рамках которого наши эксперты подробно расскажут о программе курса, а также ответят на интересующие вас вопросы.


Внедрение технологий непрерывной интеграции (Continuous Integration - CI) и непрерывного развертывания (Continuous Delivery - CD) в процесс разработки - бесспорно единственный способ отслеживать актуальность изменений кода и определять ошибки интеграции на самых ранних этапах. Это также еще и путь к отлаженным билдам, практически сразу же доступным для тестирования и готовым к отправке в продакшн даже после значительных изменений кода.

Интегрируя CI/CD в свою повседневную работу, разработчики могут достичь двух важных целей: во-первых, возможность запускать наборы тестов на сервере, который не является рабочим компьютером, чтобы инженер мог продолжать разрабатывать новый функционал без отвлекающих факторов и, во-вторых, возможность отправлять билды своему заказчику или инженеру по обеспечению качества, чтобы продемонстрировать/протестировать/проанализировать новую фичу, даже если они не могут собрать и запустить проект на своих собственных компьютерах.

Но что происходит, когда у нас есть несколько промежуточных сред, и тесты должны выполняться на разных серверах или функции должны тестироваться в разных средах? Вот где на помощь приходят Jenkins и Fastlane  - инструменты, которые позволяют автоматизировать процесс под различные конфигурации, и именно на этом фокусируется данная статья.

Существует множество отличных статей и руководств, в которых подробно описывается, как использовать Jenkins и Fastlane для настройки CI для мобильного проекта. Однако я хочу сосредоточиться на том, как мы можем настроить соответствующие скрипты для работы с несколькими средами.

Jenkins и Fastlane

Чтобы понять, как мы можем интегрировать CI в проект, мы должны понимать, как Jenkins и Fastlane работают. Вкратце, Jenkins - это сервер непрерывной интеграции с открытым исходным кодом, написанным на Java, и это один из наиболее широко используемых инструментов для управления сборками непрерывной интеграции. Jenkins предоставляет возможность создавать пайплайны (Pipelines), которые по сути являются жизненными циклами процессов, называемых задачами (Jobs), которые включают сборку, документирование, тестирование, упаковку, стейджинг, развертывание, статический анализ и многое другое. Задачи связаны друг с другом в последовательности, образующей конвейер (пайплайн), и именно здесь в игру вступает Fastlane.

Fastlane - это инструмент с открытым исходным кодом, который используется для автоматизации процесса развертывания и распространения мобильных проектов (iOS и Android), предлагающий широкий спектр функций автоматизации в рамках жизненного цикла мобильного приложения, таких как упаковка, подписание кода, распространение сборок и многое другое. Fastlane позволяет создавать задачи, именуемые Lanes, которые по сути представляют из себя скрипты, то есть серию команд, называемых Actions, которые описывают рабочий процесс, который мы хотим автоматизировать.

Наша цель

Итак, то, чего мы здесь хотим достичь, - это автоматизировать процесс распространения нашего iOS-приложения путем автоматизации загрузки нашего приложения в Testflight, откуда заинтересованные лица (заказчик, инженер по обеспечению качества, продавец, который хочет продемонстрировать приложение, и в том же духе) могут войти в систему и загрузить его без особых усилий. Более того, мы хотим продвинуться на один шаг дальше и реализовать возможность автоматически загружать билды в Testflight по одному нажатию кнопки:

a) для разных веток под разные фичи

b) для нескольких конфигураций, соответствующих разным средам

Такова будет наша конечная цель ?.

Предварительные требования

В этой статье мы считаем, что Jenkins и Fastlane уже были установлены и настроены. Существует множество руководств, в которых подробно описывается, как нужно выполнять настройку. Кроме того, для Jenkins потребуется установить некоторые плагины, чтобы позволить Jenkins запускаться из веб-хуков Github и запускать задание. Это плагины Github, Xcode, SCM (Source Control Management), которые будут использоваться для того, чтобы сделать чекаут нашего проекта с Github, и Credentials Plugin для того, чтобы связать учетные данные для переменных окружения.

Начнем

Для начала нам нужно создать новый пайплайн в Jenkins. Этот пайплайн будет описан созданным нами скриптом, который выполняет загрузку нашего приложения в Testflight.

В главном меню панели инструментов Jenkins (ниже) мы выбираем первый вариант => New Item (Pipeline) и создаем задачу (Job) Jenkins с именем “Upload to Testflight”.

 

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

В поле Definition ниже, в разделе Pipeline выбираем параметр «Pipeline Script from SCM». Этот параметр указывает Дженкинсу получить пайплайн из системы управления исходным кодом (SCM), в роли которой будет наш клонированный Git-репозиторий.

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

Наконец, мы определяем скрипт, который будет описывать весь процесс пайплайна.

Нажимаем кнопку «Save» и вуаля! Нам удалось создать собственную задачу в Jenkins. Теперь мы готовы приступить к написанию нашего скрипта!

В основном мы будем использовать подход Scripted Pipeline. Наш скрипт будет состоять из нескольких этапов, называемых стадиями (stages), которые описывают, что собирается делать наш пайплайн. В конечном итоге мы хотим закончить загрузкой в Testflight, но перед загрузкой мы хотим убедиться, что наши модульные тесты проходятся успешно. Таким образом, различные фазы скрипта автоматизации должны включать следующие стадии:

  1. Чекаут репозитория

  2. Установка зависимостей

  3. Сброс симуляторов

  4. Запуск тестов

  5. Сборка билда

  6. Загрузка в Testflight

  7. Очистка

После того, как мы написали наш скрипт, нам нужно выбрать опцию Build with Parameters из меню пайплайна, который мы только что создали, и указать ветку, которую мы хотим собрать:

После того, как мы нажмем кнопку Build, и конвейер будет успешно запущен, мы увидим следующее в Jenkins Stage view:

что будет означать, что мы успешно загрузили наше приложение в Testflight!

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

Скрипт

В нашем скрипте, который мы назвали MyScript.groovy, мы определим функцию называемую deploy(), внутри которой мы намерены реализовать вышеперечисленные стадии следующим образом:

1. Чекаут репозитория

Мы делаем чекаут нашего репозитория с помощью команды checkout плагина SCM, которая будет запускать проверку проекта с использованием параметров конфигурации, которые мы указали в Jenkins Pipeline.

stage('Checkout') {
    checkout scm
}

2. Установки зависимостей

stage('Install dependencies') {
      sh 'gem install bundler'
      sh 'bundle update'
      sh 'bundle exec pod repo update'
      sh 'bundle exec pod install'
}

Наш проект использует в качестве менеджера зависимостей CocoaPods, поэтому нам нужно запустить pod install, чтобы загрузить зависимости проекта. Для выполнения этой команды и всех других шелл-команд мы используем Bundler, который представляет собой инструмент для управления гемом приложения Ruby. Выполнив первые 2 команды, нам удается установить Bundler, а затем Bundler загружает все гемы, указанные в Gemfile проекта. Это стадия, на которой мы можем указать набор инструментов, которые могут понадобиться нашему приложению, например Fastlane, который мы будем использовать следующим, или, если нам нужен линтер или Danger, это место как раз для определения их ruby гемов. Мы продолжаем дальше и запускаем pod repo update, чтобы всегда иметь последние версии pod'а, и, наконец, мы запускаем pod update, чтобы загрузить зависимости проекта.

3. Сброс симуляторов

stage('Reset Simulators') {
   sh 'bundle exec fastlane snapshot resetsimulators --force'
}

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

Это первый раз, когда Fastlane появляется в кадре. Как я упоминал ранее, Fastlane использует Lanes и уже имеет большое количество заготовленных лейнов, но мы можем создавать и свои собственные настраиваемые лейны внутри файла под именем Fastfile. Здесь мы используем заготовленный лейн, который делает именно то, что нам нужно.

Команда выше удалит и пересоздаст все iOS-симуляторы, что можно счесть чрезмерным, но иногда «отчаянные времена требуют отчаянных мер» .

4. Запуск тестов

stage('Run Tests') {
   sh 'bundle exec fastlane test'
}

На этом этапе мы запускаем модульные тесты для нашего проекта. Теперь test представляет собой кастомный лейн, который мы реализовали внутри нашего Fastfile, и имеет следующую реализацию:

lane :test do
    scan(
        clean: true,
        devices: ["iPhone X"],
        workspace: "ourproject.xcworkspace",
        scheme: "productionscheme",
        codecoverage: true,
        outputdirectory: "./testoutput",
        outputtypes: "html,junit"
    )
    slather(
        coberturaxml: true,
        proj: "ourproject.xcodeproj",
        workspace: "ourproject.xcworkspace",
        outputdirectory: "./testoutput",
        scheme: "productionscheme",
        jenkins: true,
        ignore: [arrayofdocstoignore]
    )
end

 

Здесь мы используем два основных экшена Fastlane: scan и slather.

Scan используется для фактического запуска модульных тестов и может быть настроен с несколькими параметрами, такими как workspace (рабочее пространство), scheme (схема), codecoverage (покрытие кода) и, что наиболее важно, devices (устройства), где можем указать симулятор, в котором мы хотим запускать наши модульные тесты.

Slather используется для сбора покрытия кода при выполнении модульных тестов, а также принимает несколько аргументов, таких как результирующий каталог для отчета о покрытии, а также массив документов, которые следует игнорировать при сборе покрытия кода (ignore).

Здесь и происходит Fastlane-магия ?. Определяя этот лейн всего двумя экшенами, нам удается легко запускать наши модульные тесты внутри Jenkins. Обратите внимание, что все они, очевидно, должны быть успешно пройдены, иначе эта стадия и вся задача закончатся неудачей.


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

А если вас заинтересовал курс, предлагаем записаться на бесплатный вебинар по ссылке.