Автоматизація процесу розробки: працюємо з Buildbot’ом

Як я й обіцяв в минулій статті, сьогодні ми дослідимо реальний приклад використання системи неперервної інтеграції під назвою BuildBot. Ні сам процес розробки, ні структура проекту не вважаються ідеальними, однак саме завдяки їм у мене зараз є можливість написати як можливо вижити в, здавалося б, такому хаотичному проекті.

Постановка задачі

Проект на Java(використовується система збирання Ant) в репозитарії Subversion знаходиться за адресою https://project.example.com/svn . Необхідно проводити аудит працездатності системи щоразу після внесення змін до нього. Результати збирання системи надсилаються автору змін у випадку успішного результату, або ж у список розсилки всього проекту, якщо процес пройшов невдало.

Вибір між CruiseControl, про який мені розповіли співробітники, та BuildBot, з яким я встиг познайомитись в якості розробника, був досить складний. Проект був вже тоді немаленький(на даний момент весь репозитарій складає 6Гб місця), після тестування його переносила на продуктивні сервери окрема людина. Enterprise, одним словом. І я, довірившись особистому знайомству, вибрав BuildBot. І не прогадав.

Встановлення

Оскільки BuildBot має клієнт-серверну архітектуру, його можна запустити в двох режимах:

  • Master: визначає, що, коли, і як робити, реалізує всі системи сповіщення
  • Slave: старанно виконує всі вказівки Master-а

Для спрощення комунікації, сервер був встановлений на машині, яка тримала репозитарій. Нехай шлях до репозитарію на сервері — /var/repos/project. DNS-ім’я сервера — example.com. Встановлення BuildBot’а в Debian проходить без жодних проблем:

# aptitude install buildbot 

Після чого BuildBot буде встановлений з усіма необхідними залежностями. Тепер слід створити сервер, який нестиме основне інформаційне навантаження та клієнт, який буде виконувати процес збирання. Для чистоти експерименту, обидва будуть працювати під власними користувачами:

# addgroup buildbot
# adduser --group buildbot buildmaster
# adduser --group buildbot buildslave

Тепер власне створення сервера:

# su - buildmaster
$ mkdir project
$ buildbot create-master project

Налаштування сервера

Після цього в директорії myproject створиться базовий набір файлів, а також деякі допоміжні сценарії для запуску сервера. Сам же конфігураційний файл зветься master.cfg. Хоча можна поправити та перейменувати вже створений master.cfg.sample, я залишу його для тренувань, натомість створимо власну конфігурацію:

1
2
3
4
5
6
7
8
9
# -*- python -*-
# ex: set syntax=python:
 
c = BuildmasterConfig = {}
 
# PROJECT IDENTITY
c['projectName'] = "Test project"
c['projectURL'] = "http://project.example.com/"
c['buildbotURL'] = "http://buildbot.example.com/"

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

10
11
12
13
14
15
16
# BUILDSLAVES
 
from buildbot.buildslave import BuildSlave
 
c['slaves'] = []
c['slaves'].append(BuildSlave("local-bot", "local-password",max_builds=1))
c['slavePortnum'] = 9989

Коли загальні відомості щодо проекту ми вказали, розберемося з тим, як бот дізнається про те, що в репозитарії було щось змінено. Сервер очікує встановлення зв’язку на вказаний нами порт. До цього порту можуть підключатись як клієнти, що виконують власне збирання системи(в даному варіанті маємо одного бота, який працює локально), так і спеціальні програми, що вказують на зміни в проекті. Для реалізації даної моделі додамо наступні рядки в налаштування:

17
18
19
20
21
22
# CHANGESOURCES
 
from buildbot.changes.pb import PBChangeSource
 
c['change_source'] = []
c['change_source'].append( PBChangeSource() )

Не завжди існує можливість отримати повідомлення про оновлення репозитарію. В таких випадках замість того, щоб очікувати підключення за вказаним портом можна власноруч періодично опитувати SVN репозитарій на наявність оновлень. Це можна зробити за допомогою об’єкту SVNPoller. Якщо ж ви отримуєте інформацію про оновлення репозитарію поштою, то Bildbot можна натравити на поштову скриньку (можливе використання як формату mbox, так і mdir), і таким чином сповіщувати систему.

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

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
localsvnroot  = 'file:///var/repos/project/'
 
# BUILDERS
 
from buildbot.process import factory
from buildbot.steps.source import SVN
from buildbot.steps.shell import Compile
 
localFastSourceUpdate = SVN(svnurl=localsvnroot,mode="update")
 
antCleanup = Compile(command=["ant","cleanup"], name="Cleanup")
antCompile = Compile(command=["ant"])
 
quickBuildFactory = factory.BuildFactory([localFastSourceUpdate, antCleanup, antCompile])
 
quickBuild = {
	'name': "quick",
	'slavename': "local-bot",
	'builddir': "quick",
	'factory': quickBuildFactory }
 
