- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток, %username%. Не так давно, меня попросили настроить Continuous Integration сервер, настоятельно порекомендовав использовать JenkinsHudson. Я, как человек несведущий в данных делах, решил изучить советы и обзоры по настройке CI систем в сети. Хочется выразить благодарность Wolonter [1] за эту [2] статью, она помогла мне понять общую концепцию и предоставила широчайший набор полезных плагинов. Но, как выяснилось, далеко не все, что я хотел реализовать, оказалось возможным найти в «интернетах». Для тех, кому интересны маленькие(и не очень) шалости и то, как я к ним пришел — прошу под кат.
И так, первоначальной задачей была научить систему просто запускать web-сервера, отслеживать изменения в репозиториях и запускать jUnit, TestNG и Selenium тесты. Со временем эта задача обросла кучей мелочей, о которых будет рассказано позже. Вроде бы не сложно, но, как оказалось, первое мнение бывает ошибочным. С чистой совестью я установил centos 6 x64 на предоставленную мне виртуальную машину, и несколькими движениями установил CI:
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins
Естественно нужно не забыть установить jdk и проверить, добавился ли jenkins в автозагрузку. Примерно так, произошел мой первый неудачный запуск Jenkins CI — ajp порты Jenkins'a конфликтовали с одним из ранее установленных веб серверов(по совместительству нереляционной БД). После отключения ajp в конфигурационном файле все стало на свои места, и наконец-то я смог увидеть все чудеса воочию.
Пока я занимался настройкой, мной было допущено много ошибок, по этому предлагаю небольшой список, для людей которые любят экономить свое время:
Думаю каждому есть, что добавить к этому списку. Но вроде бы, все самое главное, я учел. И очень надеюсь, что этот небольшой список сэкономит время многим.
Естественно после первого запуска мне было непривычно смотреть на синие кружечки, но их цвет был изменен далеко не сразу. Я настроил SVN и Git, распределил иерархию проектов и все вроде бы заработало. На следующий день, на одной задаче было 4 запланированных сборки, а запущенная длилась уже порядка 9 часов. Так вышло, что именно в этот день, был сделан «плохой» коммит, который заставлял уходить unit тест в бесконечное ожидание. На помощь пришел Build-timeout Plugin [4]. С другой стороны, у меня были проекты, которые должны находиться в «бесконечной сборке». Ant task'и, которые запускали веб сервера и в сборку выводили лог действий, что было очень удобно. Естественно эти сервера могли находиться по несколько дней в запущенном состоянии, и без лишней надобности их останавливать нет смысла, т.к. на них могут вестись работы, показываться результаты заказчикам и прочее. Было решено создать проект, который в определенное время суток проверяет, есть ли обновление ветки, и если есть — выкачивает обновление и перезапускает сборку. Больше всего убила реакция менеджеров, которые задали вопрос: «а почему полосочка сборки проекта красненькая? — ну наверно, потому что сейчас 10 утра и сборка последние 6 часов ничего не писала в лог». Решение перекраски полосок я еще не нашел(см. пункт 11), но думаю это не сложно. С незаканчивающейся сборкой возникли другие проблемы: как же запустить юнит тесты, на отдельном сервере не создавая 2 проекта? Ведь для реализации этого, нужно запустить 2 ant task'a: 'start-server' и 'junit', первый из которых, не заканчивается. Почему на отдельном сервере спросите вы: потому что не хорошо забивать тестами основной веб сервер. Более того, веб сервер для тестов должен запускаться по необходимости и только на время выполнения юнит тестов, да бы не тратить лишние ресурсы. Вспомнив о всяческих возможностях ant решено было сделать как-то так:
<target name="start-server-with-units">
<parallel>
<daemons>
<antcall target="start-server">
</antcall>
</daemons>
<sequential>
<waitfor maxwait="10" maxwaitunit="minute">
<socket server="localhost" port="${port}" />
</waitfor>
<antcall target="junit">
</antcall>
</sequential>
</parallel>
</target>
Формально мы ждем пока сервер запустится, запускаем на нем юнит тесты, и выключаем сервер по завершению тестов. Собственно что и требовалось. Мне кажется, что средствами Jenkins одним проектом, подобное сделать невозможно.
На мой взгляд в Дженкинсе плохо реализована поддержка бренчевания. «svn://svn.adress:port/${branchName}», где branchName — это переменная среды, часто не решает проблемы. Во-первых, подобные сборки можно запускать только руками, или же с параметром по умолчанию, но запуск сборки по Pall SCM уже явно невозможен. Если кому-то нужен подобный функционал(как выяснилось мне он все же не понадобился), то он с чистой совестью может написать groovy скрипт, который при запуске будет менять значение branchName по умолчанию на значение, которое было задано при запуске и потом запускать проект по обычному расписанию, и при необходимости добавить проверку, на наличие обновления в системе контроля версий. Минус такого подхода, что в череде ненужных сборок, трудно найти что-то полезное. Но это тоже не беда, в тот же postBuild groovy script можно прикрутить «педали», которые будут удалять «холостые» сборки. А стоит ли придумывать этот чудо groovy script если можно создать еще один проект, который будет проверять на наличие обновлений?
Вывод: иногда все же стоит создать на один проект больше, чем писать очередной велосипед.
Так же к проблеме бренчевания я бы отнес Build Name Setter Plugin [5]. Довольно приятно вместо номера сборки видеть имя бренча, но и тут все не так просто. Т.к. не у всех переменных есть атрибут length(например у переменных среды), с помощью которого можно обрезать максимальную длину строки. Согласитесь, подобный вид не очень мотивирует, а что если длина будет не 30, а 255 символов?
Эту проблему опять же можно решить с preBuild groovy script. Но в моей ситуации было проще попросить делать названия бренчей информативными и не очень длинными. Очень удобно, когда какие-то неудобства решаются не велосипедами, а здравым смыслом.
Все мы люди, и все хотим какого-то комфорта. Писать свой плагин мне не хотелось, на компромиссы идти было не с кем, а добиться результата — хотелось. По этому здесь я опишу, все те велосипеды, которые каким-либо образом мне облегчили жизнь.
if(manager.build.result == hudson.model.Result.ABORTED){
manager.build.@result = hudson.model.Result.SUCCESS
}
Т.к. у меня были проекты, которые можно было завершить только по нажатию крестика(что означает «отмена сборки»), меня очень сильно угнетали серые шарики, по этому мне захотелось сделать сборку успешной(пусть не портит статистику, я же знаю, что все правильно). Plugin'a реализующего это я не нашел, зато нашел Groovy Postbuild Plugin [6], который я активно пиарил и антипиарил выше. Так вот, groovy postbuild API (назовем его так), предлагает метод buildSuccess(), для задания успешного состояния сборки, и подобные для других состояний. Проблема в том, что данный метод ничего не делает. Все семейство может только ухудшить текущее состояние сборки, а т.к. Aborted намного хуже чем Success, то состояние сборки не менялось. В свое время на Jenkins'e я нашел три issue с просьбой реализации полноценного функционала изменения статуса сборок. Представленный выше кусок кода, настолько прост, что он просто не мог уложиться мне в голову. Задав себе вопрос: «а может быть у groovy реализован аналог reflections?» решение проблемы пришло моментально. Надеюсь любители извращений изысков оценят.
Build promotion. Да, я знаю про существование Promoted Builds Plugin'a [7], но в моем случае он опять же не помог. Был один сервер, который обновлялся только руками и поднимал прописываемый в ручную бренч, и был проект, который запускался раз в 2 часа, узнавал гитовую ветку первого проекта, скачивал ее и запускал юнит тесты. Количество сборок в проектах было разное. По договоренности было решено давать звезду, если последние юнит тесты были успешны. При чем звезда присваивается только по завершению работы первого сервера. Согласитесь, довольно необычная реализация promoted plugin заточенная чисто под личные нужды:
item = hudson.model.Hudson.instance.getItem("jUnitJobName")
def build = item.getLastBuild()
if(build.getResult() == null){
build = build.getPreviousCompletedBuild()
}
def result = build.getResult()
if(result == hudson.model.Result.SUCCESS){
manager.addBadge("star-gold.gif", "Success Unit Tests")
} else {
manager.addBadge("warning.gif", "Unit Tests Failure")
}
Борьба с ручным тестированием
Так уж сложилось, что тестеры бывают разные. И очень обидно, когда они скорее всего знают, почему что-то работает не так, но заблаговременно пытаются спихнуть ответственность, аргументируя «я все делал(а) хорошо, а оно сломалось, ты виноват, ты чини». Именно для таких случаев очень хорошо помогает AnsiColor Plugin [8]. Если и это не подействует, то настоятельно рекомендую воспользоваться более обидными мерами: Build User Vars Plugin [9] — личное обращение делает ваши действия более постыдными(откуда вообще машина узнала как меня зовут?). Главное не переусердствовать, возможна ситуация, когда скрипт некорректно работает, а тестеры боялись 3 дня спросить, ибо им в консоли писалось: «а ты точно все сделал правильно?». В этом случае все камни полетят в вас. Никто не любит выглядеть дураком. Но если накосчячил — получай что-то подобное(! красный цвет использовать обязательно):
Ну и в завершение напишу вещи — которые мне очень бы хотелось, но писать плагины я не стану. Может быть они и реализованы, но я их не нашел. За подсказки — буду благодарен.
Авто запуск сборок при старте. Допустим из-за скачка напряженияотсутствия света сервер перезагрузили. На нем запустился JenkinsCI, но не запустились проекты, которые должны быть постоянно запущены? Каждый раз запускать ручками — глупо. Так что, очень хочется галочку: «запускать ли данный проект, после перезагрузки?»
SVNGit custom branch + patch, если обновляться указанными выше образами, то он просто переписывает все существующие локальные изменения. Это делает очень неудобным применение патчей. Уж больно не нравятся мне мои скрипты, которые отменяют патч, выкачивают нужную ветку и применяют патч обратно.
System Message. Что бы результат выполнения 'jenkinsconfigurationSystem Message' отображался на всех страницах, а не только на view. И вообще, хотелось бы больше плагинов по изменению внешнего вида. Т.к. в первую очередь, это облегчает работу менеджерам, а чем меньше вопросов по эксплуатации, тем больше времени остается на разработку.
Rebuild Plugin. Хочу, что бы Rebuild Plugin научился останавливать предыдущую сборку, а то нажал кнопку «rebuild», а он только запланировал еще одну сборку.
P.S. Я отдаю себе отчет в том, что вещи которые мне хочется, далеко не вещи первой необходимости, но это те вещи, которых мне наверное не хватает для полного счастья. Надеюсь данная статья будет кому-то полезной.
Автор: kentilini
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/plugins/36682
Ссылки в тексте:
[1] Wolonter: http://habrahabr.ru/users/wolonter/
[2] эту: http://habrahabr.ru/post/168451/
[3] ChuckNorris Plugin'a: https://wiki.jenkins-ci.org/display/JENKINS/ChuckNorris+Plugin
[4] Build-timeout Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Build-timeout+Plugin
[5] Build Name Setter Plugin: http://wiki.jenkins-ci.org/display/JENKINS/Build+Name+Setter+Plugin
[6] Groovy Postbuild Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Groovy+Postbuild+Plugin
[7] Promoted Builds Plugin'a: https://wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin
[8] AnsiColor Plugin: https://wiki.jenkins-ci.org/display/JENKINS/AnsiColor+Plugin
[9] Build User Vars Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Build+User+Vars+Plugin
[10] Источник: http://habrahabr.ru/post/183558/
Нажмите здесь для печати.