Continuous Integration для мобильных и веб-проектов

Добрый день, в своей статье, хочу рассказать, всем известную практику разработки ПО — Continuous Integration или Непрерывная интеграция.
Чтобы сразу пояснить в чем особенность статьи объясню, что в нашей команде стояла задача построить единый процесс для всех наших проектов. А проекты у нас бывают как мобильные (iOS, Android) и веб (верстка, сервисы, сайты).

Введение

В самом начале, позвольте кратко рассказать, что же такое непрерывная интеграция и чем она может пригодиться.
Непрерывная интеграция (англ. Continuous Integration) — практика разработки ПО, при котором осуществляется автоматизированная сборка продуктов для выявления интеграционных проблем. Wikipedia

А если проще — это «всего лишь» возможность при нажатии одной кнопки (или вообще автоматически) получить готовую сборку вашего продукта (приложения, сайта).
Чем это может быть полезно?
В первую очередь, ваш QA отдел скажет вам спасибо, так как им не надо будет каждый час теребить разработчика в надежде получить сборку на тестирование.
Во вторых — у вас будет возможность тестировать всю вашу систему в целом, что позволит вам заранее отловить все интеграционные ошибки.
И в третьих — заказчик будет вам благодарен если один раз получив ссылку на проект он в любой момент времени сможет посмотреть в каком состоянии ваш проект и за что он платит деньги.

Итак, цель — создать систему для сборки проектов под различные платформы (web + mobile). Поиск привел нас к нескольким существующим решениям в этой области:

  • Hudson
  • CruiseControl
  • TeamCity
  • FastBuilder

Посмотрев каждый, поискав минусы и плюсы, мы остановились на варианте Hudson. Этот инструмент на тот момент показался нам наиболее гибким и поддерживаемым сообществом. После мы уже узнали что от него есть ветка Jenkins, но переходить на него не стали т.к. Hudson всем и всех устраивал.
В качестве системы контроля версий у нас исторически был выбран Git, с помощью него мы храним версии исходных кодов и сборок. Так же, с помощью хуков мы публикуем текущие версии проектов на тестовом сервере.
И наконец то, ради чего мы все затеяли — корпоративный веб-портал, который отвечает за доступы пользователей к сборкам, хранении информации по ним и наконец за то чтобы можно было зайти, скачать и протестировать их. Мы назвали его Публикатор и это написанный нами на Python (Django) несложный веб-сервис. Выглядит это вот так —
Continuous Integration portal

Реализация

А теперь подробнее о том, как это все работает:
При старте проекта создается репозиторий под исходный код и новый проект в Hudson. В настройках проекта мы указываем адрес репозитрий и выставляем настройки чтобы репозиторий опрашивался каждые 5 минут и в случае изменений запускается сборка. Для Hudson есть немало плагинов, которые могу автоматически собирать различные типы проектов, но нам хотелось все попробовать самим и в итоге у нас сборка представляет из себя скрипт командной строки.
Сами скрипты сборок отличается от типа проектов.
Самый простой — веб-проект, в этом случае текущая версия репозиторий собирается в архив и выкладывается в доступ.
Далее по сложности идет сборка Android проекта, тут вначале мы обновляем ant сценарий (которые по умолчанию поддерживаются Android SDK) командой, а затем запускаем сгенерированный скрипт сборки. Например вот так:

android update project --target 10 --name ProjectName
ant debug

В результате, мы получаем готовый apk файл, который можно скачать и установить на устройство. В данном примере мы не рассматривали вариант с подписью проекта для публикации в GooglePlay. Но, это все так же можно сделать средствами командной строки с помощью утилит SDK.
И наконец, самый интересный вариант — сборка iOS. Если использовать стандартный способ предлагаемый компанией Apple — приложение нужно собрать, подписать сертификатом разработчика и только потом установить его (обычно это делают через iTunes). Мы решили максимально упростить этот процесс. В итоге проект собирается следующим образом: с помощью утилиты xcodebuild мы компилируем и собираем проект в приложение app. После этого с помощью утилиты xcrun подписываем его сертификатом разработчика (который лежит на сервере сборок) и готовый apk файл отправляем в общий доступ.

