… или использование TeamCity для сборки *.deb
-пакетов и не только.
Написать статью меня побудило знакомство с модулем tcDebRepository. Я наивно полагал, что "вот сейчас я его подключу, и всё волшебным образом заработает". Как водится, не заработало, и в конце концов был накоплен некий опыт, который захотелось систематизировать.
Статья ни в коей мере не является введением в основы TeamCity и предполагает, что читатель уже знаком и собственно с TeamCity, и с инфраструктурой Debian GNU/Linux. Если вы уже представляете, что такое continuous integration, но ещё ни разу не держали в руках TeamCity — вам, наверное, сюда. О сборке пакетов в Debian можно почитать в Debian New Maintainers' Guide.
Для игр (на случай, если кто-то захочет воспроизвести результаты) использовался сервер TeamCity 10 и 3 агента п/упр Debian 8.0 (Jessie). 3 агента — это лимит в случае TeamCity Professional. Всё ниженаписанное, думаю, без проблем переносится на любой другой дистрибутив на основе Debian GNU/Linux, напр., Astra Linux.
Планы
Достаточно произвольным образом я выбрал для экспериментов 4 пакета:
С учётом ограничения лицензии типа Professional на количество конфигураций сборки можно было "набрать" до 20 пакетов.
Подготовка
TeamCity загружается с официального сайта. Кроме собственно TeamCity, на каждую из агентских машин нам потребуется установить пакет build-essential, равно как и необходимые для сборки зависимости для всех четырёх пакетов (из категорий build-depends
и build-depends-indep
). Это позволит минимизировать (но совсем не обязательно устранить) проблемы с зависимостями при сборке.
Виды пакетов в Debian GNU/Linux
Пакеты, помимо прочих особенностей, делятся на "родные" (native) и внешние (non-native) (подробнее). "Родные" пакеты (autotools-dev
, debhelper
, dpkg
) обычно разрабатываются в рамках проекта Debian, и исходный код уже содержит необходимую для сборки метаинформацию (каталог debian/
в корне дерева исходного кода).
Отличие внешних пакетов (bash
) в том, что исходный код никоим образом не завязан на Debian, и инженерам сопровождения (в русскоязычной документации это называется "разработчик Debian", в англоязычной — просто "maintainer") приходится поддерживать параллельное дерево исходного кода с метаинформацией и патчами (это то самое содержимое каталога debian/
).
Общие настройки
Бинарные пакеты, которые мы будем собирать — это, в терминологии TeamCity, "артефакты". Соответственно, нужно указать, что мы ожидаем иметь в сухом остатке по окончании очередной сборки, указав artifact paths:
Для "родных" пакетов артефакты pkgname.orig.tar.{gz,bz2,xz}
и pkgname.debian.tar.{gz,bz2,xz}
не создаются.
Подключение исходного кода к TeamCity
Чаще всего как раз с этим шагом нет ничего сложного: просто идём в настройки конфигурации сборки (build configuration) и добавляем новый корень системы контроля версий (VCS root). Для "родных" пакетов эту операцию нужно выполнить однократно, для внешних — как правило, дважды (но возможны исключения, когда и разработчики (вне проекта Debian), и инженеры сопровождения используют одну и ту же DVCS (Git, Bazaar), и изменения в коде постоянно "кочуют" из одного репозитория в другой, в то же время не вызывая merge-конфликтов для метаинформации и патчей).
Единственная особенность состоит в том, что артефакты в нашем случае будут собираться вне дерева исходного кода (на один каталог выше), так что нам нужно настроить checkout rules таки образом, чтобы, скажем, исходный код пакета dpkg
выгружался не в текущий рабочий каталог, а в одноимённый пакету подкаталог, т. е. dpkg/
. Это достигается добавлением одной строчки:
+:.=>dpkg
и в конечном счёте выглядит так:
Теперь можно добавить VCS-триггер и к настройке контроля версий уже не возвращаться:
Интеграция с Bazaar
"Но ведь для сборки bash
требуется интеграция с Bazaar, а штатная поставка TeamCity не поддерживает эту систему!" — скажет внимательный читатель, и будет прав. Кроме того, TeamCity, увы, не позволит нам добавить и Git URL вида bzr::http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian
— у JGit слишком много ограничений.
Существует внешний модуль для поддержки Bazaar, но у него есть по меньшей мере два серьёзных недостатка:
- checkout на стороне агента не поддерживается, и
- штатной поставки Bazaar недостаточно, т. к. модуль опирается на функциональность bzr xmlls и bzr xmllog, что выясняется только в процессе сборки:
Поскольку сервер TeamCity у меня работал на Windows, я отказался от весёлого приключения в виде установки Bazaar на стороне сервера, а вместо этого в случае пакета bash
просто добавил ещё один шаг сборки (Bazaar-интеграцию для бедных), используя Command Line Runner и следующий сценарий оболочки:
#!/bin/bash
#
# vim:ft=sh:
#
export LANG=C
export LC_ALL=C
set -e
rm -rf bash/debian
bzr branch http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian bash/debian
major_minor=$(head -n1 bash/debian/changelog | awk '{print $2}' | tr -d '[()]' | cut -d- -f1)
echo "Package version from debian/changelog: ${major_minor}"
tar_archive=bash_${major_minor}.orig.tar
rm -f ${tar_archive} ${tar_archive}.bz2
# +:.=>bash checkout rule should be set for the main VCS root in TeamCity
tar cf ${tar_archive} bash
tar --delete -f ${tar_archive} bash/debian
# Required by dpkg-buildpackage
bzip2 -9 ${tar_archive}
Такой подход не позволит нам "видеть" изменения в одном дереве исходного кода (из двух) и автоматически запускать сборку при их (изменений) появлении, но для первого опыта вполне достаточен.
N.B.! Поскольку Command Line Runner не умеет подсвечивать синтаксис кода сценария, для пользователей браузеров Mozilla Firefox и SeaMonkey я бы рекомендовал расширение It's All Text!, позволяющее редактировать содержимое текстовых полей во внешнем редакторе. Можно подключить Vim или Emacs и насладиться подсветкой синтаксиса, автодополнением, шахматами и поэтессами.
Сборка: настройка
Для сборки нам достаточно использовать уже знакомый нам Command Line Runner, вызывающий dpkg-buildpackage
. Ключи -uc
и -us
означают, что мы не хотим создавать цифровых подписей для наших пакетов. Если всё-таки хотим — придётся загрузить соответствующую пару GnuPG-ключей на каждый из агентов.
Также обратите внимание, что dpkg-buildpackage
должен исполняться не в текущем рабочем каталоге, а в одноимённом пакету подкаталоге (куда будет выгружено дерево исходного кода). Если настройка контроля версий выполнена, поле "Working directory" можно заполнить в один щелчок мыши, не вводя имя каталога вручную:
Сборка: разрешение проблем
Качество кода
Как ни странно, но качество кода (или, точнее, стиль разработки) может являться серьёзной проблемой на пути внедрения continuous integration. Опытным путём выяснилось, что, в случае bash
, версии в двух деревьях кода рассинхронизированы: последние коммиты в основном дереве соответствуют версии 4.4, хотя файл debian/changelog
уже без малого два года назад остановился на версии 4.3, и код одной версии с метаинформацией другой версии вместе не собираются. Хорошо, значит, мне нужна ветка bash-4.3
в основном дереве.
- Вот идёт ветка
bash-4.3-testing
с тэгамиbash-4.3-rc2
и (ниже, не видно)bash-4.3-rc1
— и потом она внезапно обрывается. Если верить истории версий, то релизbash
4.3 так и не состоялся. - В то же время, спустя несколько дней на ветке
master
появляется коммит с тэгомbash-4.3
, которому не предшествует ни одна операция типа merge или cherry-pick. - Беглый взгляд на историю и содержание коммитов приводит к ощущению, что вся разработка ведётся в локальной ветке одного человека, а
git push
на savannah.gnu.org происходит через равные промежутки времени, причём черезgit merge --squash -s ours
(у каждого коммита невероятно длинный и трудно читаемыйdiff
). - Коммиты "
Bash-4.3 patch XY
" (всего 46 патчей для версии 4.3) кладутся вmaster
(наbash-4.3-testing
их нет), а через 3 недели на веткеmaster
появляется меткаbash-4.4-beta2
. Это означает, что последнее стабильное состояние "bash
4.3 плюс патчи" взять, увы, неоткуда. Слава богу, TeamCity позволяет выполнять сборку по тэгу (флаг "Enable to use tags in the branch specification"), что и было в конце концов сделано.
Резюме:
- То, что я увидел, не похоже ни на традиционную схему создания веток, ни на git-flow.
- Да, я в курсе дела, что сборка по тэгу сводит к нулю весь смысл continuous integration, но общаться с разработчиком
bash
мы будем в другой раз.
Зависимости
При запуске первой же сборки мы увидим, что dpkg-buildpackage
завершил работу с кодом возврата 3:
В результате просмотра протокола сборки выяснится, что какие-то зависимости всё-таки отсутствуют:
Но вот мы установили всё, что требовалось (на всех агентах), а dpkg-buildpackage
завершается с тем же кодом. В чём же дело? Здесь есть несколько нюансов.
- Скорее всего, вы собираетесь собирать П/О из Debian unstable или Debain experimental. В таком случае, для удовлетворения необходимых для сборки зависимостей агенты TeamCity тоже должны работать п/упр Debian unstable или Debian experimental (иначе
dpkg-buildpackage
будет "ругаться", что ваши стабильные версии зависимостей "устарели"). Для подавления ошибки иногда достаточно добавить ключ -d:dpkg-buildpackage -uc -us -d
- Частным случаем устаревших зависимостей является сценарий
configure
, созданный более новой версией GNU Autotools, чем в настоящее время установлены в системе.dpkg-buildpackage
не в состоянии диагностировать такую ситуацию — вместо этого в протоколе сборки мы наблюдаем загадочные сообщения об отсутствующих макросахm4
. Решением является повторное создание сценарияconfigure
с помощью текущей версии GNU Autotools. Просто добавьте первым шагом сборки следующую команду:autoreconf -i
"Сломанные" unit-тесты
Если мы всё-таки хотим себя обмануть и таки собрать наш пакет, достаточно будет запустить dpkg-buildpackage
в изменённом окружении:
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -uc -us
О других способах самообмана можно почитать здесь.
Финишная прямая
После того, как все круги ада пройдены, мы увидим, что очередная сборка завершилась созданием артефактов:
Теперь самое время настроить наш Debian-репозиторий. Это достигается добавлением артефакт-фильтров в настройках модуля tcDebRepository. Некоторое неудобство состоит в том, что для каждой конфигурации (читай: программного пакета) приходится добавлять новый фильтр, фактически идентичный предыдущему:
Уже существующие артефакты не будут проиндексированы, поэтому после окончательной настройки Debian-репозитория в каждой конфигурации должна пройти как минимум одна сборка. После этого наступает предвкушение:
При добавлении репозитория в /etc/apt/sources.list
можно наблюдать все те же пакеты уже со стороны клиента:
N.B.! Если вы собираете под несколько архитектур (i386
, x32
, amd64
, arm
), стоит либо иметь несколько отдельных конфигураций сборки, соответствующих одному пакету и различающихся требованиями к агентам, либо, в дополнение к VCS Trigger, добавить Schedule Trigger с флагом "Trigger build on all enabled and compatible agents":
Через какое-то время вы увидите, что проект dpkg
активно развивается, а вот остальные участники, похоже, курят бамбук.
Автор: unix_junkie