Pull to refresh

TeamCity как Debian-репозиторий

Reading time 8 min
Views 7K

… или использование 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, равно как и необходимые для сборки зависимости для всех четырёх пакетов (из категорий image build-depends и image 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/. Это достигается добавлением в checkout rules одной строчки:


+:.=>dpkg

и в конечном счёте выглядит так:


image


Теперь можно добавить 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, что выясняется только в процессе сборки:

image


Поскольку сервер 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" можно заполнить в один щелчок мыши, не вводя имя каталога вручную:


image


Сборка: разрешение проблем


Качество кода


Как ни странно, но качество кода (или, точнее, стиль разработки) может являться серьёзной проблемой на пути внедрения continuous integration. Опытным путём выяснилось, что, в случае bash, версии в двух деревьях кода рассинхронизированы: последние коммиты в основном дереве соответствуют версии 4.4, хотя файл debian/changelog уже без малого два года назад остановился на версии 4.3, и код одной версии с метаинформацией другой версии вместе не собираются. Хорошо, значит, мне нужна ветка bash-4.3 в основном дереве.


А теперь можно посмотреть на дерево коммитов и порадоваться.

image


  • Вот идёт ветка 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:


image


В результате просмотра протокола сборки выяснится, что какие-то зависимости всё-таки отсутствуют:


image


Но вот мы установили всё, что требовалось (на всех агентах), а dpkg-buildpackage завершается с тем же кодом. В чём же дело? Здесь есть несколько нюансов.


  • Скорее всего, вы будете собирать ПО из Debian unstable или Debian 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

О других способах самообмана можно почитать здесь.


Финишная прямая


После того, как все круги ада пройдены, мы увидим, что очередная сборка завершилась созданием артефактов:


image


Если вы не хотите, чтобы с каждым инкрементом версии пакета количество артефактов единичной сборки увеличивалось (в конечном счёте предлагая широкий ассортимент из 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"):



А вот таким образом будет выглядеть соответствующий фрагмент протокола сборки, если модуль Swabra правильно настроен:



Теперь самое время настроить наш Debian-репозиторий. Это достигается добавлением артефакт-фильтров в настройках модуля tcDebRepository. Некоторое неудобство состоит в том, что для каждой конфигурации (читай: программного пакета) приходится добавлять новый фильтр, фактически идентичный предыдущему:


image


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


Каталоги пакетов по архитектурам

и список доступных пакетов

При добавлении репозитория в /etc/apt/sources.list можно наблюдать все те же пакеты уже со стороны клиента:


Заметно, что у пакетов отсутствует цифровая подпись


N.B.! Если вы собираете под несколько архитектур (i386, x32, amd64, arm), стоит либо иметь несколько отдельных конфигураций сборки, соответствующих одному пакету и различающихся требованиями к агентам, либо, в дополнение к VCS Trigger, добавить Schedule Trigger с флагом "Trigger build on all enabled and compatible agents":



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


Happy building!

image

Tags:
Hubs:
+15
Comments 12
Comments Comments 12

Articles