Jenkins программное обеспечение. Jenkins. Continuous Integration – это просто. Ну, почти☺. Создание задачи Jenkins

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

Термины и определения

Прежде чем приступать к основной части, необходимо дать определение используемых терминов.

Непрерывная интеграция (CI, Continuous Integration) - практика разработки программного обеспечения, которая заключается в слиянии рабочих копий в общую основную ветвь разработки несколько раз в день и выполнении частых автоматизированных сборок проекта для скорейшего выявления потенциальных дефектов и решения интеграционных проблем. [wiki ]

Jenkins – проект для непрерывной интеграции с открытым исходным кодом, написанный на Java. [jenkins.io ]

Автоматизированное тестирование – это процесс верификации программного обеспечения, при котором основные функции и шаги теста, такие как запуск, инициализация, выполнение, анализ и выдача результата, выполняются автоматически при помощи инструментов для автоматизированного тестирования. [protesting ]

Немного о CI

В настоящее время Continuous Integration – одна из практик, применяемых в Agile методологии. В подобных методологиях она удачно сочетается с другими практиками, такими как unit тестирование, рефакторинг, стандарт кодирования. Но даже без них можно получить пользу от непрерывной интеграции. Из определения Continuous Integration следует его самая главная идея – найти ошибку на ранней стадии проще для разработки и дешевле для бизнеса. Поэтому, если в проект вносятся достаточно большие изменения, необходимо обязательно проводить тестирование (unit-тесты, автоматизированные тесты).

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

  • тесты запускаются после каждого коммита – это идеальный вариант для unit-тестов и спорный для end-to-end, почему поясню ниже;
  • тесты запускаются один раз в сутки (чаще всего ночью). Этот вариант не подойдет для unit-тестов, поскольку приложение долгое время может оставаться в нерабочем виде, но достаточно неплохой вариант для автоматизированных функциональных end-to-end тестов, особенно когда тесты занимают длительное время;
  • тесты запускают перед выпуском релиза – один из самых плохих вариантов использования, но и его можно тоже использовать в условиях ограниченных ресурсов, а новая функциональность, разрабатываемый в своей ветке, проверяется один или несколько раз в день.

Инструментов для CI существует достаточно много:

  • из локальных можно выделить – GitLab CI, TeamCity, Bamboo, Jenkins, Hudson, Circle CI;
  • облачные – BitBucket Pipelines, Heroku CI, Travis, Codeship, Buddy CI, AWS CodeBuild.

Jenkins

Почему стоит использовать именно Jenkins:

  • бесплатный и надёжный;
  • большое количество мануалов по работе, а значит учиться работать с ним проще;
  • легко забэкапить и развернуть на другой машине в течение 5 минут;
  • осуществлять управление можно конфигурированием и перемещением xml файлов.

Из минусов отметил бы:

  • частый выход новых версий, если используется не LTS;
  • интеграция с различными сервисами завязана на множество различных плагинов;
  • иногда может появится задача, которая требует нестандартного подхода.

Приведу запомнившийся пример. Необходимо поддерживать несколько версий продукта, которые работают с разными версиями java и если проект запускался не с той версией, то тесты стабильно начинали падать. Для этого пришлось добавлять плагин – Environment Injector, также добавить дополнительный шаг в сборке, который в зависимости от версии продукта изменял параметры рабочего окружения для использования конкретной версии java:

В случае возникновения кейса, описанного в примере выше, на TeamCity достаточно было указать версию java при запуске прогона.

Отдельно отмечу, что в данном случае Jenkins использовался исключительно для запуска автоматизированных тестов, т.к. они были достаточно длительными и требовали высокого уровня производительности.

Идеальный процесс разработки можно представить так:

  • разработчик отправляет код в репозиторий;
  • на сервере непрерывной интеграции изменения объединяются с основным кодом, выполняются юнит-тесты;
  • полученные на предыдущем шаге артефакты загружаются в отдельную тестовую среду, где приложение тестируется автотестами;
  • дальше всё проверяется для попадания на продакшн;
  • развёртывание на продакшене.


Установка Jenkins

Про установку написано достаточно много и подробно, самый лучший мануал конечно от разработчиков – Installing Jenkins.

Резервное копирование

Можно использовать встроенные плагины, но могут быть проблемы совместимости разных версий плагинов, поэтому для этой цели мы пришли к использованию bash скриптов которые входили в отдельную сборку, которая запускалась несколько раз в день\неделю. Например, скрипт jenkins-backup.sh – выполнял сохранение текущей рабочей конфигурации: view, job, настроек окружения, плагинов, которые сохранялись в отдельный архив, который можно переносить и использовать далее.

Установка из сохраненной копии

1.Необходимо установить java и инструмент архивации, в нашем случае unzip.

2. Разархивировать ранее сохранённый файл (предварительно перейдя в каталог с сохранным архивом):

unzip Jenkins.zip -d %path_To_Jenkins%

3. Перейти в каталог Jenkins и выполнить запуск Jenkins командой

cd %path_To_Jenkins% && java -jar jenkins.war

4. Зайти в WEB интерфейс по порту 8080.

Если вы работаете с linux машиной по ssh, то после закрытия соединения, вероятно, Jenkins будет остановлен. Для того чтобы избежать такого поведения можно использовать такой приём: выполнить команду с добавлением символа & – в результате команда будет выполняться в фоне, а управление будет возвращено обратно в командную строку, а для того чтобы при отключении от удаленной системы не завершались запущенные задачи можно использовать утилиту nohup, которая позволяет процессам продолжать работу даже после того, как вы выйдете из системы:

