Перехід з CruiseControl.NET на Jenkins в команді розробників PVS-Studio

<img src=«habrastorage.org/getpro/habr/post_images/1bb/7a8/97e/1bb7a897e17c6d5626f949ad85534c73.png» alt=«Picture » 1" />
Зараз важко уявити розробку програмного забезпечення автоматизованих збірок проекту і тестування. Для мінімізації часових витрат на інтеграцію змін розробників в проект, існують різні готові рішення. У даній статті я розповім про заміну сервера безперервної інтеграції CruiseControl.NET на Jenkins в команді розробників PVS-Studio. А також про те, що нас до цього спонукало, які цілі ми переслідували і з якими проблемами зіткнулися.

Введення
Безперервна інтеграція (англ. Continuous Integration, далі CI) — автоматизований процес збирання, розгортання та тестування розроблюваного програмного забезпечення. Ця практика розробки популярна як у великих колективах, так і у індивідуальних розробників. Для подібної практики є багато готових рішень. В даній статті піде мова про безкоштовних проектах з відкритим вихідним кодом CruiseControl.NET і Jenkins.

CruiseControl.NET ( CCNet ) — інструмент для безперервної інтеграції програмного забезпечення, реалізований на .NET Framework. Також існують варіанти інструменту на Java (CruiseControl) і версія для Ruby-середовищ (CruiseControl.rb). Управління та перегляд інформації про збірках здійснюється через веб-інтерфейс або desktop утиліту. Інтегрується з різними системами керування версіями. Є проектом з відкритим вихідним кодом і, на жаль, не розвивається приблизно з 2013 року.

Jenkins — інструмент для безперервної інтеграції з відкритим вихідним кодом, написаний на Java. Був ответвлен від проекту Hudson після суперечки з Oracle. Забезпечуючи функції безперервної інтеграції, дозволяє автоматизувати частину процесу розробки програмного забезпечення, в якому не обов'язково участь людини. Можливості Jenkins можна розширювати за допомогою плагінів. В даний момент проект активно розвивається і підтримується розробниками, і співтовариством.

Хоч стаття і трохи схожа на огляд в стилі «CCNet Vs. Jenkins», акцент буде зроблений на виборі на користь сервера з Jenkins. Головною причиною зміни інструменту безперервної інтеграції для нас є відсутність у розвитку проекту CruiseControl.NET. У статті будуть описані і інші моменти роботи з CCNet, з якими виникали труднощі.

Нещодавно у проекту PVS-Studio був ювілей 10 років, про який можна прочитати у статті "Як 10 років тому починався проект PVS-Studio". Більше половини часу існування продукту ми використовували CCNet. Його інтерфейс, налаштування і функції стали настільки звичними, що Jenkins здавався вкрай незручним. Вперше ми стали його використовувати, коли з'явився PVS-Studio для Linux. Переходу на Jenkins передувало тривале вивчення цього інструменту. Частину часу ми витратили на пошук аналога звичних нам функцій з CCNet. Далі будуть описані цікаві моменти з виконаної роботи.

Наші претензії до CCNet
  1. CCNet більше не розвивається. Їм можна досі користуватися, але розширювати функціонал і виправляти існуючі потенційні помилки доведеться власними силами.
  2. Нестабільно працює режим опитування SCM (Source Code Management) про зміни, а саме для автоматичного запуску при наявності змін в системі контролю версій. При проблемах з мережею, в цьому режимі проект отримує статус «Failed», навіть якщо не запускався. На практиці проблема виникає так часто (на жаль, у нашому офісі не самий стабільний доступ в інтернет), що цим режимом неможливо користуватися.
  3. При опитуванні SCM про зміни, у разі наявності помилки системи контролю версій (наприклад, якщо з репозиторію був видалений який-небудь каталог прописаний в налаштуваннях і виник tree conflict), виконання проекту відразу переривається, зберігаючи статус «Success» — проект перестає працювати, але його статус в web інтерфейсі і десктоп утиліті залишається «зеленим». В такому режимі запустити, наприклад, тестів, може не виконуватися тижнями, і є ризик, що ніхто не зверне на це уваги, думаючи, що тести успішно працюють.
  4. Загальний лог роботи сервера занадто вербозный і неструктурований: складно зрозуміти, який крок складання відвалився і знайти лог саме для цього кроку. При роботі декількох проектів паралельно, лог збірки «змішується». XML лог складання окремого проекту доступний в web інтерфейсі, але він навпаки, часто недостатньо докладний і не містить всіх запускаються команд.
  5. Неефективне розпаралелювання підзадач всередині проекту. Підзавдання запускаються паралельно групами за кількістю ядер процесора. Якщо в групу потрапляють тривалі і швидкі завдання, то нові завдання запускатися не будуть, поки не завершаться всі завдання з попереднього запуску.
