- PVSM.RU - https://www.pvsm.ru -

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

… или использование TeamCity для сборки *.deb-пакетов и не только.

Написать статью меня побудило знакомство с модулем tcDebRepository [1]. Я наивно полагал, что "вот сейчас я его подключу, и всё волшебным образом заработает". Как водится, не заработало, и в конце концов был накоплен некий опыт, который захотелось систематизировать.

Статья ни в коей мере не является введением в основы TeamCity и предполагает, что читатель уже знаком и собственно с TeamCity, и с инфраструктурой Debian GNU/Linux. Если вы уже представляете, что такое continuous integration, но ещё ни разу не держали в руках TeamCity — вам, наверное, сюда [2]. О сборке пакетов в Debian можно почитать в Debian New Maintainers' Guide [3].

Для игр (на случай, если кто-то захочет воспроизвести результаты) использовался сервер TeamCity 10 и 3 агента п/упр Debian 8.0 (Jessie). 3 агента — это лимит в случае TeamCity Professional [4]. Всё ниженаписанное, думаю, без проблем переносится на любой другой дистрибутив на основе Debian GNU/Linux, напр., Astra Linux [5].

Планы

Достаточно произвольным образом я выбрал для экспериментов 4 пакета:

С учётом ограничения лицензии типа Professional на количество конфигураций сборки можно было "набрать" до 20 пакетов.

Подготовка

TeamCity загружается [15] с официального сайта. Кроме собственно TeamCity, на каждую из агентских машин нам потребуется установить пакет build-essential [16], равно как и необходимые для сборки зависимости для всех четырёх пакетов (из категорий build-depends и build-depends-indep). Это позволит минимизировать (но совсем не обязательно устранить) проблемы с зависимостями при сборке.

Виды пакетов в Debian GNU/Linux

Пакеты, помимо прочих особенностей, делятся на "родные" (native) и внешние (non-native) (подробнее [17]). "Родные" пакеты (autotools-dev, debhelper, dpkg) обычно разрабатываются в рамках проекта Debian, и исходный код уже содержит необходимую для сборки метаинформацию (каталог debian/ в корне дерева исходного кода).

Отличие внешних пакетов (bash) в том, что исходный код никоим образом не завязан на Debian, и инженерам сопровождения (в русскоязычной документации это называется "разработчик Debian", в англоязычной — просто "maintainer") приходится поддерживать параллельное дерево исходного кода с метаинформацией и патчами (это то самое содержимое каталога debian/).

Общие настройки

Бинарные пакеты, которые мы будем собирать — это, в терминологии TeamCity, "артефакты". Соответственно, нужно указать, что мы ожидаем иметь в сухом остатке по окончании очередной сборки, указав artifact paths [18]:

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

Для "родных" пакетов артефакты 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

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

image

Теперь можно добавить VCS-триггер и к настройке контроля версий уже не возвращаться:

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

Интеграция с Bazaar

"Но ведь для сборки bash требуется интеграция с Bazaar, а штатная поставка TeamCity не поддерживает эту систему!" — скажет внимательный читатель, и будет прав. Кроме того, TeamCity, увы, не позволит нам добавить и Git URL вида bzr::http://bazaar.launchpad.net/~doko/+junk/pkg-bash-debian — у JGit слишком много ограничений.

Существует внешний модуль [19] для поддержки Bazaar, но у него есть по меньшей мере два серьёзных недостатка:

  • checkout на стороне агента не поддерживается, и
  • штатной поставки Bazaar недостаточно, т. к. модуль опирается на функциональность bzr xmlls и bzr xmllog [20], что выясняется только в процессе сборки:

image

Поскольку сервер TeamCity у меня работал на Windows, я отказался от весёлого приключения в виде установки Bazaar на стороне сервера, а вместо этого в случае пакета bash просто добавил ещё один шаг сборки (Bazaar-интеграцию для бедных), используя Command Line Runner [21] и следующий сценарий оболочки:

