总体思路: 1、配置django URL、View、Model、Serializer 2、编写工厂函数,处理数据逻辑 3、配置Jira webhook 1、配置django 1.1 router配置 # 1. router配置 path ( 'pm/issues/' , views . JiraView . as_view ()), #
总体思路:
1、配置django URL、View、Model、Serializer
2、编写工厂函数,处理数据逻辑
3、配置Jira webhook
1、配置django
1.1 router配置
# 1. router配置path('pm/issues/', views.JiraView.as_view()), # jira
1.2 View配置
# Jira dataclass JiraView(views.APIView):
def __init__(self):
self.logger = logging.getLogger("cmweb")
self.resp_msg = ResponseMsg()
self.permission_classes = []
def post(self, request):
data = request.data
# receive from jira webhook and handle
webhookEvent = data['webhookEvent']
issue_event_type_name = data['issue_event_type_name']
if webhookEvent == "jira:issue_created":
NewIssueCreate().handleIssue(data)
elif webhookEvent == "jira:issue_updated":
if "comment" not in issue_event_type_name:
NewIssueUpdate().handleIssue(data)
elif webhookEvent == "jira:issue_deleted":
NewIssueDelete().handleIssue(data)
else:
pass
return JsonResponse(self.resp_msg.ok_withmsg("ok"))
1.3 Model(cmapp/models.py)
1.4 Serializers(cmapp/serializers.py)
2、编写工厂函数
2.1 Factory.py
import abcfrom subscribe.jira.issue_create import parseIssueCreate
from subscribe.jira.issue_update import parseIssueUpdate, parseIssueDelete
class AbstractFactory(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def handleIssue(self, data):
pass
class NewIssueCreate(AbstractFactory):
def handleIssue(self, data):
parseIssueCreate(data)
class NewIssueUpdate(AbstractFactory):
def handleIssue(self, data):
parseIssueUpdate(data)
class NewIssueDelete(AbstractFactory):
def handleIssue(self, data):
parseIssueDelete(data)
2.2 issue_create.py
import jsonimport datetime
from subscribe.jira.sync_to_db import create_issue_to_db
import logging
logger = logging.getLogger("subscribe")
def parseIssueCreate(data):
components_list = []
issue = data['issue']
labels = issue['fields']['labels']
resolution = None if issue['fields']['resolution'] is None else issue['fields']['resolution']['name']
issue_id = issue['id']
issue_name = issue['key']
issue_type = issue['fields']['issuetype']['name']
project = issue['fields']['project']['name']
summary = issue['fields']['summary']
status = issue['fields']['status']['name']
priority = issue['fields']['priority']['name']
reporter = issue['fields']['reporter']['displayName']
assignee = '' if not issue['fields']['assignee'] else issue['fields']['assignee']['displayName']
description = '' if not issue['fields'].get('description') else issue['fields']['description']
resolved_date = issue['fields']['resolutiondate']
close_date = issue['fields']['customfield_11231']
plan_start_date = issue['fields']['customfield_10421']
plan_end_date = issue['fields']['customfield_10422']
act_start_date = issue['fields']['customfield_10423']
act_end_date = issue['fields']['customfield_10424']
due_date = issue['fields']['duedate']
estimate_due_date = issue['fields']['customfield_10933']
comp_lists = issue['fields']['components']
platform = ''
if issue['fields']['customfield_11301']:
platform = issue['fields']['customfield_11301']['value']
milestone_flag = ''
if issue['fields']['customfield_11118']:
milestone_flag = issue['fields']['customfield_11118']['value']
for component in comp_lists:
components_list.append(component['name'])
if issue['fields']['issuetype']['name'] == "Bug" and issue['fields']['customfield_10603'] is not None:
reproduce_radio = issue['fields']['customfield_10603']['value']
else:
reproduce_radio = None
create_date = issue['fields']['created']
update_date = issue['fields']['updated']
# change to Asia/Shanghai time format
up_tmp_date = datetime.datetime.strptime(update_date, "%Y-%m-%dT%H:%M:%S.%f+0800")
update_date = datetime.datetime.strftime(up_tmp_date, "%Y-%m-%d %H:%M:%S")
cr_tmp_date = datetime.datetime.strptime(create_date, "%Y-%m-%dT%H:%M:%S.%f+0800")
create_date = datetime.datetime.strftime(cr_tmp_date, "%Y-%m-%d %H:%M:%S")
if resolved_date is not None:
rs_tmp_date = datetime.datetime.strptime(resolved_date, "%Y-%m-%dT%H:%M:%S.%f+0800")
resolved_date = datetime.datetime.strftime(rs_tmp_date, "%Y-%m-%d %H:%M:%S")
combine_res = {
"issue_name": issue_name,
"issue_type": issue_type,
"project": project,
"summary": summary,
"status": status,
"priority": priority,
"reporter": reporter,
"assignee": assignee,
"description": description,
"create_date": create_date,
"update_date": update_date,
"issue_id": issue_id,
"resolved_date": resolved_date,
"close_date": close_date,
"plan_start_date": plan_start_date,
"plan_end_date": plan_end_date,
"act_start_date": act_start_date,
"act_end_date": act_end_date,
"due_date": due_date,
"estimate_due_date": estimate_due_date,
"components": json.dumps(components_list),
"platform": platform,
"milestone_flag": milestone_flag,
"reproduce_radio": reproduce_radio,
"labels": json.dumps(labels),
"resolution": resolution
}
logger.info("prehandle create data %s" % combine_res)
create_issue_to_db(combine_res)
2.3 issue_update.py
from subscribe.jira.sync_to_db import update_issue_to_db, delete_issue_from_dbimport logging
logger = logging.getLogger("subscribe")
def parseIssueUpdate(data):
"""
创建时间 created
更新时间 updated
计划开始时间 customfield_10421
计划结束时间 customfield_10422
实际开始时间 customfield_10423
实际结束时间 customfield_10424
解决时间 resolutiondate
关闭时间 customfield_10939
截止时间 duedate
预估截止时间 customfield_10933
"""
fmap = {
"issue_name": "issue_name",
"issue_type": "issue_type",
"project": "project",
"summary": "summary",
"status": "status",
"priority": "priority",
"reporter": "reporter",
"assignee": "assignee",
"description": "description",
"Created": "create_date",
"Updated": "update_date",
"Resolved": "resolved_date",
"Close Date": "close_date",
"Planned Start Date": "plan_start_date",
"Planned End Date": "plan_end_date",
"Actual Start Date": "act_start_date",
"Actual End Date": "act_end_date",
"Due": "due_date",
"Estimated Due Date": "estimate_due_date",
"components": "components",
"platform": "platform",
"milestone_flag": "milestone_flag",
"reproduce_radio": "reproduce_radio",
"labels": "labels",
"resolution": "resolution"
}
datefield = ["Close Date", "Planned Start Date", "Planned End Date", "Actual Start Date", "Actual End Date", "Due", "Estimated Due Date"]
supfield = list(fmap.keys())
predata = {
"issue_name": "",
"issue_type": "",
"project": "",
"summary": "",
"status": "",
"priority": "",
"reporter": "",
"assignee": "",
"description": "",
"create_date": "",
"update_date": "",
"issue_id": "",
"resolved_date": "",
"close_date": "",
"plan_start_date": "",
"plan_end_date": "",
"act_start_date": "",
"act_end_date": "",
"due_date": "",
"estimate_due_date": "",
"components": "",
"platform": "",
"milestone_flag": "",
"reproduce_radio": "",
"labels": "",
"resolution": ""
}
issue = data['issue']
predata['issue_name'] = issue['key']
changelog = data['changelog']
items = changelog['items']
for item in items:
if item['field'] in supfield:
logger.info(item['field'])
if item['field'] == "status":
if item['toString'] != "Integrated":
predata[fmap[item['field']]] = item['toString'].upper()
else:
predata[fmap[item['field']]] = item['toString']
elif item['field'] in datefield:
if item['toString'] == "":
predata[fmap[item['field']]] = None
else:
predata[fmap[item['field']]] = item['toString'].split(" ")[0]
else:
if item['toString'] is None:
predata[fmap[item['field']]] = ""
else:
predata[fmap[item['field']]] = item['toString']
update_issue_to_db(predata)
def parseIssueDelete(data):
issue = data['issue']
issue_name = issue['key']
delete_issue_from_db(issue_name)
2.4 sync_to_db.py
from cmapp.models import Jiraimport logging
from cmapp.serializers import JiraSerializer
logger = logging.getLogger("subscribe")
def create_issue_to_db(data):
jira_serial = JiraSerializer(data=data)
if jira_serial.is_valid():
jira_serial.save()
logger.info("create issue %s to db ok" % data['issue_name'])
else:
logger.error("create issue failed: %s" % jira_serial.errors)
def update_issue_to_db(data):
try:
updict = {}
hasvaluecount = 0
for k, v in data.items():
if v != "" and k != "issue_name":
updict[k] = v
hasvaluecount += 1
if hasvaluecount > 0:
logger.info("receive data %s" % data)
check_exist = Jira.objects.filter(issue_name=data['issue_name'])
if check_exist.exists():
check_exist.update(**updict)
logger.info("ok jira update %s" % updict)
else:
logger.warning("%s not exist" % data['issue_name'])
except Exception as e:
logger.error("error jira update: %s" % e)
def delete_issue_from_db(issue_name):
try:
Jira.objects.filter(issue_name=issue_name).delete()
logger.info("ok jira delete %s" % issue_name)
except Exception as e:
logger.error("error delete %s, : %s" % (issue_name, e))
3、配置Jira web-hook
jira管理员,system -> webhook ->新建URL指向:http://xxx.example.com/api/v1/pm/issues/
触发事件为:issue_created issue_updated