Порівняння сценаріїв використання
Налаштування сервера
Налаштування проектів CCNet (конфігурація сервера) зберігалися в одному xml файлі, а різні паролі в іншому. Хоч файл налаштувань і досяг розміру ~4500 рядків, користуватися їм було досить зручно. Легким натисненням Alt+2 в Notepad++ список всіх проектів можна згорнути і редагувати потрібний (малюнок 1).

Рисунок 1 - Редагування CCNet налаштувань в Notepad++
Малюнок 1 — Редагування CCNet налаштувань в Notepad++

Хоч файл і містив повторюваної код, за підтримки сервера особливих труднощів не виникало.

Ось так заповнювався блок SCM:

<svn>
<username>&SVN_USERNAME;</username>
<password>&SVN_PASSWORD;</password>
<trunkUrl>&SVN_ROOT;...</trunkUrl>
<workingDirectory>&PROJECT_ROOT;...</workingDirectory>
<executable>&SVN_FOLDER;</executable>
<deleteObstructions>true</deleteObstructions>
<cleanUp>true</cleanUp>
<revert>true</revert>
<timeout units="minutes">30</timeout>
</svn>

Так заповнювався блок MSBuild:

<msbuild>
<description>PVS-Studio 2015</description>
<workingDirectory>&PROJECT_ROOT;...</workingDirectory>
<projectFile>...\PVS-Studio-vs2015.sln</projectFile>
<buildArgs>/p:Configuration=Release</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<executable>&MSBUILD14_PATH;</executable>
</msbuild>

А так заповнювався блок для загальних завдань:

<exec>
<description>PVS-Studio 2015 sign</description> 
<executable>&PROJECT_ROOT;...\SignToolWrapper.exe</executable>
<baseDirectory>&PROJECT_ROOT;...</baseDirectory>
<buildArgs>"&SIGNTOOL;" ... \PVS-Studio-vs2015.dll"</buildArgs>
<buildTimeoutSeconds>600</buildTimeoutSeconds>
</exec>

На основі такого проектного файлу CCNet потім зручно відображає всі виконувані кроки (правда, тільки в десктопної tray утиліті. Web інтерфейс це чомусь не підтримував). У Jenkins з «високорівневим» відображенням етапів проходження інтеграційного проекту довелося повозитися, але про це буде розказано пізніше.

Для Jenkins необхідно зберігати досить багато файлів налаштувань: конфіг сервера, файли налаштувань деяких плагінів, кожен проект має свій власний файл конфігурації. Хоч всі ці задані файли у форматі xml, для перегляду і редагування вони не дуже зручні (принаймні порівняно з CCNet), оскільки всі команди всередині тегів прописані суцільним текстом. Щоправда, більшою мірою це пов'язано з ідеологією використання інструменту. У CCNet конфіг пишеться вручну, і тому, може бути красиво відформатований. Jenkins ж передбачає редагування налаштувань проекту через веб інтерфейс, а конфіги генерує автоматично.

Приблизно так виглядають команди в конфігах Jenkins'а:

