… или использование 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:
![](https://habrastorage.org/files/87b/e4b/abc/87be4babcf1441008ab72345b4b6700a.png)
Для "родных" пакетов артефакты 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/
. Это достигается добавлением в checkout rules одной строчки:
+:.=>dpkg
и в конечном счёте выглядит так:
Теперь можно добавить VCS-триггер и к настройке контроля версий уже не возвращаться:
![](https://habrastorage.org/files/0fa/6ac/95e/0fa6ac95e61546c197b35b90bb8be392.png)
Интеграция с 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
О других способах самообмана можно почитать здесь.
Финишная прямая
После того, как все круги ада пройдены, мы увидим, что очередная сборка завершилась созданием артефактов:
Если вы не хотите, чтобы с каждым инкрементом версии пакета количество артефактов единичной сборки увеличивалось (в конечном счёте предлагая широкий ассортимент из dpkg_1.18.16_i386.deb
, dpkg_1.18.17_i386.deb
и dpkg_1.18.18_i386.deb
), содержимое рабочего каталога стоит выборочно очищать перед каждой сборкой. Это можно было бы выполнить вручную, непосредственно перед dpkg-buildpackage
вызвав rm -rf
c пресловутыми artifact paths в качестве аргументов, но есть способ лучше — штатный модуль TeamCity с ласковым названием "Швабра". Вот так выглядят его настройки (ключевое здесь — "Before next build start"):
![](https://habrastorage.org/files/8bb/de5/2c7/8bbde52c75bc412c9dac315186f1a9c5.png)
А вот таким образом будет выглядеть соответствующий фрагмент протокола сборки, если модуль Swabra правильно настроен:
![](https://habrastorage.org/files/12a/445/8bd/12a4458bd5954e97b2fc6d411713705e.png)
Теперь самое время настроить наш Debian-репозиторий. Это достигается добавлением артефакт-фильтров в настройках модуля tcDebRepository. Некоторое неудобство состоит в том, что для каждой конфигурации (читай: программного пакета) приходится добавлять новый фильтр, фактически идентичный предыдущему:
Уже существующие артефакты не будут проиндексированы, поэтому после окончательной настройки Debian-репозитория в каждой конфигурации должна пройти как минимум одна сборка. После этого наступает предвкушение:
![](https://habrastorage.org/files/1a4/5ee/d6e/1a45eed6e781486380420a2c0c389ae7.png)
![](https://habrastorage.org/files/ddb/386/191/ddb386191ef74a9b804c0855fad4b2d0.png)
При добавлении репозитория в /etc/apt/sources.list
можно наблюдать все те же пакеты уже со стороны клиента:
![](https://habrastorage.org/files/878/459/c62/878459c626d64abfb11705569804e5f6.png)
![](https://habrastorage.org/files/31b/964/9aa/31b9649aaeae4bcc87ee8a4142855658.png)
N.B.! Если вы собираете под несколько архитектур (i386
, x32
, amd64
, arm
), стоит либо иметь несколько отдельных конфигураций сборки, соответствующих одному пакету и различающихся требованиями к агентам, либо, в дополнение к VCS Trigger, добавить Schedule Trigger с флагом "Trigger build on all enabled and compatible agents":
![](https://habrastorage.org/files/d64/297/9d2/d642979d28bf442a9248e70015904cae.png)
Через какое-то время вы увидите, что проект dpkg
активно развивается, а вот остальные участники, похоже, курят бамбук.
Комментарии (12)
rudenkovk
19.12.2016 11:48+1Беда таких систем сборки конечных пакетов в следующем (мой опыт): нет пересборки по древу зависимостей. (сделать можно, но дикое усложнение и деньги, в случае TC/Bamboo). Сие ведет, в частности, к тому, что тяжело контролировать версии (когда их нужно много). Если пакетов мало, то с OBS нет никакого смысла заморачиваться. В противном случае, проще отправлять таском из CI в OBS.
Singaporian
19.12.2016 14:23+1Статья обалденная. Но в ней, кроме сисек, не раскрыт еще один важный момент: debian/changelog. Как он меняется? Что происходит в случае Team Upload (dch --team)? Что в случае QA Upload(dch --qa)? NMU? Как автоматически отображать релиз в ченджлоге (dch -r)?
unix_junkie
19.12.2016 20:29Спасибо за оценку.
На вопрос, думаю, смогу ответить спустя какое-то время, когда наберётся достаточная статистика по
dpkg
(пока что не было ни одного NMU или QA Upload).
Пока что вижу, что
- не всякий коммит сопровождается записью в
debian/changelog
, что странно - имена авторов изменения в VCS и в
debian/changelog
изредка различаются, что тоже странно
Думаю, надо внимательно курить специфичную для Debian литературу (Policy Guide и т. д.).
Могу порекомендовать Вам поднять сборку
dpkg
, используя статью в кач-ве инструкции, и убедиться во всём воочию.Singaporian
19.12.2016 21:55+1А вот в этом то и проблема. Запись в ченджлоге должна быть не с каждым коммитом (может там всего лишь identetion поправили), а одна запись на одну story или один bugfix. То есть законченная задача, связанная не столько с системой контроля версий, сколько с issue-трэкером — значит он тоже должен быть в связке.
unix_junkie
19.12.2016 23:06Похоже, пора переводить статью на английский и писать в
debian-devel@lists.d.o
с просьбой прокомментировать.
unix_junkie
21.12.2016 16:56Андрей Рахматуллин из проекта Debian комментирует:
If you use dpkg-buildpackage then the specifics of the last changelog entry don't matter.
Singaporian
21.12.2016 17:10+1Doesn't matter потому что он говорит про «entry». Но версию то менять надо. На ее основе будет собран пакет с этой версией и отправлен в репозиторий. Если версию не поменять автоматически, то он перетрет старый пакет в репо. В результате все машины, настроенные на этот репозиторий выкинут ошибку о неконсистентной чексумме. А даже если им всем сделать apt-get clean/update, то все равно апдейтиться на эту версию они не станут, так как у них уже эта версия стоит (хотя по факту она предыдущая).
unix_junkie
21.12.2016 17:36Я понял.
Т. е. вопрос скорее в контексте не continuous integration, а continuous delivery. Тогда это не вопрос ко мне или к разработчикам Debian, а задача для автора tcDebRepository, причём имеющая смысл исключительно для сборки пакетов из основной поставки Debian GNU/Linux.
Если я собираю свой пакет на своём сервере, я не вижу проблем в том, чтобы просто сделать инкремент версии в случае, эквивалентном, скажем, binNMU.
Или я что-то упустил?
Singaporian
21.12.2016 17:56+1Да, это откровенно continuous delivery (даже если это деливери в QA). Но .deb — это вообще continuous delivery всегда по определению :)
По поводу своего пакета — тогда врядли актуально. Я тоже собираю свои пакетики для инфраструктуры. Changelog меняю руками. Вполне хватает рук, автоматика не нужна. Все вышесказанное актуально для пакетов основного приложения, которое тестируют, деплоят и обновляют. Где важен конвейер.
- не всякий коммит сопровождается записью в
gtbear
1. Можете объяснить в чем смысл самостоятельно собирать пакеты типа bash?
2. Смотрели ли вы в сторону http://openbuildservice.org/ который как раз таки заточен под сборку пакетов и интеграцию с репозиториями?
unix_junkie
bash
приведён исключительно для примера. Смысл собирать в том, чтоxfs
, X11 Font Server) ранее присутствовали в дистрибутиве, а затем были исключены из него, но по-прежнему представляют интерес для пользователей.