Первую часть можно найти здесь.

Обновление


Обновлять нужно как сам сборщик, так и его плагины. Страница настроек находится по адресу 127.0.0.1:4242/manage (с поправкой на свои настройки). В случае наличия новой версии на странице будет висеть кнопочка с предложением обновиться. Рекомендую все же скачать свежую версию самим, после чего аккуратно выключить сборщик, заменить jenkins.war файл и перезапустить его.
При обновлении jenkins.war может возникнуть ошибка, поэтому старый файл на всякий случай бэкапим. Почему? Сначала файлики появляются на японском сервере (автор сборщика — обыкновенный японский инженер, подробнее здесь), потом распространяются по зеркалам. Ссылки:



Настроить плагины можно на 127.0.0.1:4242/pluginManager/. Подробнее о плагинах будет в соответствующем разделе, однако рекомендую обновить уже имеющиеся.

Первичная настройка сборщика


Проекты под Unity не собираются параллельно.
ОДНАКО
YoungSkipper написал, что можно. После прочтения документации появилось желание попробовать — опишу изменения в следующей статье, после этого отредактирую абзац.
То есть одновременно может быть запущена только одна сборка на одном компьютере. По-умолчанию Jenkins создает один сборщик с несколькими исполнителями, что не есть хорошо. Переходим через графический интерфейс или напрямую на 127.0.0.1:4242/computer/(master)/configure в настройки и меняем "Количество процессов-исполнителей" на 1.

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