<hudson.tasks.BatchFile>
<command>CD &quot;%BUILD_FOLDERS%\Builder&quot;&#xd;
PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES ...&#xd;
Publisher_setup.exe /VERYSILENT /SUPPRESSMSGBOXES</command>
</hudson.tasks.BatchFile>

І це ще дуже маленький приклад.

Перегляд статусів завдань
Як я писав раніше, в CCNet проекти заповнюються Task блоками. Ось так виглядає успішно виконане завдання з відображенням кроків (малюнок 2).

Рисунок 2 - Перегляд статусу завдання в CCTray (desktop клієнт для CCNet)
Малюнок 2 — Перегляд статусу завдання в CCTray (desktop клієнт для CCNet)

Помилку у кожному з блоків добре видно в ієрархії підзадач. Це дуже зручна і наочна візуалізація інтеграційного процесу. Майже ніколи не було необхідності шукати логи, за описом завдання було відразу зрозуміло, що варто перевірити на локальному комп'ютері. Прямо в такому вигляді в Jenkins нічого не знайшлося, тому довелося докладно вивчити цей момент перед переїздом на новий сервер.

Можна провести таку аналогію між CCNet і Jenkins: CCNet є проект (Project), кроком у цьому проекті є Task (як видно на малюнку вище). У Jenkins також є проект (Job), а його кроками є Step'и (малюнок 3).

Рисунок 3 - Відповідність найменувань проектів в CCNet і Jenkins
Малюнок 3 — Відповідність найменувань проектів в CCNet і Jenkins

На жаль, web інтерфейс Jenkins'а не вміє візуалізувати роботу окремих кроків — у Job'а є тільки повний консольний лог всіх кроків разом. Великою незручністю тут є те, що з Jenkins неможливо подивитися, який з кроків завершився з помилкою — потрібно дивитися повний лог складання Job'а. І так як до хорошого швидко звикаєш, від старого сценарію використання відмовлятися не хотілося. Тоді на допомогу прийшов Multijob Plugin.

Цей плагін дозволив нам внести наступні нововведення:

1. Використання Job'ів в якості Step'ів в інших Job'ах. Таким чином з'явилися універсальні Job'и, які дозволили відокремити лог конкретних завдань і, найголовніше, окремо переглядати статуси конкретних завдань. Web інтерфейс Jenkins вміє добре візуалізувати виконання окремих Job'ів в рамках Multijob'а — як раз те, що ми шукали. На малюнку 4 показаний приклад виконаного Multijob'а.

Рисунок 4 - Перегляд виконаного Multijob&#39;а
Малюнок 4 — Перегляд виконаного Multijob'а

2. З використанням універсальних Job'ів вдалося позбутися від дублюючого коду. Наприклад, є компіляція який-небудь утиліти: для дистрибутива, для запуску тестів і для запуску аналізу коду. У CCNet це були однакові Task блоки в 3-х різних проектах. У Jenkins для компіляції цієї утиліти зроблений Job, який використовують кілька Multijob'ів.