c['builders'] = [quickBuild]

Вище вказаний код вимагає деяких пояснень. Очевидно, процес збирання програми руками, виглядає як

$ svn up
$ ant cleanup
$ ant

Рядки 40-50 визначають кроки, які необхідно виконати для збирання програми. Далі ці кроки збираються в єдиний об’єкт, який надалі буде управляти процесом збирання. В останніх рядках виконується прив’язка до конкретного імені та списку клієнтів, на яких необхідно проводити збирання. Останнім рядком додаємо наш об’єкт до налаштувань.

Наступним кроком буде прив’язка процесу збирання проекту до події оновлення репозитарію. Для цього використовується об’єкт Sheduler. Його різновидів достатньо для більшості задач: збирати за повідомленням ззовні, періодичне виконання, виконання за розкладом тощо.

45
46
47
48
49
50
51
52
# SCHEDULERS
 
from buildbot.scheduler import Scheduler
 
c['schedulers'] = []
c['schedulers'].append(Scheduler(name="dirty and quick",
	treeStableTimer=10*60,
	builderNames=["quick"]))

Параметр treeStableTimer визначає час в секундах(в даному випадку 10 хвилин), протягом якого в репозитарій не повинні бути внесені зміни для початку процесу збирання. У разі швидко виявленої помилки та своєчасних внесень змін до репозитарію, процес збирання буде виконаний лиш один раз. Це дозволить розробнику не привертати до себе зайвої уваги проблемами з процесом збирання проекту.

Наостанок, визначимо служби сповіщення. Для поставленої задачі достатньо налаштувати пошту, однак web-інтерфейс ніколи зайвим не був.

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# STATUS TARGETS
 
from buildbot.status import html
from buildbot.status import html, mail
 
c['status'] = []
c['status'].append(html.WebStatus(http_port=80))
 
# Send notification on build to committer
c['status'].append(mail.MailNotifier(fromaddr="buildbot@example.com",
	relayhost="localhost",
	lookup="example.com",
	mode="all",
	addLogs=True,
	builders=["quick"],
	sendToInterestedUsers=True))
 
# Send notification to the mailing list if fails
c['status'].append(mail.MailNotifier(fromaddr="buildbot@example.com",
	relayhost="localhost",
	mode="failing",
	builders=["quick"],
	extraRecipients=["robots@example.com"],
	sendToInterestedUsers=False))

Ну ось, налаштування для сервера готові. Кілька ремарок щодо web-інтерфейсу. Хоча ми і вказували URL бота і головну сторінку проекту в перших рядках налаштувань, сервер очікує, що 80й порт не зайнятий на жодному інтерфейсі, інакше процес запуску не відбудеться. В наступній статті я розповім, як здружити бота і Web-сервер на прикладі Apache2. Ну і не забудьте налаштувати MTA, щоб бот міг висилати пошту, або ж вкажіть інший SMTP сервер.

Налаштування клієнта

Встановлення клієнта для бота не вимагає надмірних зусиль. Для цього в більшості випадків достатньо виконати наступні команди:

# su - buildslave
$ mkdir project
$ buildbot create-slave project localhost:9989 local-bot local-password

Налаштування репозитарію

Оскільки ми очікуємо, що репозитарій має нас сповістити про оновлення, необхідно вказати наступні рядки у файлі
/var/repos/project/hooks/post-commit:

1
2
3
REPOS="$1"
REV="$2"
/usr/share/buildbot/contrib/svn_buildbot.py --repository "$REPOS" --revision "$REV" --bbserver localhost --bbport 9989

Відлагодження та автозапуск

Останнім штрихом буде запуск сервера і клієнта в інтерактивному режимі. Для цього правимо файл /etc/default/buildbot :

1
2
3
4
5
6
7
8
9
10
11
12
# buildbots to manage
# add a new set of variables for each buildbot to start
 
BB_NUMBER[0]=0
BB_NAME[0]="master"
BB_USER[0]="buildmaster"
BB_BASEDIR[0]="/home/buildmaster/project"
 
BB_NUMBER[1]=1
BB_NAME[1]="slave"
BB_USER[1]="buildslave"
BB_BASEDIR[1]="/home/buildslave/project"

Тепер все це щастя можна сміливо запускати:

# /etc/init.d/buildbot start

Для відлагодження бота в процесі роботи необхідно додати в налаштування сервера наступні рядки:

78
79
80
# DEBUG CREDENTIALS
 
c['debugPassword']="debugPassword"

А для початку відлагодження слід виконати

$ buildbot debugclient buildbot.example.com:9989 debugPassword

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

Заключне слово

Ну ось, система працює, однак вона ще далека від ідеалу: часто необхідно збирати один і той же продукт на різних платформах, централізовано викладувати т.з. нічні (Nightly) збірки, до того ж, поточна конфігурація не враховує можливих змін в структурі репозитарію, надлишковості збирань. Але це тема наступної статті.