Автоматизация HotFix в Maven проектах с использованием TeamCity

    Я из компании Luxoft.
    В этом посте будет описана настройка автоматизации HotFix в Maven проектах с использованием Teamcity.


    Чтобы сделать HotFix обычно делается много ручных действий:


    1. Создать бранч для релиза, на который вы хотите выкатывать HotFix
    2. Исправить ошибку в релизе
    3. Измененить bugfix версию в релизном бранче
    4. Выкатить тег bugfix версии

    Пункты 1,3,4 можно автоматизировать.


    Перед тем как перейдем к теме, хочется затронуть важную и сложную тему — версионирования программного обеспечения. Кратко о Semver можно понять на этом скриншоте.


    Подробнее можно прочитать по ссылке: 1.


    Все настройки описанные в этом посте опираются на Semver и Trunk-Based Development.


    В Trunk-Based Development для каждого релиза нужно создать свой бранч. Все изменения (hotfix) в рамках этого релиза коммитятся в этот бранч.


    В рамках этого поста автоматизируем следующие вещи:


    • CI сборка


    • Создание нового релиза


    • Создание бранча для релиза


    • Изменение bugfix версии




    Требования:


    • Git репозиторий для хранения вашего кода. В посте будет использоваться репозиторий https://gitlab.com/anton_patsev/automation-maven-hotfix.
    • Teamcity сервер и агент. Вы можете поднять свой локальный Teamcity сервер и агент с помощью docker-compose
    • Там где у вас Teamcity агент, должны быть установлены java, maven, git

    Создадим в Teamcity проект "Automation Maven Hotfix" и создадим там 4 таски.


    • CI Build (CI сборка)


    • Create branch for release (Создание бранча для релиза)


    • Maven increment bugfix (Изменение bugfix версии))


    • Maven release (Создание нового релиза)



    Скриншот проекта:



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


    Во всех тасках необходимо выставить галку "Clean build: Delete all files in the checkout directory before the build", так как при отстутствии этой галки у меня появлялись ошибки.


    Создаем единственный VCS. Особенности VCS обведенны красным.



    Обычно VCS испольуют схему HTTPS. В Branch specification: указано смотреть все бранчи и все теги:


    +:refs/heads/*
    +:refs/tags/*

    Необходимо создать 4 Configuration Parameters.


    • BRANCH_FOR_INCREMENT
    • TAG_FROM_VERSION
    • TEAM_USER
    • TEAM_USER_EMAIL

    Поле value в BRANCH_FOR_INCREMENT и TAG_FROM_VERSION нужно оставить пустым.



    Необходимо закачать/добавить приватный ключ. Во всех тасках кроме CI Build необходим приватный ключ.



    В каждой таске кроме CI Build в разделе Build Features нужно подключить приватный ключ.


    Пример для Maven release



    CI Build**.


    В таске CI Build всего лишь один шаг mvn clean test



    Maven release


    В таске Maven release 2 шага. Первый шаг проверяет что бранч это master. Если бранч не master, то таска падает.


    BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
    echo "$BRANCH"
    if [[ "$BRANCH" != "master" ]]; then
      echo 'Branch is not master';
      echo 'Aborting';
      exit 1;
    fi


    Второй шаг это стандартный mvn release:prepare c опцией --batch-mode



    Create branch for release


    Чтобы создать hotfix для релиза нужно создать бранч. Этим занимается таска Create branch for release. У нее 2 шага.


    Первый шаг проверяет что бранч не master, и второе проверяет что версия в файле pom.xml не содержало слово SNAPSHOT


    BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
    echo "$BRANCH"
    if [[ "$BRANCH" == "master" ]]; then
      echo 'Branch is master';
      echo 'Aborting';
      exit 1;
    fi
    
    echo "Get version package from pom.xml"
    version=`python -c "import xml.etree.ElementTree as ET; print(ET.parse(open('pom.xml')).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)"`
    
    echo "Check SNAPSHOT"
    if [[ $version == "*SNAPSHOT*" ]]; then
        echo "******************* W A R N I N G *************************"
        echo "************ You are create branch for SNAPSHOTS ******************"
        echo "***********************************************************"
        exit 1
    fi


    Второй шаг изменяет в developerConnection схему подключения с HTTPS на GIT.


    # Здесь получаем developerConnection из файла pom.xml
    developerConnection=$(xmllint -xpath "/*[local-name() = 'project' ]//*[local-name() = 'developerConnection']/text()" pom.xml | sed  's|scm:git:ssh://||')
    echo developerConnection
    echo $developerConnection
    # Здесь меняем / на : в URL для git_remote_url
    git_remote_url=$(echo $developerConnection| sed 's/gitlab.com\//gitlab.com:/g')
    echo git_remote_url
    echo $git_remote_url
    
    git remote set-url origin $git_remote_url
    
    # Если вы не используете ввстроенную возможность Teamcity получения user и email из ~/.gitconfig, то можно указать их здесь
    echo 'git config user.name %TEAM_USER%'
    git config user.name %TEAM_USER%
    echo 'git config user.email %TEAM_USER_EMAIL%'
    git config user.email %TEAM_USER_EMAIL%
    
    # Здесь получаем версию из файла pom.xml
    echo "Get version package from pom.xml"
    version=`python -c "import xml.etree.ElementTree as ET; print(ET.parse(open('pom.xml')).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)"`
    echo $version
    
    # Почему-то без fetch выдавало ошибку.
    git fetch
    
    if [ `git branch -a | egrep "${version}$"` ]
    then
        echo "Branch exists"
        exit 1
    fi
    
    # Создаем бранч той версии, который был в файле pom.xml
    echo "Create branch"
    git checkout -b $version
    
    # Чистый git всегда предлагает настроить политику отправки.
    git config --global push.default simple
    
    # Пушим в ветку совпадающую с версией в pom.xml
    echo "Push release branch"
    git push --set-upstream origin $version


    Maven increment bugfix


    Таска состоит из 6 частей. Можно было отрефакторить, но и так работает.


    Первый шаг — проверка что бранч не master. Если бранч master таска падает.


    BRANCH=$(git branch | grep \* | cut -d ' ' -f2)
    echo "$BRANCH"
    if [[ "$BRANCH" == "master" ]]; then
      echo 'Branch is master';
      echo 'Aborting';
      exit 1;
    fi
    
    # Здесь получаем версию из файла pom.xml
    echo "Get version package from pom.xml"
    BRANCH=`python -c "import xml.etree.ElementTree as ET; print(ET.parse(open('pom.xml')).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)"`
    # Приходится делать checkout на нужный бранч.
    # Иначе git status показывает detached к нужному бранчу.
    # Нужно чтобы git status показывал просто бранч
    git checkout $BRANCH
    # Экспортируем переменную bash в переменную Teamcity для дальнейшего использования.
    echo "##teamcity[setParameter name='BRANCH_FOR_INCREMENT' value='$BRANCH']"


    Второй Maven шаг изменение bugfix версии в файле pom.xml.


    Goals: у maven все одной строкой


    build-helper:parse-version versions:set -DnewVersion=${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion} versions:commit


    Третий шаг — вывод информации Git status и другие:


    echo 'cat pom.xml'
    cat pom.xml
    echo 'git status'
    git status
    echo 'git remote -v'
    git remote -v
    echo 'git branch'
    git branch


    Четвертый шаг изменяет в developerConnection схему подключения с HTTPS на GIT.


    И пушит изменения в ветку, указанную в Teamcity переменной %BRANCH_FOR_INCREMENT%


    # Здесь получаем developerConnection из файла pom.xml
    developerConnection=$(xmllint -xpath "/*[local-name() = 'project' ]//*[local-name() = 'developerConnection']/text()" pom.xml | sed  's|scm:git:ssh://||')
    echo developerConnection
    # Здесь меняем / на : в URL для git_remote_url
    git_remote_url=$(echo $developerConnection| sed 's/gitlab.com\//gitlab.com:/g')
    echo git_remote_url
    echo $git_remote_url
    
    git remote set-url origin $git_remote_url
    
    # Если вы не используете ввстроенную возможность Teamcity получения user и email из ~/.gitconfig, то можно указать их здесь
    echo 'git config user.name %TEAM_USER%'
    git config user.name %TEAM_USER%
    echo 'git config user.email %TEAM_USER_EMAIL%'
    git config user.email %TEAM_USER_EMAIL%
    echo 'git add .'
    git add .
    echo 'git commit -m "Increment bugfix"'
    git commit -m "Increment bugfix"
    
    git push --set-upstream origin %BRANCH_FOR_INCREMENT%


    Пятый шаг получает из файла pom.xml версию и устанавливает ее в Teamcity переменную TAG_FROM_VERSION. Заметьте что версия из файла pom.xml без буквы v впереди. А тег, на основе этой версии уже с буквой v вначале.


    echo "Get version package from pom.xml"
    VERSION_AFTER_CHANGE=`python -c "import xml.etree.ElementTree as ET; print(ET.parse(open('pom.xml')).getroot().find('{http://maven.apache.org/POM/4.0.0}version').text)"`
    echo $VERSION_AFTER_CHANGE
    echo "##teamcity[setParameter name='TAG_FROM_VERSION' value='v$VERSION_AFTER_CHANGE']"


    Шестой шаг — тегирование bugfix версии. Делается это с помощью Maven с нужной опцией в Goal.


    Опция Goals:


    -Dtag=%TAG_FROM_VERSION% scm:tag

    Комментарии 6

      0
      Если вы, в 2020 году, все еще пользуетесь release plugin, мне кажется именно это — ваша проблема. Возможно не самая большая, но проблема.
        0
        Здравствуйте. Можете рассказать поподробнее?
          0
          это 2013 год был. Но на самом деле это лишь часть темы. Возможно я ошибаюсь, но большую часть того, что вы тут описали, делает один из многих плагинов для реализации gitflow.
            0
            Если вы можете написать пост о том, как можно сделать иначе с помощью плагинов, сообщество будем вам благодарно.
              0
              Про gitflow и плагины для его реализации написано куча текста. Я могу поискать еще ссылки, но уж переводить это — увольте. Да там в общем все несложно идеологически-то, если уж быть откровенным. Вы вот практически тоже самое в итоге придумали — просто свой велосипед реализовали, и у меня скажем вопросы в основном по реализации, а идея-то сама вполне норм.

              Ну вот например: github.com/aleksandr-m/gitflow-maven-plugin
                0

                Вы можете поискать статьи по использованию таких плагинов?
                Спасибо.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое