В продолжение поста Jenkins: добавление комментария в Jira-тикет после билда — напишем свой костыль, который будет добавлять комментарии в Jira-тикеты.
Скрипт будет парсить заголовок коммита, в котором будет указан Jira-тикет, а потом через Jira API добавлять комментарий.
Писать будем на Python — полгода не писал на нём, наконец-то появился повод.
Содержание
Парсинг git-коммита
Для того, что бы получить ID тикета — напишем функцию, которая использует модуль gitpython.
Устанавливаем python-gitpython:
[simterm]
$ sudo pacman -S python-gitpython
[/simterm]
Проверяем.
Сначала получим последний коммит:
import os
from git import Repo
def parse_ticket_id():
repo = Repo('/home/setevoy/Work/devops/')
c = repo.commit()
print(c)
print(c.summary)
Запускаем:
[simterm]
$ ./add_jira_comment.py 662488948be7e4511d7f0db366a5af9ab65b04cd cloudwatch role disabled
[/simterm]
ОК, текст коммита есть — «cloudwatch role disabled», предыдущий коммит.
Теперь добавим тестовый коммит, в который включим тикет:
[simterm]
$ 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
[/simterm]
Обновляем скрипт — добавим параметр 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')
И проверяем ещё раз:
[simterm]
$ ./add_jira_comment.py dca0163ba7d33ca07241c78e32d90af7ab45a9c5 [BMEDIOS-198] Jira comment script
[/simterm]
Хорошо, это работает.
Теперь надо из полученного текста вытянуть сам номер тикета.
Добавляем парсинг — используем модуль 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')
Проверяем:
[simterm]
$ ./add_jira_comment.py BMEDIOS-198
[/simterm]
Тоже хорошо.
Но — в комментарии может быть несколько Jira-тикетов, разделённых запятыми — и комментарий надо будет добавлять ко всем.
Добавим ещё один тестовый коммит:
[simterm]
$ 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(-)
[/simterm]
Проверяем:
[simterm]
$ ./add_jira_comment.py BMEDIOS-198, BMEDIOS-198
[/simterm]
Хорошо, но лучше создать 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(','))
Проверяем:
[simterm]
$ ./add_jira_comment.py ['BMEDIOS-198', ' BMEDIOS-198']
[/simterm]
Отлично. теперь можно добавить 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)
Для начала посмотрим как срабатывает список тикетов:
[simterm]
$ ./add_jira_comment.py BMEDIOS-198 BMEDIOS-198
[/simterm]
Ага… Перед вторым номером пробел (тут плагин его вырезает, но он есть), т.к. в комментарии список тикетов добавлен через пробел.
Можно было бы договориться с девелоперами, что они будут добавлять номера без пробелов — но 100% кто-то забудет.
Вырезаем пробел — используем strip():
...
def add_comment(tickets_ids):
for ticket in tickets_ids:
print(ticket.strip())
Проверяем:
[simterm]
$ ./add_jira_comment.py BMEDIOS-198 BMEDIOS-198
[/simterm]
ОК, тут всё работает.
Теперь можно добавить добавление комментария.
...
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()для авторизации
Проверяем:
[simterm]
$ ./add_jira_comment.py 201 201
[/simterm]
И проверяем тикет:
Работает.
Jenkins job
Теперь можно начинать тестить на Jenkins.
В тестовую джобу добавляем параметры:
JIRA_ISSUE_URLJIRA_USERJIRA_PASS
Тип задачи в Jenkins — Freestyle project.
Имя бранча в скрипте теперь не надо — его зададим в настройках билда:
Проверяем:
ОК, только надо будет вырезать origin из имени.
Второе — надо изменить путь к каталогу репозитория, сейчас он задан явно:
...
def parse_ticket_id(branch):
repo = Repo('/home/setevoy/Work/devops/')
...
Скрипт лежит в каталоге tools каталога /home/setevoy/Work/devops/:
[simterm]
$ ls -l ~/Work/devops/tools/ total 4 -rwxr-xr-x 1 setevoy setevoy 978 Sep 25 12:52 add_jira_comment.py
[/simterm]
Добавляем в скрипт определение текущего каталога и берём на один уровень выше, что бы «выйти» из каталога 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) и вызов скрипта:
Проверяем:
И комментарии к тикету:
Готово.