nohup java -jar jenkins.war &

Добавление Jenkins в службы

Для того чтобы в linux системах избежать ситуации, описанной в предыдущем абзаце, можно установить Jenkins как службу, для того чтобы каждый раз после перезагрузки Jenkins стартовал автоматически. Для этого необходимо создать файл /etc/systemd/system/jenkins.service командой:

Sudo cat /etc/systemd/system/jenkins.service sudo vi /etc/systemd/system/jenkins.service

и добавить содержимое в jenkins.service:

Description=Jenkins Daemon Environment="JENKINS_HOME=%path_To_Jenkins%" ExecStart=/usr/bin/java -jar %path_To_Jenkins%/jenkins.war User=имя текущего пользователя WantedBy=multi-user.target

Выполнить перезапуск службы сервисов: sudo systemctl daemon-reload

Команда для запуска сервиса jenkins: sudo systemctl start jenkins.service

перезапуска sudo systemctl restart jenkins.service

Важно отметить , что файл jenkins.war может быть расположен где угодно. Для того чтобы “подхватились” текущие параметры проекта, можно использовать команду, которая выполнит монтирование раздела Jenkins к работающему jenkins:

sudo mount -o bind /%path_To_Jenkins%/ ~/.jenkins/

Такой вариант будет работать только до перезагрузки системы, поэтому можно создать симлинк в директории ~/:

cd ~/ && sudo ln -s /%path_To_Jenkins%/ .jenkins

Добавление и подготовка к работе node в Jenkins

Данный раздел написан с учетом практики, что жизненный цикл у Jenkins и node ограничен, например, 2 неделями или месяцем.

Для добавления slave node в Jenkins можно добавить каждую машину руками, но из-за этого требуется постоянно заходить на машину и выполнять одни и те же операции, а это приводит к мысли, что всё можно максимально автоматизировать.
Для этого достаточно создать несколько Job, которые будут последовательно выполнять:

  1. заказ машин для добавления в качестве slave node в Jenkins;
  2. добавлять ранее заказанные машины в Jenkins с использованием rest api или Jenkins cli;
  3. выполнять развертывание необходимого окружения.

Все выше названные действия можно выполнять, используя дополнительные инструменты: ansible – для развертывания и настройки необходимых параметров и docker – как для развертывания Jenkins, так и для установки окружения на slave nodes.

Заключение

Главное, чтобы словосочетание “непрерывная интеграция” были на вашем проекте не только красивыми новомодными словами, но и действиями. И если вы, хотя бы минимально, будете соблюдать принципы CI, то проблем в жизненном цикле разработки станет гораздо меньше, а сам процесс станет приятнее. Опрос с интересной статистикой использования CI на проекте –

У нас есть сервер, на котором лежит множество проектов на WordPress и Magento CMS. Мне как PHP-разработчику была поставлена задача внедрить Jenkins для этих проектов, чтобы публикация изменений исходного кода на сервер происходила быстрее.

К чему нам Continuous Integration?

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

CI многими уже давно и успешно применяется. Использование этого метода разработки позволяет существенно сократить время на публикацию проекта на сервер, сводя эту работу к исполнению нескольких консольных команд. Кроме того, при применении CI имеется возможность в любое время оперативно вернуться к предыдущей версии проекта, благодаря тому, что Continuous Integration неразрывно связана с репозиторием системы контроля версий.

Принцип работы CI довольно прост. В моем случае участвовало 3 сервера:

  • Сервер системы контроля версий (СКВ), где хранится репозиторий с рабочей версией проекта, в который разработчик сохраняет свои изменения.
  • Сервер Continuous Integration, на котором установлена одна из систем управления CI.
  • Сервер, где развернута рабочая версия проекта.

Сразу после изменения репозитория в системе контроля версий, сервер СКВ инициирует выполнение задачи на сервере CI (как правило, с помощью веб-хука). Эта задача выполняет сборку и развертывание исходного кода из репозитория СКВ на сервер рабочей версии проекта.

Развертывание исходного кода из репозитория СКВ на сервер рабочей версии проекта.

Более подробно о преимуществах, которые предоставляет использование Continuous Integration, можно почитать в этой статье .

Данное руководство собирает в себе информацию, достаточную для того, чтобы быстро сконфигурировать систему CI Jenkins и начать работу с ней. Также здесь представлена информация по настройке и организации взаимодействия такой популярной системы CI, как и не менее известной системы контроля версий Git. В качестве веб-сервиса для git будем использовать GitHub .

Внимание, задача

Необходимо установить и настроить Jenkins таким образом, чтобы при push-е в репозиторий GitHub происходило обновление измененных файлов на сервере рабочей версии проекта. В наличии:

  • Сервер Debian 8.2 x64.
  • Система на локальной машине: Linux Mint 17.2.

Предварительным требованием является установленный git на обеих машинах. Про то, как его установить, можно прочитать .

Решение

1. Установка Jenkins

Установку выполним на выделенном для CI сервере. Вводим следующие команды для добавления репозитория Jenkins в список репозиториев системы:

Sudo wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | apt-key add - sudo echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list

Обновим apt и установим Jenkins:

