Предыстория


Есть проект на Unity3D. Есть уже несколько лет (родился в феврале 2012 года). Через полгода я начала работать на нем программистом, а через два года мне не повезло и я стала ответственной за сборку билдов. В наследство мне достался MacMini с установленным сборщиком Jenkins, минимум документации и отсутствие адекватной сборки для iOS.

Хочется наконец написать адекватную инструкцию — ибо на первоначальную настройку было убито несколько недель, а при переносе на iMac мои старые наработки уже устарели. Итак…

Техническое задание


  1. Проект разрабатывается на движке Unity3D. Тк разработка продолжалась длительное время, то версия движка успела смениться с 3.5.6 до 4.6.6 (на момент написания статьи поддержки 5 версии пока не планируется). У каждой версии есть свои глюки, некоторые версии содержат жизненно важные правки для одной платформы и в то же время убивают сборку на другой. К примеру — в последних версиях добавлена поддержка 64b для iOS, в ранних 4.x версиях существовала сборка под плагин Google Chrome и Flash, от версии к версии меняется рекомендуемый Android SDK. Нужно иметь все.
  2. Проект находится на svn сервере. Конкретно — subversion.assembla.com. Нужна поддержка сборки из разных веток, различных подпроектов, а также проектов, включающих части других проектов.
  3. Сборка должна осуществляться для Android (Google Play, Amazon App Store, Yandex Store ...), iOS, Windows, Mac OS, Linux (все — с возможностью публикации в Steam). Некоторые части — собираться для запуска в браузере. Здесь рассмотрим только особенности сборки под каждую конфигурацию.
  4. Нужен доступ к билдам из локальной сети, чтобы тестировщик мог скачать, установить и протестировать.
  5. Автономная сборка, автозапуск после сбоя (отключение питания)

Железо


Почему собираем на яблочной продукции? Потому что надо собирать iOS приложения и отправлять их в AppStore. Иметь хакинтош или виртуалку — иметь проблемы.

Итак, есть старенький MacMini в офисе и новейший iMac дома. Оба справляются со своей работой, разница в производительности и подходе — на первый отсутствует гарантия и его не жалко (желание убить его об стол возникает каждую неделю), второй — любовно протирается тряпочкой и бережется.

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

Здесь стоит сделать отступление — я предпочитаю иметь жесткий диск с несколькими разделами, а возможно даже и с несколькими операционками. Однако, если тип накопителя Fusion Drive — сделать это не получится (мой iMac имеет на диске максимум — два раздела, и на втором обитается Windows). Если диск обычный — проблем никаких. Можно хранить все важные данные в одном разделе (и бэкапить его с помощью Time Machine), а тяжеловесные копии проекта хранить на другом.

Установка системы


Заслуживает отдельной статьи. Кратко:

  1. На новейших маках есть интернет-установка. Иначе — нужен дисковод или флешка с образом системы. Вход в меню установки Cmd+R.
  2. Все диски и разделы обзываем понятными именами. Разделы с системой и рабочими данными форматируем обязательно в Mac OS Extended (Journaled). Обязательно — не Case-sentive.
  3. Для установки софта потребуется Apple Id. Желательно, чтобы этот Apple Id соответствовал аккаунту разработчика Apple, который используется при подготовке и заливке билдов.
  4. Помимо аккаунта администратора необъодим аккаунт с обычными правами. Называем его jenkins, паролим также.
  5. Если кто-то нуждается в удаленном доступе через Chrome Remote Desktop — придется предоставить аккаунту права администратора.
  6. Ставим нормальный браузер и полезный софт по желанию.
  7. Если возникли проблемы с отображением страниц — Steam Community, YouTube и других — смотрим раз и два.

Установка Xcode


  1. Последняя версия обычно ставится из магазина.
  2. При установке нескольких версий — желательно выделить отдельную папку и ставить туда. К примеру — в /Applications/Xcode лежат Xcode_5_1_1.app и Xcode_6_1_1.app.
  3. Старые версии можно найти здесь.

Установка Unity3D


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

По умолчанию после установки Unity.app, MonoDevelop.app и документация лежат в /Applications/Unity. Если требуется установить несколько версий — сначала переименовываем старую папку установки, к примеру /Applications/Unity_4_6_6_f2, только после этого ставим новую версию и переименовываем место установки тоже. Все версии и патчи можно найти здесь.

MonoDevelop достаточно оставить самый свежий, прописав в настройках каждой Unity путь. В папке /Users/Shared можно обнаружить дефолтный проект Unity — его можно снести.

