- PVSM.RU - https://www.pvsm.ru -
Хотел бы поделится небольшим опытом по автоматизации и стандартизации процесса разработки. Статья не претендует быть истиной, но я надеюсь будет интерестным чтивом для конца рабочей недели.
Для начала немножко расскажу с чего все начиналось:
Самой большой проблемой было отсутсвие каких либо механизмов для контроля согласованности по функционалу между компонентами системы. Небыло ни одного критерия, основываясь на котором, можно было бы смело сказать, что взятые в какойто момент времение две компоненты системы согласованы между собой.
Согласованными по функционалу мы называем комноненты которые общаются между собой на одном языке одной версии протокола. В нашем случае версия протокола так же тесно переплетена с бизнес логикой. Точнее сказать ни какая новая бизнес логика не может быть введена без изменения или расширения протокола.
В ходе долгих дебатов о том “как правильно вести svn” был выбран вариант фиксирования тегов и сформулирован ряд требований/правил которому следует придерживаться:
Trunk
Tag N
Оговорка: в случае появления новой компоненты системы, которую уже можно начинать тестировать, но которая явно не дотягивает до функционала последнего тега, для того что бы попасть в общий процесс тестирования, такую компоненту можно брать из транка на ответственность разработчика и общем понимании, что это абсолютно исключительная и временная ситуация, пока не появится новый тег.
Наши теги, не такие уж и теги. Но они ближе по своей сути именно в понятию “тег” нежели к понятию “бранч”.
На обсуждении был и другой формат ведения SVN — вести основную разработку в бранчах.Т.е. если у нас возникает мажорное изменение, то мы создаем отдельный бранч, реализуем там это изменение и мержим его в транк. В этом случае транк всегда должен быть стабильным, что бы в любой момент времени можно было взять все компоненты системы и они были как минимум согласованы по функционалу, как максимум готовы для продакшена. В нашем случае это выглядит, не жизнеспособным. Так как порой одно мажорное изменение может вылезти в момент реализации другого. Тогда пришлось бы создавать на него отдлельный бранч и переключатся на него. Проблемы начались бы в момент когда нужно было бы смержить две векти в транк.
У нас весьма долкий цикл разработки, и еще не обкатан процесс перехода с версии на версию. Поэтому отдавая в публичное тестирование наш продукт, мы хотели бы иметь возможность делать хот фиксы. Но не имея тега(ветки) на каждую финальную версию, сделать это было бы не возможно. Так же мы не имеем возможности говорить, что “мол это будет исправленно с ледующей версии”.
Дальше в статье я буду использовать термин “тег” именно в том значении которое я описал выше.
От тегов не было бы пользы не будь в нем все компоненты соглдасованы по функционалу. Узким местом в это случае является момент времени когда мы срезаем скальп создаем тег. Как правило на одной из планерок мы принимаем решение о том, что в течении ближайшей недели мы должны подготовить транк для создание тега. Т.е. каждый из проектов должен прийти в состояние когда он согласован по функционалу со всеми компонентами с которыми он непосредственно общается. После этого мы создаем тег. Который уходит в тестирование. Тег мы именуем в специальном формате MAJOR_NUM.MINOR_NUM.
Слепдующим важным шагом был ввод критерия основываясь на котором можно было бы смело заявить, что две компоненты согласованы между собой. Мы решили, что этим критерием будет версия. При этом версия сама по себе должна нести информацию основываясь на которой можно понять, что две компоненты согласованы.
Формат версии: MAJOR_NUM.MINOR_NUM.REVISION. Т.е. первая часть версии является так же номером тега. А мы знаем, что у нас все компоненты в теге согласованны. Указание сразу двух чисел в названии тега, позволяет делать нормальнй переход между мажорными версиями, т.е. вместо 1.1.x, 1.2.x, 1.3.x, 2.4.x, у нас будет 1.1.x, 1.2.x, 1.3.x, 2.1.x. Номер ревизии остается и используется как обычно. Это номер ревизии каждой из отдельных компонент, а не просто последняя ревизия тега.
Следующим шагом был процесс внедрения CI (Continuous Integration). Выбор пал на, думаю многим известную CI систему, Jenkins. Выбор был между Cruise control, с которым я имею не самый приятный опыт работы, Team City которым является платным для нормального его использования и непосредственно Jenkins, который бесплатен, широко распростренен и хорошо документирован. Фактор бесплатности был немаловажен, так как сташно просить у начальства деньги за что то, что не факт что приживется.
Компоненты нашей системы весьма разнообразные и на текущий момент используют 3 платформы для сборки: windows, linux и mac os. Получается один мастер и 2 slave (не хочу я больше повторять слово “раб”). Вопрос где делать мастера не возникал, конечно же на Linux. Была развернута начальная конфигурация из одного мастера (Linux) и одного slave (Windows). Начался процесс автоматизации сборки всех наших компонент. В ходе работы, уже появился тег 1.1 и число задач в Jenkins перевалило за 10. И тут начались проблемы. В один прекрасный день Jenkins упал. Мы его подняли, он у пал снова. И еще раз. И продолжал падать, независимо от того, как мы его запускаем через Tomcat или как службу. Независимо от JAVA машины, open JDK или SUN java. Независимо от текущей версии. Вернее падал не сам Jenkins, а JAVA машина которую он рушил. Я даже завел отдельный баг в их багтрекете (JENKINS-16199 [1], правда на это все и заглохло). Потратив полторы недели на всякие попытки понять что происходит или хотябы почему, было принято решение перенести мастера на Windows систему. И о чудо, в той же самой конфигурации все стало работать стабильно. Со времене число задач возросло в два раза, но все продолжает работат. В итоге конечная структура выглядит так:
Мастер на Windows, два Slave, на Linux и MacOS, взаимодействие по SSH через побличные ключи.
Стандартную поставку Jenkins мы расширили следующими плагинами:
Copy Artifact Plugin [2] — Используем для того что бы артифакт одной сборки использовать другой. Тут есть один просто момент, на котором можно споткнуться.
Если вы в одной из задача сохраняете артифакт вот так
А в другой, используя данный плагин, загружаете этот арт
То вы как минимум должны указать путь до него так же как в первом случае, а еще не помешает установить опцию “Flatten directories” что бы отбросить лишние пути и скопировать только сам арт в то место куда вам нужно.
Jenkins description setter plugin [3] — Позволяет указывать некоторую информацию о каждой сборке в поле Build Description. Те задачи которые имеют версию, выводят ее туда.
Extra Columns Plugin [4] — позволяет добавить поле Build Description на View.
Publish Over SSH [5] — Отличный плагин для заливки файлов и выполнения команд на удаленной машине. Правда пока его не используем в силу того, что автотестирование еще не налажено. Недостатком данного плагина является то, что требует предварительная конфигурации всех SSH соединений и в каждой задаче явно указывается кукое соединение использовать на этапе ее создания.
Python Plugin [6] — часть шагов сборки написано на Python, потому что так проще. В том числе есть отдельная задача которая делает почти все тоже самое что Publish Over SSH [5] но только позволяя на лету конфигурировать параметры доступа к удаленной машине.
XCode integration — Используется для сборки проекта на MacOS. Нам пришлось попотеть для того, что бы уметь делать сборки как для разных версий iOS. В итогде на билд машине было разрешено использовать комманду sudo xcode-select -switch без ввода пароля.
Я уже упоминал необходисость удаленной заливки и выполнения команд, которую почти прекрасно рещает плагин Publish Over SSH [5]. Но который не позволяет непосредственно для каждого процесса сборки указать нужный таргет.
У нас есть свой инсталятор, несколько тестировшиков и несколько машин. Многим лень тащить этот файл себе и чтото делать с ним что бы установить продукт. Для этих целий была создана сцепиальна задача “Remote deploy”.
И так, что она умеет:
Забрать инсталятор из тега который укажет пользователь
Выполнить его установку на той машине которую укажет пользователь
Вот как это выглядит
Данная задача является параметризированной.
Параметры
TAG, HOST, USER, DEPLOY_DIR, OPENSSL_DIR, тут никакой магии, обычные строки.
JOBS_NUMBER — “Build selector for Copy Atrifact”, позволяет указать какую версию сборки брать, последнюю удачную или какотой определенный номер или что то еще.
PASSWORD это параметр типа “Password Parameter” — закрывает пароль звездочками.
Вот таким образом забирется нужная сборка из нужной задачи
Виды в Jenkins это средство кастомизации отображения проектов. Мы убрали одну колонку и добавили “Build Description” для наших видов Trunk, Tag_X. Мы хотели что бы на дефолтном виде Jenkins было так же. Но Jenkins не позволяет делать такие манипуляции с его главным видом. Вместо этого можно создать свой вид (Default), добавить в него все проекты по маске .* и сделать этот вид, видом по умолчанию.
У нас есть специальный скрипт для создание версии и всех ее возможных вариаций. В начале он появлялся в каждом из проектов в которм нужен был подобный функционал. Спустя время, мы его положили в одном месте и везде где он нужен, тянем его как внешнюю зависимость. И тогда случился Epic fail, когда его случайно поправили в одном из проектов, где он был зависимостью. В Jenkins выстроилось в очередь 15 проектов на пересборку, холостую пересборку.
Первое что пришло в голову, это заблокировать файл для изменений. На файл повесили свойство needs-lock и от специального build юзера заблокировали его (svn lock).
Но есть решение лучше. Горазду лучше. Jenkins позволяет ввести фильтрацию перед запуском сборки иницированной изменением репозитория. Это находится в разделе “Управление исходным кодом -> Расширенные”. Нас инетерсует параметр “Excluded Regions” в котором можно указать изменения в каких файлах и директориях стоит игнорировать.
На этом мое повествование заканчивается. В данный момент я уже покинул то место работы где был получен сей опыт и написана данная статья, поэтому на возможно возникшые вопросы о детялаях и настройках наврядли смогу ответить.
Спасибо за внимание.
Автор: Cupper
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/45469
Ссылки в тексте:
[1] JENKINS-16199: https://issues.jenkins-ci.org/browse/JENKINS-16199
[2] Copy Artifact Plugin: http://wiki.jenkins-ci.org/display/JENKINS/Copy+Artifact+Plugin
[3] Jenkins description setter plugin: http://wiki.jenkins-ci.org/display/JENKINS/Description+Setter+Plugin
[4] Extra Columns Plugin: http://wiki.jenkins-ci.org/display/JENKINS/Extra+Columns+Plugin
[5] Publish Over SSH: http://wiki.jenkins-ci.org/display/JENKINS/Publish+Over+SSH+Plugin
[6] Python Plugin: http://wiki.jenkins-ci.org/display/JENKINS/Python+Plugin
[7] Источник: http://habrahabr.ru/post/197158/
Нажмите здесь для печати.