Интегрируем TeamCity с JIRA – без плагинов и администраторов

Мы разрабатываем большое модульное UI-приложение, состоящее из большого количества плагинов с разными циклами релиза. Весь код располагается в одном репозитории, так что к разработчикам постоянно приходит QA-специалист и спрашивает: «А какой компонент поменялся? Какую версию выкладывать, чтобы проверить задачу?». Вопрос оказался актуален не только на UI (C#), но и на backend (Java). После наших опрометчивых обещаний все писать ручками я предложил автоматически формировать нужный список на базе изменившихся файлов в момент merge pull-request-а. В этой статье мы расскажем, как организовали это через расширение функциональности сборок на TeamCity (TC) без администраторских прав на сервере и установки внешних плагинов.

e_0qsrezlhthv-kmt1cxfymzebu.png


Условия задачи


Для начала определим, что должен уметь наш инструмент:

  1. При успешной сборке проставлять в JIRA номер сборки и указывать в комментарии дополнительную информацию (в какой ветке починили, какие компоненты развертывать и т.п.)
  2. При неуспешной сборке посылать письмо конкретным людям с конкретным шаблоном и описанием проблемы.


Вот как это может выглядеть:

-ziu65qoccnlbihsdingrwuls_s.png

Теперь перечислим требования по реализации:

  1. Некий нетривиальный код (логика) после сборки.
  2. Использование Windows- и Linux-агентов.
  3. Ничего нестандартного на агентах.
  4. Легкая тиражируемость на build-конфигурации.


Выбираем решение


Из-за первого пункта в требованиях выше отпадает вариант с использованием Command Line Build Step-ов в TC, потому что:

  1. Сложную логику писать на этом сложно (хотя и возможно);
  2. Специалистов, знающих bash/cmd/powershell, мало;
  3. Это не версионируется;
  4. Один и тот же код на Windows и на Linux агентах не запустить.


Поэтому мы решили написать maven-plugin, который бы запускался maven-runner-ом. Собранную версию сохранили в бинарном хранилище, откуда она скачивалась прямо в процессе сборки. Можно было каждый раз собирать его прямо при сборке, но это заметно увеличило бы время работы сборки, и кроме того, создало бы дополнительную зависимость от отдельного VCS-root, что привело бы к лишним сборкам.

Как вариант, можно делать NuGet-пакет с нужным exe-файлом, скачивать его с приватного NuGet-сервера и запускать. Хотя в нашем случае из-за Linux-серверов вариант с .NET-программами оказался недоступным, но в другом проекте подобный подход хорошо показал себя.


Теперь о тиражировании на большое количество build-конфигураций. Есть два способа:

  1. Build template. От него можно наследовать нашу сборку, и таким образом изменять в одном месте различные параметры/шаги/свойства.
  2. Meta-Runner. Мимикрирует под runner, никак не отображается в сборке.


Build template в нашем случае не очень подходит, так как сборки, в которых мы хотим его использовать, уже наследуются от своих build template. Также в этом случае в шагах/свойствах появляется много нерелевантных текущей сборке подробностей.

Таким образом, возможная техническая реализация выглядит так:

  1. Создается отдельный репозиторий, где хранится код нашего плагина.
  2. Плагин собирается отдельной сборкой и выкладывается в хранилище бинарных артефактов (Nexus или Artifactory).
  3. Для целевых сборок неким креативным способом запускаем этот плагин.
  4. Всё это оформляем как meta-runner.


Простейший maven-plugin


Начнем с того, что создадим простейший maven-plugin с названием «com.db.meteor: jira-commenter». Для этого наследуем AbstractMojo, вот так:

@Mojo( name = "stampJira", requiresProject = false)
public class MainMojo extends AbstractMojo {
    @Parameter( property = "jiraCommenter.branch")
    public String branchName;

    public void execute() throws MojoExecutionException{
        getLog().info(branchName);
    }
}


Тут же приведен пример передачи параметра из mvn. Также в нашем pom.xml указываем, как это собирать, используя maven-plugin-plugin:

    
        org.apache.maven.plugins
        maven-plugin-plugin
        3.2
        
            
            >trueskipErrorNoDescriptorsFound>
        

        
            
                mojo-descriptor
                
                    descriptor
                
            
        
    


Плагин готов. Теперь сохраним изменения в наш VCS и сформируем отдельную сборку, которая сделает mvn: deploy. Это несложно: нужен единственный build step.

8ceca60335afefb190a4bb3fe4c4e462.png

Теперь у нас есть отдельная сборка, которая будет собирать и выкладывать наш maven-plugin в локальный nexus (или artifactory, в зависимости от того,  что вы используете для бинарных артефактов).

Запуск на TeamCity


Теперь запустим этот плагин на TeamCity, чтобы убедиться, что идем в правильном направлении. Для этого сделаем отдельную сборку, в которую не будем подключать никаких VCS-root-ов и добавим единственный шаг — запуск maven, в котором в goals укажем наш плагин и передадим наш параметр:

0ea2b110a6ce119b9cf7d2322c2d46f6.png

Так при запуске maven сам скачает из нужного места наш плагин, положит в локальный кэш и запустит указанное mojo (в нашем случае — stampJira).

В Maven 2 как версию еще можно было указать LATEST, но с третьей версии приходится указывать точную версию. Запустив сборку, убедимся, что наш плагин скачивается и выполняется:

xphtmg502_l875zdfhslfw4jcj4.png

Передавать параметры через maven неудобно, но, к счастью, существует альтернатива. У TeamCity есть REST API. Сам REST API достаточно мощный и позволяет узнавать почти всё о сборках, агентах и т.п. Детально останавливаться на нем я не буду, для этого есть отличная подробная документация.

Я использовал получение информации о текущем статусе сборки и о проблемах, которые возникли (тесты/еще что-то/build output). Во время работы сборки ее статус будет RUNNING или FAILING, исходя из этого мы и будем определять, успешная сборка или нет.

Для доступа к API нужны логин и пароль. Не используйте свои собственные, так как при старте сборки генерируются одноразовый логин и пароль, которые доступны через параметр teamcity:

4gl__f3hnbbnmrgsaooud7joa_o.png

Еще понадобятся id сборки, которые передадим аналогичным образом.

Теперь стоит интегрировать наш плагин с Jira, чтобы ходить туда и обновлять нужные задачи. Не будем подробно здесь останавливаться, так как это несколько выходит за рамки статьи. Мы использовали для этого библиотеку com.atlassian.jira: jira-rest-java-client, на stackoverflow много примеров ее использования.

Extract meta-runner


Покажу на примере, как создается meta-runner. Сначала надо найти редко используемый пункт меню и придумать название для нового meta-runner-а.

64adf35c9ffadbbb833022adada813b7.png

После извлечения мы окажемся на вкладке с meta-runner-ами проекта. Там можно будет его редактировать и обновлять, если нужно:

fpdg7b4iz1tsuudauciirqxqitu.png

Технически meta-runner — это xml-описание шага (шагов) для выполнения, и он доступен так же, как и любой другой build step. У меня, например, получился такой:



  Temporary for article
  
    
      
      
    
    
      
        
          
          
          
          
          
          
          
          
          
          
          
        
      
    
    
  

При желании можно написать такой XML самому, но получить начальный из сборки проще. Редактировать же его можно прямо здесь изменением XML.  Мы, например, меняем так версию сборки.

Теперь возможно в любой сборке в текущем проекте добавить новый buildstep:

ee2aff725bde83c43f488a6cb02050e0.png

Причем параметры, которые использовались в тестовой сборке, теперь доступны для заполнения в нашем build step, например, teamcity.build.branch:

b347827ea982da4bfb02a54f954bd70f.png

Отлично, теперь мы можем попросить наших коллег и всех заинтересованных добавить себе в сборки этот шаг и радоваться жизни.

Замечание: после извлечения meta-runner-a он никак не синхронизируется с тем проектом, откуда его извлекли. Поэтому если хотите что-то поменять — меняйте в нем.

Run always?


Итак, теперь при успешной сборке будет выполняться наш код. А если сборка не прошла? В advanced options существует полезная опция: «когда выполнять этот шаг»:

41af02594c4e09dd684998c6b8c446f8.png

Тут выбирается подходящее условие выполнения. Для текущей задачи поставим «Even if some of the previous steps failed». 

Вот так удалось сделать счастливее наших QA-инженеров — теперь после каждого merge request в master или release ветки в соответствующей задаче в JIRA пишется подробный комментарий о том, что поменялось и что разворачивать для тестирования.

© Habrahabr.ru