В продолжение поста 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_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/
:
[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) и вызов скрипта:
Проверяем:
И комментарии к тикету:
Готово.