xcodebuild -project ProjectName.xcodeproj
xcrun -sdk iphoneos PackageApplication -v ProjectName.app -o ~/path/projectname.ipa -embed "~/path/provision.mobileprovision"

В данном случае собирается тот Target, который был установлен у разработчика в самом xCode, но и этот параметр можно принудительно установить.
Наконец, все сборки (ipa, apk, zip) попадают в общий доступ и перед нами встала задача как пользователю их проверить. С веб-проектом проблем нет — рядом с ним есть ссылка на тестовый сервер, Android apk файл можно просто скачать с телефона и установить. И остается проблема установки iOs приложения. Пользователю в идеале, нужно просто зайти на портал с устройства, нажать на ссылку и установить приложение. И такая возможность есть. Почитав документацию и поиска в интернете мы решили эту проблему. Чтобы iPhone перейдя по ссылке начал устанавливать приложение, эта ссылка должна быть вида itms-services://?action=download-manifest&url=http://server/projectname.plist По этому адресу должен лежать xml файл, структура которого описана в документации и который можно получить при сборке проект в xCode если установить галочку Enterprise при упаковке приложения. Основные поля в этом файле:

<!-- Ссылка на ipa файл -->
<key>url</key>
<string>http://server/distribs/prokectname.ipa</string>

<!-- Идентификатор приложения -->
<key>bundle-identifier</key>
<string>ru.handh.projectname</string>

<!-- Название приложения -->
<key>title</key>
<string>ProjectName</string>

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

Заключение

В данный момент, у нас каждый причастный к проекту может зайти на наш портал, скачать последнюю версию проекта и протестировать ее. И туда мы можем публиковать проекты всех платформ которыми занимаемся (Web, iOS, Android). А в дальнейшем хотим прикрутить туда публикация результатов Unit тестирования и уведомление о неудачных сборках.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 21

    +2
    Я так понимаю Hudson у вас установлен на Mac OS?

    Ну а в целом вы конечно же конкретно урезали понятие CA до «всего лишь» подготовки билда для OTA (Over the Air) distribution, равзе что собирается он автоматически.
    Как минимум в CI входят хотя бы юнит тесты, ну это ладно, если они в Xcode проекте есть, они обычно вместе с билдом выполняются.
    Но и это не все, если открыть ту же самую статью в вики, только на английском, можно прочитать следующее
    In addition to automated unit tests, organisations using CI typically use a build server to implement continuous processes of applying quality control in general — small pieces of effort, applied frequently. In addition to running the unit and integration tests, such processes run additional static and dynamic tests, measure and profile performance, extract and format documentation from the source code and facilitate manual QA processes.


    Мне бы было очень интересно прочитать статью о том, как делать regression тестирование для iOS с помощью того же Hudson, как запускать автоматически iOS симулятор и прогонять на нем тесты, или даже автоматически устанавливать билды на тестовые девайсы и выполнять тесты на них, и т.д. Еще интересно как автоматизировать тестирование мобильного UI в рамках CI и с помощью каких инструментов этого добиться, как, например, запустить много iOS симуляторов на разных виртуальных машинах, и автоматизировать весь процесс.
      +1
      >>> Я так понимаю Hudson у вас установлен на Mac OS?
      Для запуска xcodebuild и пр. обязательно нужен slave на Mac OS.
      При этом если собираетесь запускать симулятор, то Hudson нужно ставить не демоном (читай «из *.dmg»), а в userspace (читай «из *.war плюс скриптовая магия»).
      В моём случае (не путать с автором статьи) это один mac mini, поскольку ведроидом пока не занимаюсь.

      >>> Мне бы было очень интересно прочитать статью о том
      А я-то думал, здесь все ну оооочень умные — вот и не пишу. Надо будет подумать над этим…

      А пока вот вам немного устаревший материал.
      Раз, Два

      Обновлять пока смысла не вижу. И не я один такой

      Для тестов использую calabash
      Почитать про Build&Analyze можно в документации clang
        0
        В моём случае (не путать с автором статьи) это один mac mini, поскольку ведроидом пока не занимаюсь.

        Ну по идее Mac OS вполне справится с Android, там весь тулчейн доступен практически для любой оси.

        Надо будет подумать над этим…

        Подумайте, что уж :) Мне эта тема как раз сейчас очень даже интересна. До этого момента занимался нативной разработкой под iOS, буквально через пару недель перехожу на новую работу, как раз на позицию связанную с тестированием мобильных приложений. Там все только начинается, еще даже не сделан окончательный выбор инструментов. Например, в плане автоматизации тестирования UI рассматривают вариант MonkeyTalk.
          0
          >>> Там все только начинается, еще даже не сделан окончательный выбор инструментов.

          Итого, я пришел к следующему набору job-ов и инструментов.
          Надеюсь, будет вам полезно.

          1. OTA (Over the Air) distribution
          Jenklins xCode plug-in + script для заливки в testflight. «Родной» testflight pug-in пока нормально настроить не получилось
          Иногда собираю под симулятор когда QA «дрались» за device-ы (один смотрит на device, а другой — увы через iphonesim).

          2. Static analyzer.
          Clang «scan-build» с принудительным выставлением компилятора в тот, что поставляется с xCode

          3. Unit test (Sen testing kit)
          Обычный xcodebuild (не привязывая к application/library в качестве dependence).
          Для них можно считать coverage с помощью gcovr + cobertura plug-in

          4. gh-unit тесты
          Гоняются через «iphonesim» и скриптовую магию (см. презентации по ссылкам выше). Coverage для них пока считать не умею

          5. UI тесты
          calabash + Jenkins TAP plug-in

          6. Документация
          Пока только appledoc. Latex еще не осилил (да и вряд ли понадобится).

          Небольшой бонус для любителей framework-ов.

          P.S. CocoaPods я не забыл, а намеренно не упомянул.
            0
            Ок, спасибо.

            Интересует пара моментов по пунктам.

            Негативные результаты static analyzer'а репортятся как ошибки и «забраковывают» весь билд?
            И почему «намерянно не умпомянул» CocoaPods? Он каким-то боком не вписывается в процесс CI?
            Сам использую pods, многие open source проекты полны warning-ов, а некоторые содержат код, который не нравится статическому анализатору, dead value storage, например, а иногда и вещи посерьезнее.

            И насколько «зрелый» calabash? Тот же MonkeyTalk, про который я писал выше, имеет свои недостатки. Я взял очень простое приложение, которое использует только родные контролы, storyboard с обычными переходами и т.д. Запустил приложение, проделал простейшие действия, получил скрипт этого дела. Только выясняется, что в этом скрипте изначально не учитываются задержки между жестами, если его просто проиграть, приложение не успевает обработать действия так быстро. Но это мелочи, даже когда добавил задержки, все равно тот же скрипт не выполняется корректно, в самом конце он в упор откзывается «узнавать» кнопку по тегу, который сам же выдал в процессе записи. Другая проблема с UIGestureRecognizer'ами, напрмер обычный UITapGestureRecognizer вызывает селектор вроде — (void)handleTap:(UITapGestureRecognizer *)tgr. Абсолютно корректный код, работает без проблем в куче приложений, а в билде с включенным MonkeyTalk агентом входной параметр tgr внезапно становится объектом класса NSArray и вызов вроде tgr.state рушит приложение, как-будто MonkeyTalk агент занимается какой-то промежуточной магией и вставляет свои перехватчики где захочет, подменяя параметры своими мета-данными. Такой код уже и не протестируешь толком, разработчиков тоже не заставишь писать код с учетом недокументированного поведения MonkeyTalk агента. Т.е. проект во многом сырой и не выглядит как более-менее завершенный продукт, придется не только искать баги в своем приложении, но и разбираться, почему MonkeyTalk не работает.
        0
        Цель статьи рассказать о различиях сборки для разных платформ.
        В заключении статьи написано, что тестирование — наш следующий шаг и возможно, тема следующего поста :) А пока что unit тесты, как вы написали, прогоняются в режиме прошли/не прошли и никак системой сборки не анализируются.
        Насчет regression тестирования — тоже очень хотелось бы реализовать, но это уже чуть позже. Если вообще получится.

        Да, Hudson стоит на отдельном Mac OS. На нем установлены iOS и Android SDK
        0
        А как с номерами версий у вас устроено дело? Допустим, есть текущая версия 7.0, над которой все работают, а надо выпустить срочно 6.4 SR, которая решает какие-то проблемы.

        Сколько задач в hudson, как работаете с ветками в git, как скрипт сборки узнает «узнает» про номер версии.
          0
          В hudson сейчас 12 задач.
          Сама система собирает всегда из ветки master, если принудительно не указать другую при создании проекта.
          Номер версии — инкремент при выполнении каждой задачи. Текущий номер берется из проекта xcode или eclipse.
          Если нужно выпустить версию 6.4 SR, то все зависит насколько часто она будет востребована. Если она нужна один раз что закрыть баги — то это делает сам разработчик :( Если же это отдельные продукт, то в hudson создается новая задача для него и указывается отдельная ветка. При сборке соотвественно будет. что нибудь вроде 6.4.1, 6.4.2 и т.д.
            0
            >>> А как с номерами версий у вас устроено дело?
            xCode plug-in умеет сам версию в нужный Info.plist «вшивать».

            >>> Допустим, есть текущая версия 7.0, над которой все работают, а надо выпустить срочно 6.4 SR, которая решает какие-то проблемы.
            То есть, вопрос «как вы пользуетесь git tag/branch»?
            Каждый выбирает для себя. А иногда за вас выбирает начальство и заставляет сидеть на уродливом SVN…
            0
            Bamboo как вариант вы не рассматривали? Мы в итоге остановились именно на Bamboo.
              0
              Первым делом приглянулся именно Hudson, т.к. нашли для него плагины для тестирования Android приложений и поддержки эмуляторов. На тот момент это было самым важным для нас функционалом.
              0
              Интересно, но в качестве средства доставки приложений тестировщикам рассмотрите TestFlightApp.com
              Работает с Adroind и iOS + предоставляет SDK для получения крашлогов.
              Закачку можно автоматизировать, уведомлении о новых версиях тоже рассылаются, можно мониторить установки и конкретные версии приложений, управлять списками допущенных к тестированию отдельных проектов. Вообщем, очень рекомендую.
                0
                >>> Чтобы iPhone перейдя по ссылке начал устанавливать приложение, эта ссылка должна быть вида itms-services://?action=download-manifest&url=http://server/projectname.plist

                У них там свой testflight — with blackjack and hookers. Чтобы враги не украли( дизассемблировали ) драгоценные приложения. git, небось, тоже сами хостят.
                Корпорасты иногда выдвигают подобные требования…
                  0
                  Ну… маркеры у каждого свои, на вкус и цвет подобранные :)
                  На tesflightapp ты тоже закачиваешь уже готовые apk/ipa.
                    0
                    Не обязательно «свой testflight». При разработке enterprise приложений, важной частью является OTA distribution, этот процесс нужно наладить, автоматизировать, если нужно, проработать все возможные варианты, учесть возможные особенности IIS или Mac OS серверов, и т.д. А TestFlight все это дело делает за разработчика. В целом, TestFlight прекрасен, конечно же, но в плане креш-логово мне на данный момент больше нравится Crashlytics, чисто субъективно, хотя у них еще даже нет своего пода в CocoaPods.
                      0
                      На данный момент у нас OTA реализован на том уровне который нам нужен был. А именно
                      — пользователь может оставить свой UDID
                      — администратор (как и в testFlight если я не ошибаюсь) должен прописать его в профиль
                      — пользователь заходит с устройства на сайт и тут же ставит себе приложение OTA
                      В TestFlight прикручены различные вкусности вроде уведомлений, приглашений и управления. Но нам пришлось отказаться от этого в угоду «безопасности». Хотя некоторые проекты мы оставили в TF )
                    0
                    Как уже написали — у нас свой TestFlight (с шахматами и поэтессами))
                    Именно по причине беспокойства заказчиков (как это вы наше приложение куда то залили?!)
                    0
                    Попробуйте лучше jenkins — это тот же Hudson, но поэтессы красивее и в шахматах больше фигур.
                      0
                      Да, думаем на него переходить. Тем более там ест ьвсе что нам нужно — плагины для Android и iOS сборок.
                    0
                    так переход довольно простой — подмена варника и переименование папки с .hudson на .jenkins и потом уже борьба с совместимостью плагинов — это самое трудоемкое

                    Only users with full accounts can post comments. Log in, please.