Sudo apt-get update sudo apt-get install jenkins Перезапустим Jenkins: /etc/init.d/jenkins restart

Теперь порт 8080 сервера CI будет «прослушиваться» Jenkins. Это значит, что при переходе в браузере по адресу 8080 , пользователь попадет в панель управления Jenkins. Конечно, такой способ доступа является не очень удобным, поэтому на сервере CI можно настроить доступ к Jenkins с помощью виртуальных хостов в Apache или Nginx.


Приветственное окно Jenkins.

Следующим важным шагом является настройка прав доступа. Это очень важно, особенно если сервер доступен через Интернет. Без соответствующих настроек он будет открыт для всех.

2. Добавление администратора

Manage Jenkins → Configure Global Security (глобальная настройка безопасности).

1. Заполняем необходимую информацию:

  • Enable security — true; //включить защиту;
  • Jenkins’own user database — «Jenkins’ own user database»; //использовать для авторизации базу данных Jenkins;
  • Authorization — «Matrix-based security»; //матричное распределение прав доступа (распределение прав на уровне проектов);
  • User/group to add — «admin». //предоставляем пользователю «admin» право доступа в панель управления Jenkins.

Добавление администратора.

2. Сохраняем настройки.

Теперь при попытке входа в панель управления Jenkins будет требовать от пользователя авторизоваться.

3. Создание пользователя для GitHub

Теперь необходимо создать учетные данные для доступа GitHub к серверу Jenkins.

В панели управления Jenkins переходим Manage Jenkins → Manage Users → Create User . Заполняем форму регистрации, идентичную той, которая была при регистрации администратора, нажимаем Sign Up .

После создания пользователя следует дать ему необходимые права. Для этого перейдем в Manage jenkins → Configure Global Security (настройка глобальной безопасности).

Из всех этих настроек нам необходима матрица безопасности .

Для начала добавим пользователя в эту матрицу. В поле «User/group to add» вводим имя созданного пользователя и нажимаем Add . Пользователь появится в матрице. Предоставим ему права на чтение и сборку. Для этого в подстолбцах Read и Build столбца «Job» напротив имени созданного пользователя устанавливаем чек-боксы и нажимаем Save .


Создание пользователя для GitHub.

4. Установка плагина для GitHub

Переходим в Manage Jenkins → Manage Plugins → Вкладка «Available» . Выбираем для установки три плагина:

  • Github Authentication plugin;
  • GitHub plugin;
  • GitHub API Plugin.

Нажимаем на кнопку «Download now and install after restart» и ожидаем завершения установки.

5. Настройка сервера для работы с Jenkins

На продукционном сервере проекта (куда будет производиться автодеплой) необходимо создать пользователя «jenkins»:

Ssh-keygen

И вводим необходимую информацию.

Также для доступа необходимо добавить публичный ключ в файл... /jenkins/.ssh/authorized_keys (если файла нет, его необходимо создать)

Кроме этого требуется создать на GitHub открытый SSH ключ для данного сервера. О том, как это сделать, можно посмотреть .

Данный этап завершен.

Если что-то по ssh-аутентификации является непонятным, рекомендую прочитать очень полезную на данную тему.

6. Настройка доступа к серверу

Для того чтобы Jenkins при автодеплое на сервере с рабочей версией проекта мог авторизовываться на нем, в панели управления требуется создать необходимые данные для аутентификации. Для этого в панели управления Jenkins переходим Credentials → Global credentials → Add Credentials и делаем следующее:

  1. В качестве Kind выбираем «SSH Username with private key»;
  2. Username — вводим имя созданного на сервере пользователя («jenkins») ;
  3. Private Key — «Enter directly», в текстовое поле копируем все содержимое файла приватного ключа jenkins-пользователя. («.../jenkins/.ssh/id_rsa»);
  4. Нажимаем «OK».

Настройка доступа к серверу.

Теперь необходимо настроить подключение к серверу. Для этого в панели управления jenkins перейдем Manage Jenkins → Manage Nodes → New Node . Производим следующие действия:

  1. Вводим имя продукционного сервера (к примеру — «target»), устанавливаем «Dumb Slave», нажимаем «OK»;
  2. Вводим путь к корневой директории Jenkins на продукционном сервере. В качестве корневой директории на целевом сервере обычно выбирается директория пользователя jenkins («.../jenkins»);
  3. Вводим «Labels»; например — «target_server». Label — это метка, по которой задача будет привязываться к конкретному серверу;
  4. Host — вводим имя хоста, к которому будем обращаться;
  5. Credentials — выбираем ранее созданные данные для аутентификации;
  6. Нажимаем «Save».

Через некоторое время, подключение к серверу должно успешно установиться. Если все прошло успешно, в Manage Jenkins → Manage Nodes вы должны увидеть примерно следующую картину:


Настройка подключения к серверу.

Если подключение не устанавливается, нажимаем на созданное подключение («target»), выбираем «Log» в левом навигационном меню и смотрим, что произошло не так.

Наиболее распространенными ошибками являются:

Первое решение — изменить в настройках подключения корневую директорию на домашнюю директорию пользователя Jenkins.

Второе решение — предоставить пользователю Jenkins права на запись и чтение указанной в настройках подключения директории.

7. Настройка хука GitHub

Для GitHub-репозитория, который будет использоваться, необходимо настроить веб-хук так, чтобы при обновлении репозитория, хук отсылал запрос на обновление Jenkins. Для этого:

  • Переходим в созданный репозиторий на GitHub-е.
  • «Settings» → «Webhooks & services».
  • «Add webhook».
  • Вводим «Payload URL» (куда будет обращаться GitHub). Он должен иметь следующий формат
    <протокол>: //<имя пользователя для github в jenkins>: <пароль пользователя github в jenkins>@<домен>/github-webhook/
    (например — http://github:[email protected]:8080/github-webhook/).
  • «Content type» — «application/json».
  • «Which events would you like to trigger this webhook?» — «Just the push event».
  • «Active» — true.
  • Нажимаем «Add webhook».

Веб-хук создан.

8. Создание задачи Jenkins

Теперь необходимо создать задачу, которая будет выполняться при обновлении репозитория. В панели администрирования Jenkins делаем следующее:

  • Нажимаем «New Item».
  • Вводим название задачи в поле «Item name».
  • Выбираем «Freestyle project» и нажимаем «OK».
  • «Restrict where this project can be run» — вводим имя метки, которое было выбрано при добавлении сервера (например — «target_server»).
  • «Source Code Management» — выбираем «Git» и вводим адрес репозитория в поле «Repository URL» (например — «[email protected]: TestCi/Continuous-integration.git»).
  • В поле «Credentials» выбираем ранее созданные учетные данные.
  • «Build Triggers» — «Build when a change is pushed to GitHub».
  • «Build» — «Execute shell» (shell-скрипт будет выполняться при каждом push-е на github): sudo rsync -a —cvs-exclude —delete —omit-dir-times. / <директория проекта> sudo chown -R www-data: jenkins < директория проекта>

    Первая строка производит синхронизацию на продукционном сервере рабочей директории Jenkins с целевой директорией проекта. Вторая строка — установка владельца файлов проекта.

    — статья по настройке виртуальных хостов в Nginx;

  • digitalocean.com — статья по настройке виртуальных хостов в Apache.

Сегодня (да прямо сейчас) создается и производится множество различной организационной техники и гаджетов, которые не могут, и не будут работать правильно, без должного программного обеспечения. И тут понеслась 🤯

Давайте по порядку

Программное обеспечение (ПО) это программа или список программ, необходимых для работы компьютера или его устройств. Во как.

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

Программистам ставятся различные задачи по написанию софта, но человеческий фактор всегда имеет место быть, и при написании программы могут быть допущены ошибки, из-за чего софт просто не запустится, либо выдаст ошибку, исправление которой может занять большое количество времени, что в условиях современной экономики крайне не выгодно. Да и разработчик рискует получить по ж**е от Тимлида.

Слава небесам - для упрощения и ускорения данной задачи, в 2008 году был создан Jenkins .

Jenkins система с открытым исходным кодом, то есть продукт доступен для просмотра, изучения и изменения. Кстати создан на базе Java . Дженкинс позволяет автоматизировать часть процесса разработки программного обеспечения, без участия человека. Данная система предназначена для обеспечения процесса непрерывной интеграции программного обеспечения. Воу воу.

Непрерывная интеграция (Continuous Integration, CI ) это процесс разработки программного обеспечения, смысл которого заключается в постоянном соединении рабочих копий в общую линию разработки , и выполнении постоянных автоматизированных сборок проекта для быстрого выявления возможных ошибок и решения интеграционных проблем. Вот такой конвеер.

Иными словами, это создание нескольких драфтовых версий (черновиков) проекта, то есть копий, в предварительной сборке проекта.

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

Для начала разберемся, что такое деплой вообще. С английского "deploy " переводится как "развертывание ". И это целый процесс действий, которые делают программный продукт готовым к использованию:

  • выпуск ;
  • установка ;
  • активация ;
  • адаптация ;
  • обновление ;
  • исправление ошибок и другие.
Автоматический деплой это развертывание при помощи автоматизированных решений.

Многие пользователи скажут: "Зачем нужен Jenkins , когда есть Buildbot ?". У нас есть ответочка.

Основные плюсы и отличия Jenkins в том, что разобраться с ним может обычный, рядовой программист, либо менеджер не имеющий опыта в управлении. И сделает он это за короткий срок.

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

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

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

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

Стоит отметить основные преимущества Jenkins:

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

Посмотрите обучающие видео на YouTube и обязательно попробуйте этот инструмент. Уверены, вы совершенно не пожалеете. Но это не точно.

Полезна ли Вам эта статья?

Пожалуйста, расскажите почему?

Нам жаль, что статья не была полезна для вас:(Пожалуйста, если не затруднит, укажите по какой причине? Мы будем очень благодарны за подробный ответ. Спасибо, что помогаете нам стать лучше!

Прогрессивная часть девелоперской среды практикует методику непрерывной интеграции (CI ), и iOS-отдел компании Лайв Тайпинг решил к ней примкнуть, развернув сервер для сборок на платформе Jenkins. С тех пор началась совсем другая жизнь.

Что мы получили в итоге:

  1. Сервер начинает сборку:
    1. по веб-хуку в случае push’а в master-ветку;
    2. по команде в чате slack с указанием нужной ветки и доп. параметров.
  2. Выполняет Unit и UI -тесты.
  3. Получает следующие метрики:
    1. покрытие кода тестами;
    2. количество строк кода;
    3. дублирование кода;
    4. цикломатическая сложность кода.
  4. Архивирует проект в ipa, далее отправляет его на сервер сборок (собственной разработки) и отправляет в slack ссылку на сборку.

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

  1. сервер разворачивался под нужды iOS-разработки;
  2. установка большинства вспомогательных программ через homebrew, включая и сам Jenkins (быстрые обновления и удобство использования);
  3. использование xcodebuilder для всех задач сборки-тестирования (отказались от использования xctool из-за невозможности запуска UI -тестов);
  4. в качестве репозитория у нас используется GitLab;
  5. для хранения сборок мы используем сервер собственной разработки. Для каждой сборки генерируется уникальный URL , и далее достаточно открыть ссылку с мобильного устройства в браузере и нажать «Установить» - благодаря аккаунту Enterprise любой может установить приложение на телефон. Из-за специфичности действий, связанных с отправкой файлов на наш сервер, этот этап в статье не описывается;
  6. все наши проекты используют систему управления зависимостями СocoaPods.

Руководство получилось довольно громоздким, и мы решили разбить его на две части. Эта часть посвящена базовой установке и настройке Jenkins.

Что необходимо:

  1. Mac c установленным OS X и Xcode (В нашем случае MacBook Pro 2011 года с OS X 10.11.4);
  2. несколько часов свободного времени.

Создание пользователя Jenkins и его настройка

Пользователя можно создать как через консоль, так и используя GUI . Вряд ли во втором варианте возникнут сложности, поэтому мы лучше рассмотрим первый ():

#Создание группы ‘Applications’ dseditgroup -o create -n . -u username -p -r ‘Applications’ applications #Получение идентификатора для группы sudo dscl . -read /Groups/applications #Получение списка идентификаторов для пользователей (будет нужен уникальный идентификатор для пользователя) sudo dscl . -list /Users UniqueID #Создание пользователя (значения идентификаторов должны быть уникальными) sudo dscl . -create /Users/jenkins sudo dscl . -create /Users/jenkins PrimaryGroupID 777 sudo dscl . -create /Users/jenkins UniqueID 1777 sudo dscl . -create /Users/jenkins UserShell /bin/bash sudo ddcl . -create /Users/jenkins RealName "Jenkins" sudo dscl . -create /Users/jenkins NFSHomeDirectory /Users/jenkins sudo dscl . -passwd /Users/jenkins #Создание домашней директории и установка прав на неё sudo mkdir /Users/jenkins sudo chown -R jenkins /Users/jenkins

Наш пользователь готов, и теперь нам нужно зайти за него. Мы можем произвести вход в систему через GUI , либо зайти, используя консоль:

Sudo -u jenkins -i

Внимание: все дальнейшие действия мы совершаем под пользователем Jenkins.

Установка необходимых программ

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

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. Установка jenkins:

Brew install jenkins

Установка системы управления зависимостями cocoapods:

Sudo gem install -n /usr/local/bin cocoapods

Чтобы наш сервер автоматически запускался при старте системы, нам необходимо настроить запуск соответствующей задачи для launchd. У нас есть выбор: сделать это через LaunchAgents или LaunchDaemon. Мы воспользуемся именно LaunchAgents, т.к. это упростит* дальнейшую работу с Jenkins. Достаточно посмотреть на таблицу ниже, чтобы понять это:

Daemon Agent
Launch Time System start User login
User Type Non-login Login
Home Folder No Yes
Login Keychain No Yes
iOS Simulator No Yes
Provisioning Profiles No Yes

*Главная проблема запуска через Daemon заключается в том, что нельзя выполнить тестирование, не запустив iOS Simulator (подробнее про разницу использования демона и агента можно прочитать )

Однако из-за выбора LaunchAgents нам нужно решить проблему отсутствия залогиненного пользователя при запуске системы. Для этого необходимо настроить autologin. Мне известен только один способ это сделать: через GUI (Системные настройки -> Пользователи и группы -> Параметры входа -> Автоматический вход). Если кто-то знает, как это сделать через shell - пожалуйста, отпишитесь в комментариях!

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

1. выгрузим демона (был создан автоматически при установки Jenkins):

Sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.jenkins.plist

2. удалим демона:

Sudo rm /Library/LaunchDaemons/homebrew.mxcl.jenkins.plist

3. создадим агента:

Cd /Users/jenkins/Library/LaunchAgents tap homebrew.mxcl.jenkins.plist

4. настроим агента, используя vim-редактор:

Vim homebrew.mxcl.jenkins.plist

Пример содержимого файла plist:

Label homebrew.mxcl.jenkins ProgramArguments /usr/bin/java -Dmail.smtp.starttls.enable=true -jar /usr/local/opt/jenkins/libexec/jenkins.war -httpListenAddress=0.0.0.0 --httpPort=8080 RunAtLoad UserName jenkins

Здесь стоит обратить внимание на поле httpListenAddress со значением 0.0.0.0 и поле httpPort со значением 8080 - так сервер будет «прослушивать» любые ip-адреса по указанному порту.

Напомню: для закрытия и сохранения файла в редакторе vim вводим:wq
После установки Jenkins доступен по умолчанию по адресу 127.0.0.1 (localhost).
Для доступа из внешней сети можно пробросить порты на маршрутизаторе: 8080 для веб-интерфейса Jenkins и 22 для доступа по ssh.

Установка плагинов для Jenkins

Заходим на сервер Jenkins -> Настроить Jenkins -> Управление плагинами. Во вкладке «Доступные» находим и устанавливаем следующие плагины:

  1. Role-based Authorization Strategy - обеспечение безопасности. Даёт возможность создания групп пользователей с распределением прав;
  2. GitLab Plugin и Gitlab Hook Plugin- плагины для работы с gitlab;
  3. Xcode integration - интеграция с Xcode;
  4. Keychains and Provisioning Profiles Management - облегчает работу с provisioning profile.

Базовая настройка Jenkins

Через веб-интерфейс Jenkins`а заходим в «Настройки», а затем в раздел «Конфигурирование системы». На что здесь стоит обратить внимание:

1. Настройки Xcode Builder. Если вы устанавливали Xcode в стандартную директорию, то настройки менять не нужно. В противном же случае необходимо задать путь для указанных компонентов. Учитывая, что мы запустили сервер с использованием LaunchAgents, то Xcode будет иметь доступ к login.keychain. Но если вы хотите подстраховаться, то можете в этом разделе добавить keychain, как указано на скриншоте (здесь и далее нажмите на изображение для просмотра).

Теперь мы можем загрузить необходимые сертификаты через GUI или через shell в login.keychain, а Xcode будет автоматически подтягивать нужные ему во время сборки.

2. Для настройки доступа по ssh делаем так:

a. генерируем shh-ключ, если его нет (инструкцию для примера можно найти );

b. добавляем ключ в разделе CVS ;


c. для доступа к GitLab перейдём в раздел Credentials на главной странице веб-интерфейса Jenkins. Здесь необходимо добавить закрытый ключ для нашего пользователя (Jenkins в данном случае пользователь, зарегистрированный в GitLab). Вы можете вставить его непосредственно, как показано на примере ниже, или же указать путь к нему:


d. в настройках самого GitLab необходимо указать соответствующий открытый ключ:


3. Для настройки безопасности воспользуемся плагином Role-based Authorization Strategy. Перейдём в настройки через веб-интерфейс Jenkins, а далее в раздел Manage and Assign Roles. Здесь мы сможем создать различные роли, которые назначаются для пользователей и групп, и определить для них права на те или иные операции. Здесь каждый всё делает на своё усмотрение. Но, если вы настроили внешний доступ к серверу, настоятельно рекомендую убрать все права для пользователя «гость».

Создание job’а и настройка сборки проекта

1. На главной странице веб-интерфейса Jenkins выбираем «Создать Item». Далее выбираем пункт «Создать задачу со свободной конфигурацией» и вводим название проекта;
2. на странице настройки job’а первое, что мы сделаем - это перейдём во вкладку «Управление исходным кодом» и настроим загрузку проекта с GitLab. Здесь нам нужно ввести адрес репозитория нашего проекта, указать, с помощью каких полномочий (credentials) сервер получит доступ к GitLab и какую ветку проекта необходимо собрать:


3. Далее переходим в раздел «Сборка». Если вы используете систему управления зависимостями CocoaPods и не добавляете Pod файлы в git, нужно добавить шаг сборки «Выполнить команду shell», в которой запустить установку подов:

#!/bin/bash -l export LANG=UTF-8 pod install if [ $(($(date +"%s") - $(stat -f %m Podfile))) -le 60 ]; then pod install fi

4. Добавляем шаг сборки: Xcode. Если вы используете систему управления зависимостями CocoaPods, то вам не следует указывать значение в поле Target, а в разделе Advanced Xcode build options указать название исполняемой схемы и файла.xcworkspace. Пример минимальной конфигурации показан на скриншотах ниже:



Стоит отметить, что в настройках вашего проекта исполняемая схема должна быть отмечена как shared (контейнер может быть как workspace, так и project):

Работа с сертификатами и provisioning profile

Благодаря плагину Keychains and Provisioning Profiles Management можно значительно упростить работу с установкой provisioning profile.

Добавление provisioning profile:

  1. переходим в настройки Jenkins;
  2. в списке выбираем Keychains and Provisioning Profiles Management;
  3. нажимаем кнопку «Выберите файл», находим свой provisioning profile и нажимаем Upload.

Чтобы указать конкретный Provisioning Profile, если это необходимо, то в настройках job’a в разделе «Cреда сборки» нужно установить флаг Mobile Provisioning Profiles и выбрать один из загруженных профайлов:


Затем в настройках Xcode нужно установить custom xcodebuild arguments, как на скриншоте:


Для загрузки сертификата в связку ключей login.keychain можно воспользоваться GUI (просто кликнуть по сертификату), но такая возможность есть не всегда. Поэтому мы рассмотрим чуть более сложный вариант - добавление через ssh:

  1. скачиваем нужный сертификат на свой Mac и устанавливаем в локальный keychain access двойным кликом;
  2. заходим в keychain access, находим нужный сертификат и экспортируем ключ в формат.p12;
  3. передаём сертификат на сервер:

Scp certificate.crt jenkins@server:/Users/jenkins

certificate - название сертификата;

jenkins - имя пользователя;

server - адрес сервера;

:/Users/jenkins - путь сохраняемого файла;

(Можно использовать параметр для указания нужного порта в формате: scp -P 20 certificate.crt jenkins@server:/Users/jenkins)

4. передаём ключ на сервер:

Scp privatekey.p12 jenkins@server:/Users/jenkins

5. подключаемся к серверу по ssh:

Ssh jenkins@server

6. открываем доступ к связке ключей:

Security unlock-keychain -p password /Users/jenkins/Library/Keychains/login.keychain

7. устанавливаем сертификат:

Security add-certificates ./certificate.crt

8. копируем ключ:

Security import privatekey.p12 -k /Users/jenkins/Library/Keychains/login.keychain -P password -A

Перед запуском

Теперь мы готовы нажать на кнопку Built Now на главной странице веб-интерфейса Jenkins или на странице самого проекта. Жмём и переходим в раздел Console Output начавшейся сборки. Здесь в логах можно найти много полезной информации, включая ошибки.
Если вы всё сделали правильно, то по окончанию сборки в конце лога будет указано: Finished: SUCCESS , а на главной странице Jenkins рядом с названием сборки будет гореть синий индикатор УСПЕХА.

Установка всех необходимых программ и плагинов.

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

#Определение степени покрытие кода тестами brew install gcovr #Счётчик строк кода brew install cloc #Счётчик строк кода, альтернативный вариант brew install sloccount #Поиск дублирования кода brew install pmd #Генерация отчётов о результатах тестов (также генерирует данные для oclint) sudo gem install xcpretty #Статический анализ кода brew tap oclint/formulae brew install oclint

Интеграция с чатом Slack

Для получения уведомлений о состоянии сборки в командном чате Slack, нам необходимо добавить соответствующую интеграцию с Jenkins в настройках Slack’а. Это можно сделать .
После создания интеграции будет сгенерирован уникальный токен, который необходимо добавить в настройки Jenkins’а (либо в настройки отдельного job’а) - как в примере на скриншоте:


Далее настроим запуск сборок с помощью встроенного механизма команд в Slack’е. Для начала нам необходимо добавить интеграцию. Для этого пройём в подраздел Slash commands в разделе Custom Integrations и нажмём на кнопку Add configurations. Эту операцию можно выполнить .
При настройке вам нужно указать название вашей команды, выбрать метод передачи данных POST и указать URL -адрес, на который будет идти запрос.


Рассмотрим пример формирования URL для запроса подробнее. Наш URL для примера выглядит так:

Http://server:8080/buildByToken/buildWithParameters?job=JenkinsExecutor&token=XXXXXXXXXXXXXXXXX

Разберём его по составляющим:

  1. server - это внешний адрес вашего сервера. Если необходимо, то здесь также указываем нужный порт (в нашем случае 8080);
  2. buildByToken - возможность, предоставляемая плагином Build Authorization Token Root Plugin. Позволяет запускать job по ссылке с указанием токена (в нашем случае XXXXXXXXXXXXXXXXX );
  3. buildWithParameters - указывает на то, что нужно запустить параметризованную сборку;
  4. JenkinsExecutor - название job’а, который мы создадим и будем использовать для запуска других job’ов. О нём речь пойдет ниже;
  5. XXXXXXXXXXXXXXXXX - значение токена, который устанавливается в настройках плагина в конфигурации каждого отдельного job’а.

В качестве примера будем использовать следующую структуру команды:

/build Example test master

  1. /build - название нашей команды;
  2. Example - название job’a;
  3. test - вспомогательный флаг, связанный с запуском тестов и созданием отчётов с метриками;
  4. master - ветка для сборки.

Рассмотренная конфигурация позволит нам запускать сборку любого проекта с указанием нужной ветки, при этом будет использоваться единая команда: /build.

Конфигурация вспомогательного job’a - JenkinsExecutor

Данный job будет нужен нам для того, чтобы запускать другие job’ы. В нём также можно будет обрабатывать ошибки, если пользователь ввёл не существующий проект, и добавить информацию о команде (своеобразный help).
Заходим на сервер и создаём новую задачу со свободной конфигурацией и названием JenkinsExecutor. Далее в настройках job’а выставляем флаг, указывающий на то, что сборка является параметризированной и принимает параметр text. При запуске команды в Slack’е все данные (Example master test) будут передаваться единой строкой в переменной text.

Теперь нам необходимо извлечь значения из переменной text. Для этого переходим в раздел «Сборка» и добавляем шаг сборки «выполнить команду shell». Пример команды:

#Создаём массив из элементов строки, разделённых пробелом IFS=" " read -a array <<< "$text" #Согласно нашему примеру, первое значение - это название проекта JOB_NAME=${array} #Флаг, ответственный за тесты TEST=${array} #Название ветки проекта BRANCH=${array} #Если необходимо, можно также получить другие значения: USER_NAME=${user_name} CHANNEL_NAME=${channel_name}

Для запуска сборки с параметрами отправим POST -запрос на исполнение конкретного job’а. Для этого к предыдущей shell-команде добавляем следующую строчку:

Curl -d TEST=${TEST} -d BRANCH=${BRANCH} -X POST \ -u username:password http://127.0.0.1:8080/job/${JOB_NAME}/buildWithParameters

Обратите внимание, что все запускаемые сборки должны быть параметризированными!

Настройка сборки

1. Первое, на что стоит обратить внимание при настройки job’а - это то, что сборка должна быть параметризированной. Для этого выставляем соответствующий флаг, добавляем текстовые параметры BRANCH и TEST и задаём им параметры по умолчанию:

Здесь стоит отметить, что для переменной BRANCH нужно дополнительно добавить значение по умолчанию. Дело в том, что если вы запустите сборку из Slack без указания ветки, то в переменной BRANCH будет пустое значение и соответственно будет ошибка. Для этого мы добавим флаг Run buildstep before SCM runs в разделе «Среда сборки». Затем добавим шаг «выполнить команду shell» и шаг inject environment variables. Делаем по примеру:

4. Этап сборки начинается с выполнения shell-команды, которая устанавливает Pod’ы, если файл был обновлён:

If [ $(($(date +"%s") - $(stat -f %m Podfile))) -le 60 ]; then pod install fi

Затем для удобства установим некоторые переменные для проекта и запишем их в файл:

#Название.ipa-файла PROJECT_NAME="Example" #Название файла.xcworkspace WORKSPACE_NAME="Example" #Название исполняемой схемы SCHEME_NAME="Example" #Название папки с исходниками. Будет использоваться для подсчёта количества строк кода FOLDER_NAME_WITH_CODE="Example" #Записываем переменные в файл, чтобы использовать в других этапах сборки echo PROJECT_NAME=$PROJECT_NAME > build.properties echo WORKSPACE_NAME=$WORKSPACE_NAME >> build.properties echo SCHEME_NAME=$SCHEME_NAME >> build.properties

В зависимости от установленного параметра TEST запускаем или пропускаем этап тестирования и генерацию отчётов. Пример того, как это может выглядеть:

If [ "$TEST" == "test" ]; then #Создание папки reports, в которую мы будем складывать отчёты if [ ! -d "reports" ]; then mkdir "reports" fi #Тестирование и создание отчётов для анализа xcodebuild -workspace ${WORKSPACE_NAME}.xcworkspace \ -scheme ${SCHEME_NAME} \ -configuration Debug \ -sdk iphonesimulator \ -destination "platform=iOS Simulator,name=iPhone 6" \ -IDECustomDerivedDataLocation="build_ccov" \ GCC_GENERATE_TEST_COVERAGE_FILES=YES \ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES \ clean test | xcpretty -r junit -o reports/junit.xml -r json-compilation-database -o compile_commands.json #Publish JUNIT test = **/reports/junit.xml #Анализ синтаксической сложности кода oclint-json-compilation-database -v -e Pods -- \ -rc=LONG_LINE=200 \ -rc=NCSS_METHOD=60 \ -rc=LONG_METHOD=100 \ -rc=MINIMUM_CASES_IN_SWITCH=1 \ -report-type pmd \ -o reports/oclint.xml \ -max-priority-1 1000 \ -max-priority-2 1000 \ -max-priority-3 1000 #Publish PMD analysis = **/reports/oclint.xml #Анализ покрытия кода тестами gcovr --object-directory="build_ccov/${SCHEME_NAME}/Build/Intermediates/${SCHEME_NAME}.build/"\ "Debug-iphonesimulator/${SCHEME_NAME}.build/Objects-normal/x86_64/" \ --xml \ --print-summary \ --exclude ".*Tests.*" \ --exclude ".*Libs.*" \ --exclude ".*ExternalFrameworks.*" \ --exclude ".*Platforms.*" \ --output=reports/coverage.xml #Publish Cobertura Coverage = **/reports/coverage.xml #Подсчёт строк кода (два варианта): cloc ${WORKSPACE}/${FOLDER_NAME_WITH_CODE} -by-file -skip-uniqueness -xml -out=${WORKSPACE}/reports/cloc.xml #Publish SLOCCount analysis = **/reports/cloc.xml sloccount --duplicates --wide --details ${WORKSPACE}/${FOLDER_NAME_WITH_CODE} -v > reports/sloccount.sc #Publish SLOCCount analysis = **/reports/sloccount.sc #Анализ дублирования кода pmd cpd --files ${WORKSPACE}/${FOLDER_NAME_WITH_CODE} \ --minimum-tokens 10 --language objectivec \ --encoding UTF-8 \ --format net.sourceforge.pmd.cpd.XMLRenderer | iconv -f macRoman -t utf-8 | sed "s/MacRoman/UTF-8/g" > reports/duplicated-code.xml #Publish duplicate code = **/reports/duplicated-code.xml else touch reports/junit.xml #Данная строчка нужна, чтобы избежать провала при сборке из-за генерации отчета плагином Publish JUNIT test result report fi

  • Publish Cobertura Coverage analysis results = **/reports/coverage.xml
  • Publish SLOCCount analysis results = в зависимости от используемого модуля:
    1. **/reports/cloc.xml
    2. **/reports/sloccount.sc
  • Publish JUNIT test result report = **/reports/junit.xml (Примечание : В расширенных настройках плагина нужно установить флаг Do not fail the build on empty test results. Это поможет избежать fail-статуса для сборки, если она была запущена без запуска тестов)
  • На этом этапе мы можем отправить полученный в случае успеха.ipa-файл туда, куда нам нужно (на сервер, по e-mail и т.д.). Если вы хотите отправить файлы на сервер по SFTP и вы используете плагин Publish Over SSH , то нужно перейти в раздел «Среда сборки», установить флаг для Send files or execute commands over SSH after the build runs и настроить плагин в соответствии с вашими требованиями.

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

    На этом внедрение CI можно считать оконченным. Мы надеемся, что наша статья будет для вас полезной.