Компания
55,72
рейтинг
6 сентября 2013 в 13:42

Разработка → Автоматическая сборка iOS-приложений на разных версиях Xcode с помощью Jenkins tutorial

Если к вам уже приходили с вопросом «Где можно получить свежую сборку?», то вы прекрасно понимаете, зачем нужна автоматизация сборки и распространения. Никто не хочет тратить лишнее время на рутинную работу. Раньше мы пользовались утилитой под названием iOSBetaBuilder (http://www.hanchorllc.com/betabuilder-for-ios/). Это приложение предназначено для упрощения распространения AdHoc сборок iOS-приложения: нужно только ввести название и версию проекта, адрес (URL), где хочется выложить сборку, и получаются сгенерированные index.html и manifest.plist. На первое время этого достаточно.

Но когда проект достигает стадии багфиксинга, тратить лишние 5 минут на сборку и перепубликацию для QA – неохота и некогда. А когда проектов становится много, а их сборки становятся дольше… В рамках компании затраты времени помноженные на количество проектов становятся слишком существенными, и приходит время автоматизации.

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

Для тех, кто уже в теме, есть интересный раздел в конце статьи: как настроить сборки с различными версиями Xcode на одной машине.

Как настроить автоматическую сборку iOS-приложений с помощью Jenkins?

Необходимо установить Jenkins, добавить и настроить несколько плагинов, добавить агента для сборки и настроить распространение OTA. Если хочется получать еще уведомления по почте, то надо настроить дополнительный плагин.

Итак.

Что такое Jenkins? Jenkins — это сервер непрерывной интеграции. Jenkins написан на Java и имеет большое число плагинов для расширения функционала. Всю необходимую информацию для установки можно найти здесь https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins

Для поиска плагинов — https://wiki.jenkins-ci.org/display/JENKINS/Plugins, но и Гугл тоже неплохо справляется, когда знаешь, что хочешь найти.

Архитектура нашей системы получилась следующая:



  • Jenkins установлен на машине с Ubuntu 12.04 LTS. Он используется для различных проектов, поэтому Xcode установлен на отдельной машине. Если вам нужно собирать только проекты для iOS, то можно установить Jenkins на компьютер с Mac OS X, и не нужно будет конфигурировать дополнительного агента.
  • Разработчики заливают код в репозиторий — в нашем примере это Git.
  • Jenkins запускает агента (машина с Xcode и VCS).
  • Агент выкачивает код, собирает проект и, если сборка завершена успешно, заливает на сервер по FTP для распространения.
  • Jenkins рассылает уведомления.

Для реализации этой системы нам понадобятся следующие плагины:


Настройка плагинов

Рассмотрим на примере сборки конкретного приложения. У нас есть некий проект, исходный код которого находится в Git-репозитории:
git@github.com:ShareKit/ShareKit.git

Мы хотим собрать его и выложить на наш внутренний сервер для распространения через Internet. Доступ Jenkins’а к серверу осуществляется по FTP, на сервере настроен Apache, и все что мы выкладываем, становится автоматически доступно нашему отделу QA или заказчикам на специальном сайте.

FTP
Чтобы настроить плагин для FTP после его установки необходимо открыть страницу настроек Jenkins:
Jenkins -> Manage Jenkins -> Configure System
В настройках найти раздел про FTP и прописать информацию для доступа к серверу.



Сохранить.

Git
Чтобы настроить Git, необходимо добавить описание Git installation на странице
Jenkins -> Manage Jenkins -> Configure System


Путь указывает, при помощи какой команды будет запускаться Git на агенте. Необходимо указать полный путь, по которому находится git на той машине, где установлен Xcode. Может появиться сообщение об ошибке, но не стоит обращать на него внимание, потому что Jenkins проверяет путь к Git на локальной машине, а не на удаленной, где мы будем его использовать.
Сохраняем.

Xcode Agent
Для работы любого агента Jenkins на удаленной машине необходимо добавить credentials для доступа к удаленной машине на странице настроек

Jenkins -> Manage Jenkins -> Manage Credentials


Также необходимо добавить публичный ключ машины, на которой стоит Jenkins в папку authorizedKeys той машины, на которой стоит Xcode. Username в форме должен совпадать с именем пользователя, под аккаунтом которого будет запускаться Xcode. Путь к файлу с публичными ключами в нашем случае будет такой: /Users/jenkins/.ssh/authorizedKeys

В нашем примере Xcode установлен на машине с IP-адресом 192.168.154.24.
Чтобы добавить агента, который будет использоваться для сборки проекта, на странице списка нод
Jenkins -> Manage Jenkins -> Manage Nodes
Нажимаем на New Node, назовем наш узел XcodeAgent, выбираем Dumb Slave, нажимаем OK.


Количество исполнителей можно поставить любое, в зависимости от мощности машины и нагрузки. У нас приложений не очень много, и один поток вполне справляется. Директория должна быть доступна пользователю, в нашем случае — /Users/jenkins/jenkinsCI
Указываем IP адрес машины, и выбираем наши Credentials:


После того, как мы нажали Save, можно переходить к созданию Job’а.

Настройка сборки – New Job

Создаем новую задачу:
Jenkins -> New Job


Вводим название задачи, выбираем тип Build a free-style software project. Нажимаем OK. В будущем для создания задач, подобных существующим, лучшим вариантом будет “Copy existing job”.

В разделе Source Code выбираем Git, указываем адрес репозитория (на картинке для примера указан ShareKit) и Git executable, который мы сконфигурировали ранее:


Заполняем остальные настройки:


С какой частотой мы хотим опрашивать систему контроля версий на наличие обновлений – мы поставили «каждую минуту». Как вы видите, Jenkins предлагает использовать параметр H, который означает, что опрос будет происходить 1 раз в час в случайную минуту, чтобы снизить нагрузку.


Добавляем Build Action: Xcode


Конфигурация в обычном случае довольна проста. Мы используем AdHoc профили для сборки приложений для тестирования и демонстрации заказчику.

Добавляем еще один Build Action. На этот раз нас интересует публикация приложения на нашем сервере – по FTP:




Добавляем рассылку уведомлений по почте

Если у вас есть мейл-сервер, на Jenkins можно настроить рассылку писем по результатам сборки.
Сначала на странице настроек
Jenkins -> Manage Jenkins -> Configure System
указываем email адрес, с которого пользователи будут получать письма:


Указываем адрес SMTP сервера, порт и тот же email.


Плагин, который мы установили, добавляет еще один раздел настроек:


Мы можем указать формат темы письма и используемый шаблон. Все шаблоны лежат в файловой системе. Подробности о темплейтах можно почитать на странице плагина https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin#Email-extplugin-TemplateExamples

Кроме этого, плагин позволяет задавать список получателей и различные конфигурации для каждого статуса сборки: например, если приложение не собралось – уведомление отправляется разработчикам, собралось – тестировщикам. На картинке пример для статусов неудачной сборки и исправления.

После этого добавляем в нашу сборку Post-build Action:


и конфигурируем:


Сохраняем, запускаем и радуемся!

Второй Xcode

Все хорошо, когда вы только начали делать проект и поддерживаете только самые свежие версии iOS, но время идет, мир меняется, а Apple выпускает новую iOS и новый Xcode для нее. Заказчик просит поддерживать что было и что есть, и встает вопрос о необходимости править баги старой версии, пока разрабатывается новая.
Понятное дело, мы создаем новый бранч, вешаем метки и создаем новый адрес для публикации тестовой версии. А как же Xcode?

Плагин не поддерживает переключение между версиями Xcode, поэтому у нас есть два (может кто-то придумает больше – но мы не смогли) варианта:
  1. настроить вторую машинку с Xcode и добавить агента в Jenkins
  2. заставить Jenkins переключать Xcode с помощью shell script


Мы пошли вторым путем.
Сменить Xcode можно с помощью довольно простого скрипта:
sudo xcode-select -switch $XCodePathToDeveloperFolder
– для переключения установленных Xcode необходимо обладать правами root
Однако при запуске команд по ssh возникают сложности с паролем и можно получить такую ошибку:
sudo: no tty present and no askpass program specified

Это происходит потому, что команды на Jenkins-агенте запускаются через ssh, который не предоставляет терминала.
Для решения этой проблемы нужно создать файл, например, /Users/jenkins/pass, в который поместить пароль нашего пользователя.
Нужно добавить через конвейер в скрипт по переключению Xсode команду вывода содержимого нашего файла с паролем:

cat /Users/jenkins/pass | sudo xcode-select -switch /Applications/XcodeVX.X.app/Contents/Developer


Эту команду в виде Build step – Execute shell мы добавляем первым шагом в разделе Build нашей задачи – перед Xcode.

После запуска задачи Xcode изменится, и все остальные задачи, настроенные на старую версию Xcode будут собираться неправильно. Чтобы этого избежать необходимо вернуть Xcode, на который настроены остальные проекты.
Можно было бы добавить такую же команду после выполнения Xсode, но если сборка поломается, то выполнение последовательности Build step прервется.
Нужно добавить Post-build action – Post build task, и вернуть все на место:


Собираем. Все отлично работает.

Стоит отметить, что количество executors, которое мы указали при настройке агента может повлиять на сборку, если поставить больше 1. Тогда для всех сборок придется добавить переключение Xcode на нужную версию.

Заключение

Автор: @eastbanctech

Комментарии (17)

  • 0
    А можно настроить письмо таким образом, чтобы там отправлялась ссылка на сборку?
    Чтобы можно было из почты сразу ставить приложение, открыв письмо на телефоне
    • 0
      сам занимался подобной системой (никак руке не дойдут оформить статью), мы поначалу использовали переписанный под свои нужды iOSBetaBuilder (добавлен консольный режим), далее просто загружали ipa, manifest и html страничку ссылкой на манифест для скачивания. Так вот, ссылка на html всегда была одна и та же (просто добавили в избранное на железках).
      Но со временем отказались, в пользу hockeyapp.net
    • 0
      Можно
      Можно в общем шаблоне прописать ссылку с параметром, например mydomain.ru/${JOB_NAME}/index.html

      А можно для каждой отдельной задачи в Jenkins под кнопкой Advanced для каждого триггера поменять шаблон — например, на успешную сборку слать ссылку, а на сломанную — нет.
    • +1
      Воспользуйтесь для этого testflight.
      После успешной сборки полученные артефакты тем же скриптом отправлюются на тестфлай в соотвествии с описанным API: https://testflightapp.com/api/doc/

      В самом тестфлает нужно настроить группу пользователей, которые будут получать уведомление о загруженной сборке.
  • 0
    Мы как раз сделали динамическую генерацию манифеста и странички (писал об этом тут: habrahabr.ru/post/175203/#first_unread )
    А теперь вот идея появилась, что ссылку можно и почтой отправлять
    • 0
      А мы читали вашу статью :)
      У нас похожий способ генерации страничек, выращенный из iOSBetaBuilder, но мы в статье делали упор на два Xcode — в преддверии так сказать :) ну и в целом инструкция — вещь полезная.

      Еще недавно находили идею — сделать мобильное приложение для получения Push-уведомений, и с Jenkins слать ссылки на него. Мне кажется, пуши лучше подходят для тестировщиков, письма — для менеджеров и заказчиков.

      Но это тема для отдельной статьи.
      • 0
        а почему нельзя скопировать старый сдк (см /Applications/Xcode/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/ ) и добавить в новый хкод? а далее разруливать параметром sdk
        iOS 6.1 -sdk iphoneos6.1
        iOS 7.0 -sdk iphoneos7.0
        • 0
          Потому что в каждом SDK по отдельности не содержится тулчейн (компилятор и его друзья), он общий для всех SDK в XCode. Скопировав SDK из другой версии XCode, можем поймать много веселых проблем в системных заголовочных файлах.
          • 0
            там же образом доставляется симулятор из настроек хкода. можно пример проблемы?
            • 0
              Проблемы у меня были когда я таким методом доставлял OSX 10.6 SDK в XCode 4.3. Были ошибки где-то в системных заголовочных файлах.

              SDK рассчитаны для сборки определенной версией компилятора, с другими версиями никто не тестировал, проблемы возможны, хотя и не гарантированы.
              • 0
                симуляторы то как раз качаются одни и теже (можно проверить по контрольным суммам образов в кеше хкода). Но в общем идея ясна. Спасибо
  • 0
    > cat /Users/jenkins/pass | sudo xcode-select -switch /Applications/XcodeVX.X.app/Contents/Developer
    а не лучше ли настроить sudoers? по моему, это как-то более правильный путь. И пароль в этом случае не надо светить в конфигурации сборки.
    • 0
      Сколько не пытались решить проблему через /etc/sudoers ничего толком не получилось. В линуксе такое без проблем решается, а в макоси все как-то иначе.
      • 0
        Все без проблем решается. Ничуть не отличается от Linux. У меня все работает.
        • +1
          Если не хочется писать пароль в файл, а это проще для начинающих, можно внести в файл sudoers строчку
          username ALL=NOPASSWD: /usr/bin/xcode-select

          В нашем случае:
          jenkins ALL=NOPASSWD: /usr/bin/xcode-select

          но если доступ к jenkins ограничен, то можно использовать и файл, увидеть его содержимое можно только если есть доступ к Jenkins или собственно к машине с Xcode.
          • 0
            Спасибо.
            Слона то я и не приметил :)
  • +3
    AFAIK xcode-select в вашем случае не нужен, достаточно запускать xcodebuild c полным путем (Ex: /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild, в каждом XCode есть свой xcodebuild, помимо копии в /usr/bin/xcodebuild).

    Как это сделать при помощи XCode-плагина для Jenkins я не знаю, мы запускали при помощи Jenkins shell-скрипт, который в свою очередь вызывал xcodebuild.

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

Самое читаемое Разработка