Python: скрипт добавления комментария в Jira из Jenkins

By | 09/25/2018
 

PythonВ продолжение поста Jenkins: добавление комментария в Jira-тикет после билда – напишем свой костыль, который будет добавлять комментарии в Jira-тикеты.

Скрипт будет парсить заголовок коммита, в котором будет указан Jira-тикет, а потом через Jira API добавлять комментарий.

Писать будем на Python – полгода не писал на нём, наконец-то появился повод.

Парсинг git-коммита

Для того, что бы получить ID тикета – напишем функцию, которая использует модуль gitpython.

Устанавливаем python-gitpython:

sudo pacman -S python-gitpython

Проверяем.

Сначала получим последний коммит:

import os

from git import Repo

def parse_ticket_id():

    repo = Repo('/home/setevoy/Work/devops/')
    c = repo.commit()
    print(c)
    print(c.summary)

Запускаем:

./add_jira_comment.py
662488948be7e4511d7f0db366a5af9ab65b04cd
cloudwatch role disabled

ОК, текст коммита есть – “cloudwatch role disabled”, предыдущий коммит.

Теперь добавим тестовый коммит, в который включим тикет:

git add -A && git commit -m "[BMEDIOS-198] Jira comment script"
[BMEDIOS-198_jenkins_config_Jira_plugin dca0163] [BMEDIOS-198] Jira comment script
1 file changed, 37 insertions(+)
create mode 100755 tools/add_jira_comment.py

Обновляем скрипт – добавим параметр branch для функции parse_ticket_id(), в котором передадим бранч, тут это “BMEDIOS-198_jenkins_config_Jira_plugin“:

def parse_ticket_id(branch):

    repo = Repo('/home/setevoy/Work/devops/')
    c = repo.commit(branch)

    print(c)
    print(c.summary)


parse_ticket_id('BMEDIOS-198_jenkins_config_Jira_plugin')

И проверяем ещё раз:

./add_jira_comment.py
dca0163ba7d33ca07241c78e32d90af7ab45a9c5
[BMEDIOS-198] Jira comment script

Хорошо, это работает.

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

Добавляем парсинг – используем модуль re, и в регулярном выражении получаем текст между квадратных скобок:

import re

from git import Repo

def parse_ticket_id(branch):

    repo = Repo('/home/setevoy/Work/devops/')
    c = repo.commit(branch)

    jira_ticket_id = re.search('\[(.*)\]', c.summary)
    print(jira_ticket_id.group(1))

parse_ticket_id('BMEDIOS-198_jenkins_config_Jira_plugin')

Проверяем:

./add_jira_comment.py
BMEDIOS-198

Тоже хорошо.

Но – в комментарии может быть несколько Jira-тикетов, разделённых запятыми – и комментарий надо будет добавлять ко всем.

Добавим ещё один тестовый коммит:

git add add_jira_comment.py && git commit -m "[BMEDIOS-198, BMEDIOS-198] parsing add"
[BMEDIOS-198_jenkins_config_Jira_plugin 53a3f03] [BMEDIOS-198, BMEDIOS-198] parsing add
1 file changed, 7 insertions(+), 6 deletions(-)

Проверяем:

./add_jira_comment.py
BMEDIOS-198, BMEDIOS-198

Хорошо, но лучше создать Python-список, который будет содержать элементы с ID тикетов – используем split() и разделитель по запятой:

def parse_ticket_id(branch):

    repo = Repo('/home/setevoy/Work/devops/')
    c = repo.commit(branch)

    jira_ticket_id = re.search('\[(.*)\]', c.summary)
    print(jira_ticket_id.group(1).split(','))

Проверяем:

./add_jira_comment.py
['BMEDIOS-198', ' BMEDIOS-198']

Отлично. теперь можно добавить return, и добавлять функцию, которая будет POST-ить комментарии:

...
def parse_ticket_id(branch):

    repo = Repo('/home/setevoy/Work/devops/')
    c = repo.commit(branch)

    jira_ticket_id = re.search('\[(.*)\]', c.summary)
    #print(jira_ticket_id.group(1).split(','))
    
    return(jira_ticket_id.group(1).split(','))

Добавление комментария в Jira

Добавляем новую функцию, используем requests:

import requests
from requests.auth import HTTPBasicAuth

# for testing, take fron Jenkins env later
JIRA_ISSUE_URL = "https://iteam.atlassian.net/rest/api/2/issue/"