Для пользователя jenkins необходимо проставить права на запуск всех файлов. При необходимости — и на все содержимое .app.

Также в настройках отключаем автооткрытие последнего проекта и регистрируем каждую копию.

Установка Java, JDK, Android SDK


JDK и JRE можно скачать с оффсайта. Android SDK качаем отсюда. После установки — обновляем SDK и прописываем в каждой Unity путь до него и проверяем на тестовой сборке. Пример работающей конфигурации:
  • OS X 10.10.5
  • Unity 4.6.6f2
  • jdk-8u60-macosx-x64
  • Android SDK: Tools 24.3.4
  • Android SDK: Platform-tools 23.0.1
  • Android SDK: Build-tools 23.0.1
  • Android SDK: SDK Platform API 23

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

Установка SVN


Согласно этомуsubversion поставляется в комплекте с системой. Для установки специфической версии — рекомендую использовать Homebrew, подробнее ищем здесь.

Установка Jenkins


  1. Все операции выполняем под пользователем jenkins
  2. Качаем с оффсайта установщик. Ставим, переносим в удобное место, к примеру в/Users/jenkins/WORK/JENKINS_WAR/jenkins.war
  3. Заходим в терминал, выполняем команду запуска сборщика:

    java -jar /Users/jenkins/WORK/JENKINS_WAR/jenkins.war
    

  4. Проверяем в браузере — 127.0.0.1:8080 наличие сборщика. После закрываем терминал (сборщик отключается)
  5. Создаем папку для временных файлов. К примеру — /Users/jenkins/WORK/JENKINS_TMP
  6. Создаем папку для сборщика. К примеру — /Users/jenkins/WORK/JENKINS_HOME. В нее копируем содержимое папки /Users/jenkins/.jenkins, а саму папку удаляем.
  7. Заходим в терминал и логинимся под администратора:

    login dimamatik
    

  8. Удаляем старый файл конфигурации:

    sudo rm /Library/Preferences/org.jenkins-ci.plist
    

  9. Заносим следующие параметры (можно поменять, по желанию):

    pp="/Library/Preferences/org.jenkins-ci.plist"
    sudo defaults write $pp JENKINS_HOME "/Users/jenkins/WORK/JENKINS_HOME"
    sudo defaults write $pp tmpdir "/Users/jenkins/WORK/JENKINS_TMP"
    sudo defaults write $pp war "/Users/jenkins/WORK/JENKINS_WAR/jenkins.war"
    sudo defaults write $pp httpPort 4242
    

  10. Проверяем:

    defaults read $pp
    

  11. Простанавливаем права:

    sudo chown root:wheel $pp
    sudo chmod 644 $pp
    

  12. Выгружаем демона дженкинса командой:

    sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
    

  13. Удаляем демона:

    sudo rm /Library/LaunchDaemons/org.jenkins-ci.plist
    

  14. Выходим из-под администратора:

    logout
    

  15. Запускаем сборщик через терминал еще раз (страница теперь 127.0.0.1:4242). Все должно работать.

Подробнее можно узнать здесь и здесь.

Автозагрузка, перезапуск, смерть


Проблема смерти и реанимации сборщика усугубляется использованием Mac и сборки на Unity. Пишем и сохраняем скрипты:

  • Скрипт запуска сборщика jenkins-runner.sh:

    #!/bin/sh
    "/Library/Application Support/Jenkins/jenkins-runner.sh" &
    

  • Скрипт убийства сборщика jenkins-killer.sh:

    #!/bin/sh
    ps xa | grep jenkins.war | grep -v grep | awk '{print $1}' | xargs kill -9
    

  • Скрипт перезапуска jenkins-restart.sh:

    #!/bin/bash
    (sh ~jenkins/jenkins-killer.sh) && (sh ~jenkins/jenkins-runner.sh)
    


Для автоматического старта сборщика создаем специальное приложение при помощи Automator. Выбираем шаблон Run AppleScript и создаем jenkins-restart.app в той же папке, куда сбросили остальные скрипты. Код программы ниже:

    on run {input, parameters}
    tell application "Terminal"
            activate
            if (the (count of the window) = 0) or (the busy of window 1 = true) then
                tell application "System Events"
                    keystroke "n" using command down
                end tell
            end if
            do script "sh ~jenkins/jenkins-restart.sh"
        end tell
    return input
    end run


В случае, если скрипты лежат не в домашней папке — соответствующе редактируем пути.

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

Подробнее о демоне — смотреть на вики или в общей справке. Вообще говоря, можно было бы не использовать Automator, а оставить данный механизм, добавив в скрипты выгрузку и загрузку демона. Однако плагины выключения и перезагрузки сборщика могут работать некорректно.