#!/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! [22], позволяющее редактировать содержимое текстовых полей во внешнем редакторе. Можно подключить 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 [23] происходит через равные промежутки времени, причём через 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 [24]"), что и было в конце концов сделано.

Резюме:

  • То, что я увидел, не похоже ни на традиционную схему создания веток, ни на git-flow.
  • Да, я в курсе дела, что сборка по тэгу сводит к нулю весь смысл continuous integration, но общаться с разработчиком bash мы будем в другой раз.

Зависимости

При запуске первой же сборки мы увидим, что dpkg-buildpackage завершил работу с кодом возврата 3:

image

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

image

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

  • Скорее всего, вы собираетесь собирать П/О из Debian unstable или Debain experimental [25]. В таком случае, для удовлетворения необходимых для сборки зависимостей агенты TeamCity тоже должны работать п/упр Debian unstable или Debian experimental (иначе dpkg-buildpackage будет "ругаться", что ваши стабильные версии зависимостей "устарели"). Для подавления ошибки иногда достаточно добавить ключ -d [26]:
    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

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

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

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

image

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

image

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

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

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

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

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

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

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

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

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

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

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

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

Happy building!

image

Автор: unix_junkie

Источник [29]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/222619

Ссылки в тексте:

[1] tcDebRepository: https://github.com/tcplugins/tcDebRepository

[2] сюда: https://www.youtube.com/playlist?list=PLQ176FUIyIUZGrzpC-C_jwXpsa22XKXdt

[3] Debian New Maintainers' Guide: https://www.debian.org/doc/manuals/maint-guide/

[4] Professional: https://www.jetbrains.com/teamcity/buy/#license-type=new-license

[5] Astra Linux: http://www.astralinux.com/download.html

[6] autotools-dev: https://packages.debian.org/source/unstable/autotools-dev

[7] Git: https://anonscm.debian.org/gitweb/?p=users/hmh/autotools-dev.git

[8] bash: https://packages.debian.org/source/unstable/bash

[9] Git: http://git.savannah.gnu.org/cgit/bash.git

[10] Bazaar: https://code.launchpad.net/~doko/+junk/pkg-bash-debian

[11] debhelper: https://packages.debian.org/source/unstable/debhelper

[12] Git: https://anonscm.debian.org/git/debhelper/debhelper.git

[13] dpkg: https://packages.debian.org/source/unstable/dpkg

[14] Git: https://anonscm.debian.org/git/dpkg/dpkg.git

[15] загружается: https://www.jetbrains.com/teamcity/download/#section=linux-version

[16] build-essential: https://packages.debian.org/jessie/build-essential

[17] подробнее: https://wiki.debian.org/DebianMentorsFaq#What_is_the_difference_between_a_native_Debian_package_and_a_non-native_package.3F

[18] artifact paths: https://confluence.jetbrains.com/display/TCD10/Configuring+General+Settings#ConfiguringGeneralSettings-ArtifactPaths

[19] внешний модуль: https://launchpad.net/bzr4j/

[20] bzr xmlls и bzr xmllog: http://wiki.bazaar.canonical.com/XMLOutput

[21] Command Line Runner: https://confluence.jetbrains.com/display/TCD10/Command+Line

[22] It's All Text!: https://addons.mozilla.org/en-US/firefox/addon/its-all-text/

[23] savannah.gnu.org: http://savannah.gnu.org/

[24] Enable to use tags in the branch specification: https://confluence.jetbrains.com/display/TCD10/Git#Git-GeneralSettings

[25] Debain experimental: https://wiki.debian.org/DebianExperimental

[26] -d: http://man7.org/linux/man-pages/man1/dpkg-buildpackage.1.html

[27] здесь: https://wiki.debian.org/BuildProfileSpec

[28] Schedule Trigger: https://confluence.jetbrains.com/display/TCD10/Configuring+Schedule+Triggers

[29] Источник: https://habrahabr.ru/post/204496/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best