3. При створенні проектів в Jenkins використовується наступна ідеологія. Всі Job'и ми поділяємо на Multijob «проекти» і універсальні «кроки». Імена універсальних Job'ів мають префікс «job_» і не передбачають використання як самостійного проекту. Також вони не містять завантаження вихідного коду з репозиторію. Імена Multijob'ів мають префікс «proj_» і включають в себе завантаження вихідного коду, і запуск тільки інших Job'ів. (Step'и ми намагаємося уникати, оскільки вони не візуалізуються).

Універсальні Job'и запускаються з наступним параметром:

WORKSPACE=$WORKSPACE

Це означає, що Job буде запущено в робочому каталозі Multijob'а.

Таким чином вдається отримати окремо лог оновлення вихідних файлів і логи всіх етапів складання окремо. Слідувати цій ідеології для всіх проектів складно і безглуздо. Так зроблено тільки для декількох найбільш великих і важливих проектів, які необхідно докладно вивчати при виникненні проблем.

4. У Multijob'е можна налаштувати умовні і паралельні запуски Job'ів. Multijob'и вміють запускати Multijob'и по тим же правилам. Так можна об'єднувати запуски проектів: наприклад, запустити збірку всіх інсталяторів або всі тести.

Перегляд логів складання
У CCNet переглядати логи складання проектів було вкрай незручно, т. к. вони перемішувалися з висновком сервера, і мали особливу розмітку. У Jenkins такої проблеми немає, і додатково з'явилася можливість розділяти логи підзавдань у деяких проектах.

Отримання ревізії вихідного коду
У Jenkins для кожної доданої посилання на SVN репозиторій визначається своя версія ревізії. Тобто якщо додати декілька каталогів, номери можуть сильно відрізнятися, а потрібен один максимальний.

Згідно документації, працювати з цим треба наступним чином:

If you have multiple modules checked out, use the svnversion command. If you have multiple modules checked out, you can use the svnversion command to get the revision information, or you can use the SVN_REVISION_<n> environment variables, where <n> is a 1-based index matching the locations configured.

Так і зробили: з усіх виставлених значень SVN_REVISION_<n> береться максимальне додається до зібрані програми.

Корисні плагіни для Jenkins
Розширення можливостей за допомогою плагінів дозволяє максимально гнучко налаштувати сервер. Плагіни для запуску тестів в Visual Studio, мабуть, єдині, що ми відмовилися використовувати. Вони мали додаткові обов'язкові параметри запуску, які ми не використали, тому простіше було зробити універсальний Job, просто запускає тести з командного рядка. На жаль, «з коробки» Jenkins не вмів багато чого з того, до чого ми звикли в CCNet. Однак, з допомогою плагінів вдалося «повернути» всю необхідну нам функціональність.

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

  1. Multijob plugin — дозволяє використовувати в якості етапів складання інші Job'и з можливістю послідовного і паралельного виконання.
  2. Environment Injector Plugin — за допомогою цього плагіна можна ставити глобальні паролі. Використовуються вони як змінні оточення, при цьому плагін приховує значення такої змінної в балці.
  3. Pre SCM BuildStep Plugin — додавання додаткових кроків перед виконанням команд системи контролю версій.
  4. MSBuild Plugin — зручний плагін для складання проектів за допомогою MSBuild. У налаштуваннях один раз вказуються шляхи до різними версіями MSBuild. Далі в проекті можна легко додавати кроки складання.
  5. Parameterized Trigger plugin — додає параметри запуску проектів. Можна, наприклад, зробити вибір trunk/stable гілки для складання дистрибутива.
  6. Post-Build Script Plug-in — виконання додаткових етапів після складання.
  7. Throttle Concurrent Builds Plug-in — даний плагін дозволяє регулювати кількість паралельно запущених збірок проекту глобально або в рамках заданої категорії. Він дозволяє отримати в Jenkins функціональність, подібну черг в CCNet — можливість виконувати паралельно кілька проектів з різних категорій (черг), при цьому забезпечуючи послідовне виконання проектів у рамках однієї черги. Наприклад, у нас є черги Installers (дистрибутиви) і Tests (тести). Ми хочемо мати можливість при роботі тестів паралельно збирати якийсь дистрибутив, але при цьому тести паралельно працювати не повинні — не вистачить «ядер» на сервері.
  8. Build Name Setter Plugin — дозволив задати ім'я збірки в потрібному нам форматі: Major.Minor.Revision.Build.
  9. Dashboard View — дозволяє додати своє відображення Job'ів у браузері. Оскільки у нас є універсальні Job'и, які немає сенсу запускати вручну, то ми створили список без них з допомогою цього плагіна.
  10. ZenTimestamp Plugin — зручний плагін, який додає тимчасові мітки в логах складання.
Огляд десктопних клієнтів
Для отримання повідомлень від CCNet ми користувалися клієнтом для Windows — CCTray.

Ось які варіанти тепер є для роботи з Jenkins:

1. CCTray — цю програму можна використовувати і для сервера Jenkins. Виглядати проекти будуть приблизно, як і раніше (малюнок 5).

Рисунок 5 - Скріншот CCTray
Малюнок 5 — Скріншот CCTray

Опис як клієнта для Jenkins:

  • Не розвивається, як і CCNet;
  • Не вміє показувати підзадачі (працює тільки для CCNet);
  • Не вміє запускати проекти;
  • натисненні на назву можна перейти на сторінку проекту;
  • Налаштовується вид відображення проектів (Icons, List, Details);
  • З відкритим вихідним кодом.
2. CatLight (малюнок 6)

Рисунок 6 - Скріншот CatLight
Малюнок 6 — Скріншот CatLight

Опис клієнта:

  • На даний момент Бета-версія, фінальна версія стане платною;
  • Ще є падіння при встановленні, роботі і глюки в інтерфейсі;
  • При виведенні комп'ютера з режиму глибокого сну статус проектів на dashboard'е не оновлюється автоматично;
  • Не вміє показувати підзадачі для Multijob'ів;
  • Не вміє запускати проекти;
  • Не налаштовується вид відображення проектів (єдиний можливий вид — малюнок 6);
  • натисненні на назву можна перейти на сторінку проекту;
  • Можна бачити статус останніх 5-і запусків і переходити до них;
  • Можна бачити прогрес запущеного проекту;
  • При додаванні декількох серверів вони зручно відокремлені рискою;
  • для Windows, Linux і Mac.
3. Kato (малюнок 7)

Рисунок 7 - Скріншот Kato
Малюнок 7 — Скріншот Kato

Опис клієнта:

  • Не вміє показувати підзадачі для Multijob'ів;
  • Уміє запускати проекти. На жаль, не підтримує проекти з параметризованим запуском — утиліта «падає» при спробі запустити такий проект;
  • Проекти з різних серверів відображаються в одному списку і невиразні (не завжди зручно);
  • Налаштовується вид відображення проектів (List, Grid);
  • натисненні на назву можна перейти на сторінку проекту;
  • Можна переглядати останній лог прямо в клієнті, але з-за відсутності ширини тексту це не дуже зручно;
  • З відкритим вихідним кодом;
  • Тільки для Windows.
4. CCMenu — тільки клієнт для Mac з відкритим вихідним кодом. Для нас не актуальне, але може комусь стане в нагоді.

Висновок
Використання CI корисно в будь-якому проекті. Для цього є чудовий безкоштовний інструмент Jenkins, який був розглянутий у статті, а також багато інших безкоштовних і платних CI. Приємно користуватися розвиваються проектом: для Jenkins і плагінів періодично виходить безліч оновлень. З'являються нові рішення, як, наприклад, зараз на головній сторінці наводиться новий проект Blue Ocean, який ще знаходиться на стадії Beta.

Клієнти для моніторингу проектів Jenkins не дуже мене порадували. Відсутній багато напрошуються функцій. Можливо, десктопні клієнти не особливо затребувані і правильніше користуватися тільки web-інтерфейсом.

При переїзді на новий сервер не вийшло використовувати Jenkins як службу Windows, оскільки в цьому режимі не виконуються UI тести. Вийшли з положення, налаштувавши запуск сервера як консольного додатка з прихованим вікном.

Якщо у вас є доповнення до викладеного матеріалу або цікаві вирішення наведених проблем, то ми будемо раді, якщо ви залишите коментар до статті або напишіть нам через форму зворотного зв'язку.


Якщо хочете поділитися цією статтею з англомовної аудиторією, то прошу використовувати посилання на переклад: Svyatoslav Razmyslov. Moving from CruiseControl.NET to in the Jenkins PVS-Studio development team

Прочитали статтю і є питання?Часто до наших статей задають одні і ті ж питання. Відповіді на них ми зібрали тут: Відповіді на питання читачів статей про PVS-Studio, версія 2015. Будь ласка, ознайомтеся зі списком.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.