Что имеем


На данный момент система должна работать. Сборщик (пока пустой) автоматически запускается при старте системы. Любой проект на Unity должен нормально собираться (руками) из-под пользователя jenkins. При возникновении ошибок — смотрим на разрешения, установленные компоненты, оплачиваем задолжности за лицензию. Самое интересное впереди…

Вторая часть может быть найдена здесь.

Обновления 06.10.15

  1. Добавлен абзац по демону Jenkins, исправлена инструкция по его отключению.
  2. Добавлена ссылка на оффсайт в разделе про скачивание и установку сборщика.
  3. Комментарий для скрипта и приложения перезапуска.

Обновление 13.10.15

  1. Добавлена ссылка на вторую часть.
  2. Добавлена плашка tutorial.

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


  1. Leopotam
    06.10.2015 18:46

    Зачем столько телодвижений со всем вот этим если машина выделена чисто под сборку? Почему просто не включить автовход под нужным пользователем и дальше уже стартовать что захочется? Под тем же пользователем. Удаленный рабочий стол — если везде используется osx, то штатное решение работает прекрасно.


    1. Leopotam
      06.10.2015 19:11

      Так же установка не ssd винта на сборочную машину (ну и на мак-мини в частности) — это одна большая ошибка. Места там не нужно много, достаточно 64Гб винта, а вот ускорение будет весьма значительным, как при сборке, так и при шевелении самой osx (говорю как владелец mac-mini на i5, mac-mini на i7). Желательно правда взять винт хотя бы на 128Гб, а лучше на 256Гб — у них каналов по работе с блоками памяти побольше, что дает большую скорость по сравнению со старыми моделями.


      1. dimamatik
        06.10.2015 21:19

        А в статье тип диска упоминается только вскользь. На рабочем (в офисе) сборщике MacMini используется как раз SSD на 1 TB. И используется там таки уже 200+ГБ. По поводу выбора железа, на котором работать — ну, тут уже не от меня зависело. Что дали, то и используем

        PS Тяжело писать без смайликов, но, увы, правила


        1. Leopotam
          06.10.2015 21:59

          на 99% уверен, что там обычный 2.5" 5400rpm винт, ибо стоимость ssd-терабайтника явно несоизмерима со стоимостью «древного» mac-mini. По поводу 200Гб — тоже сомневаюсь, чтобы были такие проекты под ios на unity (вероятно, древняя версия svn, гадящая служебкой в каждом каталоге? Можно / нужно апгрейдится и вообще смотреть в сторону dcvs). Если это билд сервер — каждый раз на быстрый винт качается актуальный транк / нужный коммит, билдится и удаляется, хранить смысла нет.


          1. dimamatik
            06.10.2015 22:10

            Про железо сказать больше ничего не могу
            svn 1.8 +, точную версию сейчас не скажу, то есть один каталог svn в корне проекта (за исключением тех, что используют externals)
            200 ГБ — есть совокупность из нескольких копий одного проекта (под каждую платформу и для разных параметров сборки). Размера добавляет папочка с кэшем Unity и собственно svn данные. Есть еще история сборок, несколько бэкапов ну и по мелочи.
            (точные данные — от 10 до 12 ГБ на одну копию проекта, необходимую для сборки)
            Качать\билдить\удалять не пройдет. Движок Unity производит реекспорт всех ресурсов (текстуры, звук, модели) под каждую платформу, что занимает несколько часов. Плюс скачивание до часа, плюс сборка от получаса (легкие Android билды) до часа (iOS)


            1. Leopotam
              06.10.2015 22:17

              под каждую платформу и для разных параметров сборки

              Но… зачем???? Ведь можно написать editor-код в юнити, который будет переключать платформу и настраивать нужные параметры + билдить в нужную папку из консоли в batchmode. Соответственно, переключение платформы будет происходить в одну и ту же папку.
              Время переключения платформы косвенно подтверждает, что винт не ssd. Ну и возможно текстуры воткнуты в здоровом разрешении и уже в юнити ужаты в нужную циферку — внешняя утилита по пережатию картинок работает в 1 поток и юнити ждет пока она не отработает. :(


              1. dimamatik
                06.10.2015 22:34

                Вспомогательный код для редактора написан и успешно работает
                Размер текстур — от 512 до 1024 в квадратике. При этом на мобильные платформы некоторые ужимаются. Время реимпорта библиотеки действительно получается очень большое. (Винт таки SSD)

                Для разных параметров — означает, что для одной платформы, как правило, есть стандартная сборка, сборка для последнего релиза (для быстрой сборки патчей), иногда тестовая сборка для определенной фичи, которая базируется на отдельной ветке в репозитории. Постоянно перескакивать по веткам и ревизиям не хочется.

                Различие в мелких параметрах (типа выбора подписываемого сертификата, включение или отключение какой-либо фичи, доавление тестовых сцен и тд) — прекрасно решается в рамках одной копии проекта уже в настройках самого сборщика.

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


                1. Leopotam
                  06.10.2015 22:41

                  Винт таки SSD

                  Тогда решительно не понимаю, откуда часы смены платформы. Если macmini на i5 — там само железо слабовато, но замена винта на ssd дает второе дыхание. macmini на i7 после замены на ssd может заменить достаточно сильное офисное железо, можно даже поиграться при желании. Время смены платформы на 256гб кингстоне не сильно хуже времени смены на macpro 2013 («пепельница»), а на нем я ни разу не видел проект со временем переключения «толще» 20 минут.


                  1. dimamatik
                    06.10.2015 22:55

                    подозреваю, что конкретно вот эта модель с i5 — support.apple.com/kb/SP659?locale=ru_RU
                    основное время — реимпорт текстур. Если проект собирается в чистой папке, то сначала скачается, потом импортнет все (в том числе и префабы) с дефолтными настройками, после чего начнет переимпорт под нужную платформу. И да, в проекте ОЧЕНЬ много текстур


    1. dimamatik
      06.10.2015 21:13

      Насчет удаленного рабочего стола — когда нужен доступ одновременно к трем-четырем компьютерам причем примерно одновременно, удаленка от Google работает хорошо.
      К примеру, типичная задача — срочно собрать патч, находясь дома. Алгоритм:

      1. Подсоединиться со своего домашнего компа или планшета к любому офисному компу и запустить сборку с релизными параметрами. Пойти попить чай
      2. Скачать собранный билд. Если сборка под Steam — можно проверить прямо в офисе запуск на Windows и Mac
      3. В случае возникновения ошибок сборки (напишу подробнее в продолжении) — исправить напрямую из-под Mac. Это может быть и типичная ошибка проекта, и ошибка сборщика
      4. Наконец, в AppStore приходится заливать из-под офисного Mac


      Печенька — решение от Chrome бесплатно

      по поводу остальных вопросов («Зачем столько телодвижений со всем вот этим если машина выделена чисто под сборку? Почему просто не включить автовход под нужным пользователем и дальше уже стартовать что захочется? Под тем же пользователем. „) — можно подробнее раскрыть, что имелось в виду?


      1. Leopotam
        06.10.2015 22:09

        Понял, думал, что удаленный рабочий стол нужен именно на билд-машину и с нескольких машин одновременно.
        Про остальные телодвижения — невнимательно прочитал предпоследний абзац. Но зачем автоматор, раз уже пользуются шелл-скрипты?


        1. dimamatik
          06.10.2015 22:11

          чтобы в случае чего геймдизайнер с телефоном подошел к компу и два раза нажал на иконку, вместо работы с командами


          1. Leopotam
            06.10.2015 22:17

            Так а почему он вообще что-то должен жать? Как только ушел коммит — билд-сервер начал работу. Ну и регулярные билды по расписанию ночью.


            1. dimamatik
              06.10.2015 22:21

              если меня нет в офисе, а случилось что-то (список типичных ошибок сборки не хочется сейчас перечислять), а нужен срочно билд.

              PS прошу прощения — рука дрогнула и комментарий не попал в ветку


              1. Leopotam
                06.10.2015 22:23

                Я про это: stackoverflow.com/questions/21194621/post-commit-hook-to-trigger-automatic-jenkins-build
                Те дизайнер должен закоммитить изменение — оно автоматом запустит процесс билда.


                1. dimamatik
                  06.10.2015 22:36

                  да, так и есть, автосборка присутствует, будет во второй части статьи
                  Просто если человек услышал в полной тишине приятный женский голос «Сборка провалилась» и начинает звонить по телефону — это одно из решений


                  1. Leopotam
                    06.10.2015 22:43

                    [offtop] т.е. можно не дожидаясь, сразу звонить и слышать в ответ «приятный женский голос «Сборка провалилась»» в вопросительной форме? :) [/offtop]


                    1. dimamatik
                      06.10.2015 22:50

                      в ответ обычно фейспалм по телефону
                      просто дополнительной опцией к сборщику стоит звуковая сигнализация об успехах сборки


  1. dimamatik
    06.10.2015 22:20

    bad comment, deleted