JIRA_USER = 'user'
JIRA_PASS = 'pass'

...
def add_comment(tickets_ids):

    for ticket in tickets_ids:
        print(ticket)

tickets_ids_list = parse_ticket_id('BMEDIOS-198_jenkins_config_Jira_plugin')

add_comment(tickets_ids_list)

Для начала посмотрим как срабатывает список тикетов:

./add_jira_comment.py
BMEDIOS-198
BMEDIOS-198

Ага… Перед вторым номером пробел (тут плагин его вырезает, но он есть), т.к. в комментарии список тикетов добавлен через пробел.

Можно было бы договориться с девелоперами, что они будут добавлять номера без пробелов – но 100% кто-то забудет.

Вырезаем пробел – используем strip():

...
def add_comment(tickets_ids):

    for ticket in tickets_ids:
        print(ticket.strip())

Проверяем:

./add_jira_comment.py
BMEDIOS-198
BMEDIOS-198

ОК, тут всё работает.

Теперь можно добавить добавление комментария.

...
def add_comment(tickets_ids):

    for ticket in tickets_ids:
        #print(ticket.strip())

        r = requests.post(JIRA_ISSUE_URL + ticket.strip() + '/comment',
                      json={'body':'test ' + ticket.strip()},
                      headers={'content-type': 'application/json'},
                      auth=HTTPBasicAuth(JIRA_USER, JIRA_PASS)
                      )

        print(r.status_code, r.reason)

Тут вызываем метод requests.post(), которому передаём:

  • URL, который составлен из URL к Jira, ID тикета, к которому добавляем комментарий и в конце /comment
  • передаём данные json{}, для примера добавляем ID тикета
  • добавляем заголовок, в котором указываем, что тип данных json
  • и используем метод HTTPBasicAuth() для авторизации

Проверяем:

./add_jira_comment.py
201
201

И проверяем тикет:

Работает.

Jenkins job

Теперь можно начинать тестить на Jenkins.

В тестовую джобу добавляем параметры:

  • JIRA_ISSUE_URL
  • JIRA_USER
  • JIRA_PASS

Тип задачи в Jenkins – Freestyle project.

Имя бранча в скрипте теперь не надо – его зададим в настройках билда:

Проверяем:

ОК, только надо будет вырезать origin из имени.

Второе – надо изменить путь к каталогу репозитория, сейчас он задан явно:

...
def parse_ticket_id(branch):

    repo = Repo('/home/setevoy/Work/devops/')
...

Скрипт лежит в каталоге tools каталога /home/setevoy/Work/devops/:

ls -l ~/Work/devops/tools/
total 4
-rwxr-xr-x 1 setevoy setevoy 978 Sep 25 12:52 add_jira_comment.py

Добавляем в скрипт определение текущего каталога и берём на один уровень выше, что бы “выйти” из каталога tools в корень репозитория:

...
def parse_ticket_id():

    repo = Repo(os.path.join( os.path.dirname( __file__ ), '..' ))
...

Обновляем функцию add_comment() – добавляем получение значений для Jira из переменных окружения:

...
def add_comment(tickets_ids):

    jira_issue_url = os.environ['JIRA_ISSUE_URL']
    jira_user = os.environ['JIRA_USER']
    jira_pass = os.environ['JIRA_PASS']
...

Теперь весь скрипт выглядит так:

#!/usr/bin/env python

import os
import re

from git import Repo

import requests
from requests.auth import HTTPBasicAuth


def parse_ticket_id():

    repo = Repo(os.path.join( os.path.dirname( __file__ ), '..' ))

    c = repo.commit()

    jira_ticket_id = re.search('\[(.*)\]', c.summary)

    return(jira_ticket_id.group(1).split(','))


def add_comment(tickets_ids):

    jira_issue_url = os.environ['JIRA_ISSUE_URL']
    jira_user = os.environ['JIRA_USER']
    jira_pass = os.environ['JIRA_PASS']

    for ticket in tickets_ids:
        requests.post(jira_issue_url + ticket.strip() + '/comment',
                      json={'body':'test ' + ticket.strip()},
                      headers={'content-type': 'application/json'},
                      auth=HTTPBasicAuth(jira_user, jira_pass)
                      )

if __name__ == "__main__":

    add_comment(parse_ticket_id())

Обновляем задачу в Jenkins – добавляем установку пакетов (т.к. Jenkins запущен в Docker) и вызов скрипта:

Проверяем:

И комментарии к тикету:

Готово.