Предыстория
Есть проект на Unity3D. Есть уже несколько лет (родился в феврале 2012 года). Через полгода я начала работать на нем программистом, а через два года мне не повезло и я стала ответственной за сборку билдов. В наследство мне достался MacMini с установленным сборщиком Jenkins, минимум документации и отсутствие адекватной сборки для iOS.
Хочется наконец написать адекватную инструкцию — ибо на первоначальную настройку было убито несколько недель, а при переносе на iMac мои старые наработки уже устарели. Итак…
Техническое задание
- Проект разрабатывается на движке Unity3D. Тк разработка продолжалась длительное время, то версия движка успела смениться с 3.5.6 до 4.6.6 (на момент написания статьи поддержки 5 версии пока не планируется). У каждой версии есть свои глюки, некоторые версии содержат жизненно важные правки для одной платформы и в то же время убивают сборку на другой. К примеру — в последних версиях добавлена поддержка 64b для iOS, в ранних 4.x версиях существовала сборка под плагин Google Chrome и Flash, от версии к версии меняется рекомендуемый Android SDK. Нужно иметь все.
- Проект находится на svn сервере. Конкретно — subversion.assembla.com. Нужна поддержка сборки из разных веток, различных подпроектов, а также проектов, включающих части других проектов.
- Сборка должна осуществляться для Android (Google Play, Amazon App Store, Yandex Store ...), iOS, Windows, Mac OS, Linux (все — с возможностью публикации в Steam). Некоторые части — собираться для запуска в браузере. Здесь рассмотрим только особенности сборки под каждую конфигурацию.
- Нужен доступ к билдам из локальной сети, чтобы тестировщик мог скачать, установить и протестировать.
- Автономная сборка, автозапуск после сбоя (отключение питания)
Железо
Почему собираем на яблочной продукции? Потому что надо собирать iOS приложения и отправлять их в AppStore. Иметь хакинтош или виртуалку — иметь проблемы.
Итак, есть старенький MacMini в офисе и новейший iMac дома. Оба справляются со своей работой, разница в производительности и подходе — на первый отсутствует гарантия и его не жалко (желание убить его об стол возникает каждую неделю), второй — любовно протирается тряпочкой и бережется.
Итак, для желающих — ознакомиться со сборкой и разборкой первого девайса — добро пожаловать сюда. Потребность в сборке возникла после смерти старого диска. Благодаря инструкции — успешно вскрыт и вставлен новый диск на 1 ТБ.
Здесь стоит сделать отступление — я предпочитаю иметь жесткий диск с несколькими разделами, а возможно даже и с несколькими операционками. Однако, если тип накопителя Fusion Drive — сделать это не получится (мой iMac имеет на диске максимум — два раздела, и на втором обитается Windows). Если диск обычный — проблем никаких. Можно хранить все важные данные в одном разделе (и бэкапить его с помощью Time Machine), а тяжеловесные копии проекта хранить на другом.
Установка системы
Заслуживает отдельной статьи. Кратко:
- На новейших маках есть интернет-установка. Иначе — нужен дисковод или флешка с образом системы. Вход в меню установки Cmd+R.
- Все диски и разделы обзываем понятными именами. Разделы с системой и рабочими данными форматируем обязательно в Mac OS Extended (Journaled). Обязательно — не Case-sentive.
- Для установки софта потребуется Apple Id. Желательно, чтобы этот Apple Id соответствовал аккаунту разработчика Apple, который используется при подготовке и заливке билдов.
- Помимо аккаунта администратора необъодим аккаунт с обычными правами. Называем его jenkins, паролим также.
- Если кто-то нуждается в удаленном доступе через Chrome Remote Desktop — придется предоставить аккаунту права администратора.
- Ставим нормальный браузер и полезный софт по желанию.
- Если возникли проблемы с отображением страниц — Steam Community, YouTube и других — смотрим раз и два.
Установка Xcode
- Последняя версия обычно ставится из магазина.
- При установке нескольких версий — желательно выделить отдельную папку и ставить туда. К примеру — в /Applications/Xcode лежат Xcode_5_1_1.app и Xcode_6_1_1.app.
- Старые версии можно найти здесь.
Установка 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
- Все операции выполняем под пользователем jenkins
- Качаем с оффсайта установщик. Ставим, переносим в удобное место, к примеру в/Users/jenkins/WORK/JENKINS_WAR/jenkins.war
- Заходим в терминал, выполняем команду запуска сборщика:
java -jar /Users/jenkins/WORK/JENKINS_WAR/jenkins.war
- Проверяем в браузере — 127.0.0.1:8080 наличие сборщика. После закрываем терминал (сборщик отключается)
- Создаем папку для временных файлов. К примеру — /Users/jenkins/WORK/JENKINS_TMP
- Создаем папку для сборщика. К примеру — /Users/jenkins/WORK/JENKINS_HOME. В нее копируем содержимое папки /Users/jenkins/.jenkins, а саму папку удаляем.
- Заходим в терминал и логинимся под администратора:
login dimamatik
- Удаляем старый файл конфигурации:
sudo rm /Library/Preferences/org.jenkins-ci.plist
- Заносим следующие параметры (можно поменять, по желанию):
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
- Проверяем:
defaults read $pp
- Простанавливаем права:
sudo chown root:wheel $pp sudo chmod 644 $pp
- Выгружаем демона дженкинса командой:
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
- Удаляем демона:
sudo rm /Library/LaunchDaemons/org.jenkins-ci.plist
- Выходим из-под администратора:
logout
- Запускаем сборщик через терминал еще раз (страница теперь 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
- Добавлен абзац по демону Jenkins, исправлена инструкция по его отключению.
- Добавлена ссылка на оффсайт в разделе про скачивание и установку сборщика.
- Комментарий для скрипта и приложения перезапуска.
Обновление 13.10.15
- Добавлена ссылка на вторую часть.
- Добавлена плашка tutorial.
Leopotam
Зачем столько телодвижений со всем вот этим если машина выделена чисто под сборку? Почему просто не включить автовход под нужным пользователем и дальше уже стартовать что захочется? Под тем же пользователем. Удаленный рабочий стол — если везде используется osx, то штатное решение работает прекрасно.
Leopotam
Так же установка не ssd винта на сборочную машину (ну и на мак-мини в частности) — это одна большая ошибка. Места там не нужно много, достаточно 64Гб винта, а вот ускорение будет весьма значительным, как при сборке, так и при шевелении самой osx (говорю как владелец mac-mini на i5, mac-mini на i7). Желательно правда взять винт хотя бы на 128Гб, а лучше на 256Гб — у них каналов по работе с блоками памяти побольше, что дает большую скорость по сравнению со старыми моделями.
dimamatik
А в статье тип диска упоминается только вскользь. На рабочем (в офисе) сборщике MacMini используется как раз SSD на 1 TB. И используется там таки уже 200+ГБ. По поводу выбора железа, на котором работать — ну, тут уже не от меня зависело. Что дали, то и используем
PS Тяжело писать без смайликов, но, увы, правила
Leopotam
на 99% уверен, что там обычный 2.5" 5400rpm винт, ибо стоимость ssd-терабайтника явно несоизмерима со стоимостью «древного» mac-mini. По поводу 200Гб — тоже сомневаюсь, чтобы были такие проекты под ios на unity (вероятно, древняя версия svn, гадящая служебкой в каждом каталоге? Можно / нужно апгрейдится и вообще смотреть в сторону dcvs). Если это билд сервер — каждый раз на быстрый винт качается актуальный транк / нужный коммит, билдится и удаляется, хранить смысла нет.
dimamatik
Про железо сказать больше ничего не могу
svn 1.8 +, точную версию сейчас не скажу, то есть один каталог svn в корне проекта (за исключением тех, что используют externals)
200 ГБ — есть совокупность из нескольких копий одного проекта (под каждую платформу и для разных параметров сборки). Размера добавляет папочка с кэшем Unity и собственно svn данные. Есть еще история сборок, несколько бэкапов ну и по мелочи.
(точные данные — от 10 до 12 ГБ на одну копию проекта, необходимую для сборки)
Качать\билдить\удалять не пройдет. Движок Unity производит реекспорт всех ресурсов (текстуры, звук, модели) под каждую платформу, что занимает несколько часов. Плюс скачивание до часа, плюс сборка от получаса (легкие Android билды) до часа (iOS)
Leopotam
Но… зачем???? Ведь можно написать editor-код в юнити, который будет переключать платформу и настраивать нужные параметры + билдить в нужную папку из консоли в batchmode. Соответственно, переключение платформы будет происходить в одну и ту же папку.
Время переключения платформы косвенно подтверждает, что винт не ssd. Ну и возможно текстуры воткнуты в здоровом разрешении и уже в юнити ужаты в нужную циферку — внешняя утилита по пережатию картинок работает в 1 поток и юнити ждет пока она не отработает. :(
dimamatik
Вспомогательный код для редактора написан и успешно работает
Размер текстур — от 512 до 1024 в квадратике. При этом на мобильные платформы некоторые ужимаются. Время реимпорта библиотеки действительно получается очень большое. (Винт таки SSD)
Для разных параметров — означает, что для одной платформы, как правило, есть стандартная сборка, сборка для последнего релиза (для быстрой сборки патчей), иногда тестовая сборка для определенной фичи, которая базируется на отдельной ветке в репозитории. Постоянно перескакивать по веткам и ревизиям не хочется.
Различие в мелких параметрах (типа выбора подписываемого сертификата, включение или отключение какой-либо фичи, доавление тестовых сцен и тд) — прекрасно решается в рамках одной копии проекта уже в настройках самого сборщика.
Ну и совсем добивает то, что иногда, в случае критической ошибки, сборщик предпочитает полностью удалить проект и перекачать его заново. Приходится останавливать его и решать проблему на месте
Leopotam
Тогда решительно не понимаю, откуда часы смены платформы. Если macmini на i5 — там само железо слабовато, но замена винта на ssd дает второе дыхание. macmini на i7 после замены на ssd может заменить достаточно сильное офисное железо, можно даже поиграться при желании. Время смены платформы на 256гб кингстоне не сильно хуже времени смены на macpro 2013 («пепельница»), а на нем я ни разу не видел проект со временем переключения «толще» 20 минут.
dimamatik
подозреваю, что конкретно вот эта модель с i5 — support.apple.com/kb/SP659?locale=ru_RU
основное время — реимпорт текстур. Если проект собирается в чистой папке, то сначала скачается, потом импортнет все (в том числе и префабы) с дефолтными настройками, после чего начнет переимпорт под нужную платформу. И да, в проекте ОЧЕНЬ много текстур
dimamatik
Насчет удаленного рабочего стола — когда нужен доступ одновременно к трем-четырем компьютерам причем примерно одновременно, удаленка от Google работает хорошо.
К примеру, типичная задача — срочно собрать патч, находясь дома. Алгоритм:
Печенька — решение от Chrome бесплатно
по поводу остальных вопросов («Зачем столько телодвижений со всем вот этим если машина выделена чисто под сборку? Почему просто не включить автовход под нужным пользователем и дальше уже стартовать что захочется? Под тем же пользователем. „) — можно подробнее раскрыть, что имелось в виду?
Leopotam
Понял, думал, что удаленный рабочий стол нужен именно на билд-машину и с нескольких машин одновременно.
Про остальные телодвижения — невнимательно прочитал предпоследний абзац. Но зачем автоматор, раз уже пользуются шелл-скрипты?
dimamatik
чтобы в случае чего геймдизайнер с телефоном подошел к компу и два раза нажал на иконку, вместо работы с командами
Leopotam
Так а почему он вообще что-то должен жать? Как только ушел коммит — билд-сервер начал работу. Ну и регулярные билды по расписанию ночью.
dimamatik
если меня нет в офисе, а случилось что-то (список типичных ошибок сборки не хочется сейчас перечислять), а нужен срочно билд.
PS прошу прощения — рука дрогнула и комментарий не попал в ветку
Leopotam
Я про это: stackoverflow.com/questions/21194621/post-commit-hook-to-trigger-automatic-jenkins-build
Те дизайнер должен закоммитить изменение — оно автоматом запустит процесс билда.
dimamatik
да, так и есть, автосборка присутствует, будет во второй части статьи
Просто если человек услышал в полной тишине приятный женский голос «Сборка провалилась» и начинает звонить по телефону — это одно из решений
Leopotam
[offtop] т.е. можно не дожидаясь, сразу звонить и слышать в ответ «приятный женский голос «Сборка провалилась»» в вопросительной форме? :) [/offtop]
dimamatik
в ответ обычно фейспалм по телефону
просто дополнительной опцией к сборщику стоит звуковая сигнализация об успехах сборки