Здесь — 127.0.0.1:4242/configure — раздел общих настроек. Меняем следующие параметры:

  1. Проверяем, что домашняя директория указана верно. К примеру, /Users/jenkins/WORK/JENKINS_HOME
  2. Раскрываем расширенные настройки. "Корневая директория рабочей области" — место, где должны быть размещены проекты Unity. "Корневая директория записи сборки" — хранилище собранных билдов. Рекомендую изменить значения по-умолчанию, вынеся обе папки из JENKINS_HOME. К примеру, в /Users/jenkins/WORK/JENKINS_WORKSPACE/${ITEM_FULL_NAME} и в /Users/jenkins/WORK/JENKINS_BUILDS/${ITEM_FULL_NAME}.
  3. "Количество сборщиков" устанавливаем, как и ранее, в 1.
  4. "Задержка перед сборкой" устанавливаем, к примеру, в 60 секунд. Полезно, чтобы отменить неправильную или случайно запущенную сборку.
  5. Для сборки под Android может потребоваться различные JDK. В соответствующем разделе прописываем имена и пути (снимая галочку автоматической установки). К примеру, jdk_1.8.0_60 имеет JAVA_HOME в /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home. Этот пункт опционален, только при сильном желании использовать разные JDK при сборке.
  6. В разделе Jenkins Location можно указать адрес сборщика (в локальной сети, к примеру http://192.168.3.69:4242/)и почту администратора. Требуется для некоторых плагинов.
  7. В разделе Subversion, при наличии последних обновлений плагина, можно выбрать последнюю версию SVN. К примеру, 1.8. Версия должна совпадать с установленной в системе (до первых двух знаков), в противном случае нельзя будет вручную отредактировать проект, который был создан сборщиком автоматически. Ссылку на установку нужной версии смотреть в прошлой статье.


Jenkins CLI


Отдельно стоит упомянуть список удаленных команд сборщика. Вся необходимая информация здесь — http://127.0.0.1:4242/cli/. Скачивается jenkins-cli.jar и с помощью, к примеру, такой команды:
java -jar jenkins-cli.jar -s http://192.168.3.69:4242/ safe-shutdown

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

Плагины


Дополнительная функциональность сборщика поставляется путем плагинов. Настроить (установить, обновить, откатить, удалить) их можно в соответствующем разделе — 127.0.0.1:4242/pluginManager/installed. Полный список рядом, официальная вики — здесь. Жизненно необходимые ниже (остальные лучше просто обновлять, но напрямую с ними работать вряд ли получится):

  • Credentials Plugin — позволяет хранить пароли. К примеру, для SVN репозитория. В настройках сборщика — 127.0.0.1:4242/credential-store/ выбираем Global credentials и создаем для каждого репозитория связку имя-пароль. Параметры — Username and password и Global.
  • Subversion Plugin — поддержка SVN. Уже должен быть настроен.


Плагины, которые нужно скачать для настройки параметров сборок (некоторые могут установить связанные плагины):

  • conditional-buildstep — настройка действий сборщика, если при сборке произошла ошибка. Например, можно послать письмо с логом администратору или выполнить скрипт.
  • description setter plugin — создание описания собранного билда на основе параметров сборки.
  • Environment Script Plugin — объявление внутренних переменных (параметров) сборки.
  • Extensible Choice Parameter plugin — хранение параметров сборки отдельным файлом, к примеру в том же SVN, после апдейта из репозитория будет применена самая свежая версия настроек.
  • Groovy Postbuild — создание простейшего скрипта, обрабатывающего успешность сборки.


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

  • Extra Columns Plugin — дополнительные колонки в список задач. Содержат кнопки остановки, запуска задачи и тд.
  • Safe Restart Plugin — кнопка перезапуска сборщика прямо в графическом интерфейсе.
  • Custom Job Icon plugin — назначает каждой задаче свою специфическую иконку. К примеру, можно поставить иконку нужного приложения или платформы, под которую идет сборка. В настройках появится пункт Custom icons, куда можно загрузить свои иконки. Храниться они будут в /Users/jenkins/WORK/JENKINS_HOME/userContent/. При загрузке иконка ужимается до размера 64x64, так что ищем покрасивее.


Плагины для работы на Unity:

  • Unity3d plugin — плагин, интегрирующий в сборку вызов редактора Unity. При сильном желании можно обойтись без него (писать все команды в командной строке). После установки в настройках сборщика появится пункт Unity3d, в который можно внести список установленных редакторов. К примеру, создаем поле Unity_4_6_8_f1 со значением /Applications/Unity_4_6_8_f1/Unity.app. Оно будет использоваться, к примеру, для тестовых сборок. В качестве основной версии используем Unity_4_6_6_f2 и аналогично настроенный путь. Чтобы не обновлять в каждой задаче сборщика путь до текущей версии после перехода на новую — создаем Unity_Default с нужными параметрами.
  • Log Parser Plugin — анализирует вывод в лог и выводит примечания и ошибки. В настройках сборщика ищем в конце пункт Console Output Parsing и создаем unity_rules с путем к файлику с правилами. Источник можно найти здесь или ниже
    logpareser.rules
    start /^Initialize mono/
    start /^Mono dependencies included in the build/
    start /^Textures/
    info /^Complete size/
    start /^-----CompilerOutput:-stdout/
    info /^Compilation succeeded/
    start /^Used Assets, sorted by uncompressed size/
    info /^\*\*/
    info /^Exiting batchmode successfully now/
    start /^=== BUILD NATIVE TARGET/
    start /^Packaging IPA/
    start /^Archiving artifacts/
    start /Uploading to testflight/
    warning /error CS02446/
    error /^Error building Player/
    error /^Failed to compile/
    error /^Error:/
    error /^error:/
    error /: error CS/
    warning /^Warning:/
    warning /^WARNING:/
    error /^xcodebuild: error:/
    warning /Debug:LogWarning/
    error /There was an error/
    error /\*\*\* Cancelled/
    error /^FATAL:/
    error /^Fatal error/
    error /^ERROR:/
    error /syntax error/
    error /^UnityEngine.Debug:LogError/
    error /^System.Exception:/



Структура проекта


  1. Настроить репозиторий.
  2. Настроить файл с параметрами.
  3. Настроить платформу сборки.
  4. Настроить, выполнять ли запуск Unity или нет.
  5. Скачать данные из репозитория.
  6. Если настроен запуск Unity — собрать свежий билд.
  7. Сохранить результаты сборки в архив.
  8. Запустить скрипт в зависимости от результатов сборки (например, голосовая сигнализация).


Создание задачи (Job Item)


  1. На главной странице сборщика находим кнопку Создать Item. В параметрах выбираем задачу со свободной конфигурацией. В качестве имени выбираем что-то типа projectName_platform. Изменяя вторую часть для различных задач можно настроить потом простой фильтр по проектам. Переходим непосредственно к настройкам.
  2. Поскольку планируется использовать одни ресурсы для нескольких задач, первым делом меняем место проекта. Ищем "Расширенные настройки проекта", выбираем "Использовать другую директорию" и вводим что-то типа ../JENKINS_WORKSPACE/projectName_standalone. После чего возвращаемся к началу настроек.
  3. "Удалять устаревшие сборки" — выбираем нужный вариант. К примеру, хранить только несколько последних.
  4. Если был установлен плагин на пользовательскую иконку и иконки загружены — выбираем нужную.
  5. "Это — параметризованная сборка" — настраиваем этот параметр. Для этого нужен плагин Extensible Choice, установленный ранее. Шаблон таков — добавляется параметр данного типа, вводится его имя, выбирается, откуда ему читать данные. Данные можно хранить во внешнем файле (тогда выбираем System Groovy Choice Parameter и создаем скрипт чтения данных) или заранее занести в настройки сборщика в разделе Extensible Choice: Available Choice Providers. Здесь используем первый вариант. Важно! Во всех параметрах нужно заранее выбрать вариант по умолчанию. Но он будет доступен только после сохранения скрипта и повторного открытия страницы настроек.
  6. Настройка репозиториев. Создаем параметр REPOSITORY. Вносим все доступные во внешний файл, к примеру в /Users/jenkins/WORK/repositories.txt. После чего вбиваем скрипт:
    String _file="/Users/jenkins/WORK/repositories.txt";
    ArrayList _list=[];
    
    FileReader _reader = new FileReader(_file);
    String _line = null;
    while( ( _line = _reader.readLine() ) != null )
    {
        _list << _line;
    }
    return _list.sort();
    

  7. Выбор платформы сборки. Создаем PLATFORM, скрипт отличается только именем внешнего файла. Ниже — список платформ для 4.6 версий:
    unity_platforms.txt
    WebPlayer
    WebPlayerStreamed
    StandaloneOSXIntel
    StandaloneOSXIntel64
    StandaloneOSXUniversal
    StandaloneWindows
    iPhone
    PS3
    XBOX360
    Android
    StandaloneLinux
    StandaloneLinux64
    StandaloneLinuxUniversal
    FlashPlayer
    StandaloneWindows64
    WP8Player
    Tizen
    PSP2
    PS4
    PSM
    XboxOne
    SamsungTV

  8. Выбор файла настроек — PRESET.
    import hudson.*;
    import hudson.model.*;
    
    ArrayList _list=[];
    _list << "";
    FilePath _wp = new FilePath(new FilePath(jenkins.root),project.getCustomWorkspace());
    
    hudson.FilePath _dir = _wp.child("Assets/BuildPresets/");
    if (_dir.exists() == false) return _list;
    hudson.FilePath[] _files = _dir.list("*.asset")
    
    for (hudson.FilePath _file : _files) 
    {
        if (_file.isDirectory() == false) 
        {
            //_list << _file.getName();
           _list << _file.getBaseName();
        }
    }
    
    return _list.sort();
    

    Для этого скрипта включаем галочку Use predefined variables in scripts, которая позволяет обращаться к сборщику. Код напоминает Java, документацию можно найти здесь — http://javadoc.jenkins-ci.org/jenkins/model/Jenkins.html. Функция getCustomWorkspace предоставляет доступ как раз к тому местоположению, которое указали ранее. Если же использовать шаблон по умолчанию, то вбивать путь придется явно.
  9. Создаем параметр BUILD_UNITY. Для него отдельно выбираем Textarea Choice Parameter, где вбиваем в две строчки значения TRUE и FALSE.
  10. Настраиваем "Управление исходным кодом". Выбираем Subversion, в качестве адреса вводим ${REPOSITORY}, бесконечную глубину, выбираем логин и пароль для доступа (или создаем, если не сделали раньше). При сборке вместо введенного выражения подставится явное значение из файла. В качестве стратегии выбираем "сначала revert, потом update".
  11. Настраиваем "Триггеры сборки". Можно собирать задачу периодически, раз в сутки, к примеру, можно только после появления свежих версий в репозитории. К примеру, «H */8 * * *» в поле Опрашивать SCM об изменениях запускает сборку 3 раза в сутки при наличии свежей версии. Рядом с меню есть справка с описанием синтаксиса.

    Подробно о настройке других вариантов сборки тут. Нужно помнить, что если сборка ориентируется на свежую версию в репозитории и в настройках была выбран репозиторий, отличный от дефолтного — при изменении дефолтного сборка производиться не будет! Решение — вручную переключать следующую сборку или настроить сборку по триггеру или расписанию.
  12. Переходим в раздел Послесборочные операции в конце и добавляем шаг Groovy Postbuild. Простейший скрипт, анализирующий успешность сборки, ниже:
    String proc = "/bin/sh /Users/jenkins/WORK/build-failure.sh";
    if (manager.build.getResult() == hudson.model.Result.SUCCESS) proc = "/bin/sh /Users/jenkins/WORK/build-success.sh";
    proc.execute();
    


    В качестве скрипта ошибки, к примеру, можно использовать:

    say "Kill all humans"
    

  13. На этом этапе сохраняем настройки и запускаем сборку. Должна создаться директория, в нее скачан проект из репозитория, в конце задачи — отработать один из скриптов. В случае возникновения ошибок — проверяем, все ли файлы, используемые в скриптах, созданы, и проставлены ли у них корректные права доступа.
  14. Если все работает, возвращаемся в середину листа настроек. Выбираем "Generate environment variables from script" и вписываем что-то типа:
    BUILD_SUBDIR=`awk -F: '/location:/ {sub(/.*location: */,""); gsub(/\\\\/,"/"); print}' Assets/BuildPresets/${PRESET}.asset`
    BUILD_DIR="${WORKSPACE}/${BUILD_SUBDIR}"
    BUILD_VERSION=`../svnversion -c . | cut -f2 -d:`
    APPLICATION_NAME=`awk -F: '/buildName:/ {sub(/.*buildName: */,""); gsub(/\\\\/,"/"); print}' Assets/BuildPresets/${PRESET}.asset`
    BUILD_ARTIFACT=${APPLICATION_NAME}-${PRESET}-${BUILD_VERSION}.zip
    
    echo BUILD_SUBDIR=${BUILD_SUBDIR}
    echo BUILD_DIR=${BUILD_DIR}
    echo BUILD_VERSION=${BUILD_VERSION}
    echo APPLICATION_NAME=${APPLICATION_NAME}
    echo BUILD_ARTIFACT=${BUILD_ARTIFACT}
    


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

    Вторая часть — специально для сборочного процесса. Как написано в справке, для интеграции переменных непосредственно в сборку необходимо отправить их в /stdout в таком формате.
  15. Переходим в раздел Сборка и создаем шаг сборки Conditional steps (multiple). В условии запуска выбираем условие равенства строк и делаем проверку на равенство ${BUILD_UNITY} в одном поле и TRUE в другом. Все дальнейшие шаги выполняем в данном разделе. Такой порядок позволяет запустить задачу только на обновление данных.
  16. Добавляем шаг с командами shell. Перед сборкой нужно почистить директорию сборки — используем определенные переменные:
    rm -rf "$BUILD_DIR" || true 
    mkdir -p "$BUILD_DIR" || true
    

  17. Следующий шаг — Invoke Unity3D Editor. В параметрах указываем Unity_Default или конкретную версию. Параметры сборки имеют вид:
    -quit -batchmode -executeMethod Build.CmdBuild -buildPreset=$PRESET -switchBuildTarget=$PLATFORM
    


    Большинство команд можно найти в официальной справке здесь. Последние 2 параметра — специально для скрипта сборки, но можно использовать и стандартные -buildOSXPlayer, если нет специфических опций. Примеры скриптов и аргументов можно найти в информации о плагине Unity3dBuilder Plugin и в вики сообщества Unity.
  18. Последний шаг сборки — заархивировать результаты. Стандартная команда:
    cd `dirname ${BUILD_SUBDIR}`
    zip -qr "${BUILD_DIR}/${BUILD_ARTIFACT}" `basename ${BUILD_SUBDIR}`
    

  19. В разделе послесборочных операций можно добавить Описание сборки. К примеру, ${BUILD_VERSION} ${PRESET}. Оно будет отображаться рядом с билдом в истории сборщика.
  20. Архивируем результаты сборки. Можно перечислить все файлы, в этом примере нужно сохранить собранный архив ${BUILD_SUBDIR}/${BUILD_ARTIFACT}. Если пропустить этот шаг, то нельзя будет скачать результаты сборки. Если в настройках указана автоочистка результатов, то будут доступны только несколько последних.
  21. Самым последним шагом ставим парсинг логов с правилами для Unity. После этого задача для одной платформы полностью готова.

Создание новой задачи


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

В настройках View можно создать фильтр по задачам и вывести необходимую информацию о сборках на главную страницу. В итоге может получиться что-то типа:

image

В следующей части — сборка под Android, iOS, разбор частых ошибок сборщика и самой Unity.

Обновление 13.10.15

  1. Замечание YoungSkipper по поводу сборки нескольких билдов одновременно. Постараюсь реализовать и отредактировать в случае успеха, однако macmini может не потянуть.

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


  1. YoungSkipper
    13.10.2015 17:29

    По крайней мере вот это

    Проекты под Unity не собираются параллельно. То есть одновременно может быть запущена только одна сборка на одном компьютере.
    не верно. У нас в пиковый момент на билд сервере может одновременно думаю до проектов 7-ми собираться. Т.е. семь инстансов юнити запущено может быть — как и одной версии, так и разных.


    1. YoungSkipper
      13.10.2015 17:31

      У юнити еще забавный, не совсем очевидный баг есть со сборкой. Если размер лог файла начинает превышать 2gb то юнити падает с невнятной ошибкой. У нас проект сборки ресурсов много писал в лог, плюс колл стеки раскрывается. И в какой-то момент, оно начало падать. Так как сборка инкрементальная — про при повторном запуске было все ок. Намучались мы.


      1. dimamatik
        13.10.2015 21:54

        Все может быть… Потом опишу пару интересных багов. К примеру, в зависимости от того, под каким пользователем зайти и запустить сборку напрямую из редактора или из командной строки — будет различие в трактовке написания вещественных чисел. К примеру, 5.6f, может быть 5.6 или 5,6. Пришлось переписывать все такие места…
        Лог файл в 2GB — я слабо себе представляю, что там может быть. У меня репозиторий проекта в текстовых дампах 30ГБ занимает


        1. YoungSkipper
          13.10.2015 22:14

          С флоатами небось по конвертации забыли указать CultureInfo.InvariantCulture, а так поведение то ок — разная локаль, различное представление.

          А с логом — хороший глубокий стек-трейс потянет на 3кб, ну а дальше 10к+ сущностей, по 10 записей в лог на сущность, 10+ типов бандлов (различные сжатия + sd/hd) и вуаля. У нас бандлы тоже на билд сервере собираются.


          1. dimamatik
            13.10.2015 22:19

            Не всегда сработает… Забили такой вариант, чтоб наверняка:

            float.TryParse (str.Trim ().ToLower ().Replace (',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out val)
            

            И ведь указывали же, и в разных плагинах — свои проверки. А вот стоит перенести на новый компьютер (iMac) как посыпалось…
            Пока прогнали все тесты и нашли — несколько часов убили. И ведь как обычно, у всех все работает!


    1. dimamatik
      13.10.2015 21:49

      Странно, мой предшественник сказал, что нельзя. Вполне возможно, что это было из раздела «лучше не надо».
      В документации — вроде как можно, но нужно поколдовать с параметрами.
      Думаю, сделаю примечание в статье и напишу подробнее в последней части. Хотя, подозреваю, нужен мощный комп, тк два редактора на офисном макмини (см первую статью) не шибко быстро работают.


      1. YoungSkipper
        13.10.2015 22:16

        Уточню — что один проект (физически в одной папке находящийся) таки нельзя. Но в целом же каждый план/job — это отдельная папка.