雖然jira有現成的可視化圖表,但是用不習慣,所以自己寫了一個,方便每個sprint復盤時分析BUG情況
參考文章:https://blog.csdn.net/qq_36701194/article/details/103923356
思路:
- 利用python獲取jira中的BUG數據
- 按需求統計數據,並生成滿足圖表要求的數據格式
- 利用Pyecharts生成html
框架設計:
BugReport
- report 存放html測試報告
- jiraOperation.py 主要實現登錄jira、查詢jql、獲取需要的BUG數據生成dataframe、按需求統計BUG數據、返回滿足圖表要求的數據格式
- makeChart.py 主要實現可視化報表
- run.py 調用這兩個文件
jiraOperation.py
from jira import JIRA
import urllib3
import json
import pandas as pd
urllib3.disable_warnings()
"""
主要實現登錄jira、查詢jql、獲取需要的BUG字段生成dataframe、統計BUG
"""
class jiraOperation():
def loginJira(self, username, password):
"""
登錄jira
:return: jira
"""
options = {
'verify': False,
'server': 'url'} # 輸入jira的地址
jira = JIRA(options, basic_auth=(username, password))
return jira
def searchIssues(self, jira, jql, max_results=1000):
''' Search issues
@param jql: JQL, str
@param max_results: max results, int, default 100
@return issues: result, list
執行jql返回bug list
'''
try:
issues = jira.search_issues(jql, maxResults=max_results)
return issues
except Exception as e:
print(e)
def getIssuesfield(self, jira):
"""
獲取BUG的所有字段,包括自定義字段
:return:
"""
field = jira.fields()
for item in field:
print(json.dumps(item, ensure_ascii=False))
def getDataframe(self, jira_result):
"""
生成數據明細
:return:df
"""
key_list = []
summary_list = []
priority_list = []
severity_list = []
assignee_list = []
status_list = []
components_list = []
for issue in jira_result:
key = issue.key # BUG編號
summary = issue.fields.summary # BUG簡述
priority = issue.fields.priority # 優先級
customfield_10302 = issue.fields.customfield_10302 # 嚴重程度
assignee = issue.fields.assignee # 經辦人
status = issue.fields.status # 狀態
if issue.fields.components == []: # 如果BUG沒有綁定模塊,默認其他
components = '其他'
else:
components = str(issue.fields.components[0])
key_list.append(str(key))
summary_list.append(str(summary))
priority_list.append(str(priority))
severity_list.append(str(customfield_10302))
assignee_list.append(str(assignee))
status_list.append(str(status))
components_list.append(str(components))
ipl_data = dict(key=key_list, summary=summary_list, priority=priority_list, severity=severity_list,
assignee=assignee_list, status=status_list,
components=components_list) # 生成統計數據明細
df = pd.DataFrame(ipl_data)
return df
def count_status(self, df):
"""
BUG完成狀態統計
:param df:
:return: status_set
"""
status_set = {}
status_groupd = df.groupby("status")
for name, group in status_groupd:
count = group["status"].count()
status_set.setdefault(str(name), str(count))
return status_set
def count_statusAndassignee2(self, df):
"""
處理人完成BUG統計
可以實現根據人員分組並統計出每個人未解決和已解決的BUG數量
:param df:
:return: assignee_people_list, todo_list, done_list
"""
assignee_people_list = []
todo_list = []
done_list = []
for assignee, group in df.groupby('assignee'):
assignee_people_list.append(assignee)
status = group["status"]
status_list = list(status) # 輸出每個人所有狀態的數組
# 統計各個狀態在數組中出現的次數
todo = status_list.count('待辦')
progress = status_list.count('處理中')
resolved = status_list.count('已解決')
rejected = status_list.count('Rejected')
reopen = status_list.count('重新打開')
close = status_list.count('完成')
# 統計未解決和已解決的次數
todo_item = todo + progress + reopen
done_item = resolved + close + rejected
# 未解決和已解決輸出成數組
todo_list.append(todo_item)
done_list.append(done_item)
return assignee_people_list, todo_list, done_list
def count_components(self, df):
"""
各模塊BUG統計
:param df:
:return: components_set
"""
components_set = {}
components_groupd = df.groupby("components")
for name, group in components_groupd:
count = group["components"].count()
components_set.setdefault(str(name), str(count))
return components_set
def count_componentsAndseverity2(self, df):
"""
各模塊BUG嚴重等級統計
可以實現根據模塊統計,輸出每個模塊BUG嚴重等級的統計
:param df:
:return: components_list, deadly_list, serious_list, medium_list, low_list
"""
components_list = []
deadly_list = []
serious_list = []
medium_list = []
low_list = []
for components, group in df.groupby('components'):
components_list.append(components)
severity = group["severity"]
status_str = list(severity) # 輸出每個模塊所有嚴重等級的數組
# 統計各個嚴重等級在數組中出現的次數
deadly = status_str.count('致命')
serious = status_str.count('嚴重')
medium = status_str.count('中')
low = status_str.count('低')
# 每個嚴重等級輸出成數組
deadly_list.append(deadly)
serious_list.append(serious)
medium_list.append(medium)
low_list.append(low)
return components_list, deadly_list, serious_list, medium_list, low_list
def todo_bug(self, df):
"""
遺留BUG,待辦+處理中+重新打開
:param df:
:return: todo_bug_list
"""
# 獲得status列中值等於待辦、處理中、重新打開的行
todo_bug = df.query('status=="待辦"| status=="處理中"| status=="重新打開"')
todo_bug_list = (todo_bug.values).tolist() # 轉成列表
return todo_bug_list
makeChart.py
from pyecharts import options as opts
from pyecharts.charts import Bar, Pie, Tab, Page, Timeline, Line
from pyecharts.components import Table
from pyecharts.options import ComponentTitleOpts
import datetime
"""
主要實現生成圖表,一個圖表一個頁簽
"""
class chart():
def bugStatus_pie(self, custom_fields):
"""
餅圖-"BUG完成狀態統計
:param custom_fields:
:return:
"""
labels = "BUG完成狀態統計"
pie = (
Pie()
.add("2", [list(z) for z in zip(list(custom_fields.keys()), list(custom_fields.values()))],
radius=["40%", "70%"],
label_opts=opts.LabelOpts(
position="outside",
formatter="{b}:{c}\n{per|{d}%}",
background_color="#eee",
border_color="#aaa",
border_width=1,
border_radius=2,
rich={
"a": {"color": "#989", "lineHeight": '44%', "align": "center"},
"abg": {
"backgroundColor": "#e3e3e3",
"width": "30%",
"align": "right",
"height": 21,
"borderRadius": [0, 0, 0, 0],
},
"hr": {
"borderColor": "#aaa",
"width": "71%",
"borderWidth": 12,
"height": 12,
},
"b": {"fontSize": 15, "lineHeight": 10},
"per": {
"color": "#eee",
"backgroundColor": "#324456",
"padding": [0.5, 0.5],
"borderRadius": 1,
},
},
),
)
# .set_global_opts(title_opts=opts.TitleOpts(title="標題")) #小標題
.set_global_opts(legend_opts=opts.LegendOpts(pos_left='83%'),
title_opts=opts.TitleOpts(title="{}".format(labels)),
tooltip_opts=opts.TooltipOpts(is_show=False, ))
)
return pie
def statusAndassignee2_bar(self, statusAndassignee2):
"""
柱狀圖-處理人完成BUG統計
:param statusAndassignee2:
:return:
"""
# timeline_bar = Timeline().add_schema(is_auto_play=False, pos_top='7.5%', height='2%')
labels = "處理人完成BUG統計"
bar = (
Bar()
.add_xaxis(statusAndassignee2[0])
.add_yaxis("未解決", statusAndassignee2[1])
.add_yaxis("已解決", statusAndassignee2[2])
.set_global_opts(title_opts=opts.TitleOpts("{}".format(labels)),
xaxis_opts=opts.AxisOpts(name_rotate=30, axislabel_opts={"rotate": 30})))
return bar
def components_bar(self, components):
"""
柱狀圖-各模塊BUG統計
:param components:
:return:
"""
labels = "各模塊BUG統計"
bar = (
Bar()
.add_xaxis(list(components.keys()))
.add_yaxis("", list(components.values()))
.set_global_opts(title_opts=opts.TitleOpts("{}".format(labels)),
xaxis_opts=opts.AxisOpts(name_rotate=30, axislabel_opts={"rotate": 30})))
return bar
def componentsAndseverity2_bar(self, componentsAndseverity2):
"""
柱狀圖-各模塊BUG嚴重等級統計
:param componentsAndseverity2:
:return:
"""
labels = "各模塊BUG嚴重等級統計"
bar = (
Bar()
.add_xaxis(componentsAndseverity2[0])
.add_yaxis("致命", componentsAndseverity2[1])
.add_yaxis("嚴重", componentsAndseverity2[2])
.add_yaxis("中", componentsAndseverity2[3])
.add_yaxis("低", componentsAndseverity2[4])
.set_global_opts(title_opts=opts.TitleOpts("{}".format(labels)),
xaxis_opts=opts.AxisOpts(name_rotate=30, axislabel_opts={"rotate": 30})))
return bar
def bug_list(self, todo_bug_list):
"""
表單-BUG遺留清單
:param todo_bug_list:
:return:
"""
bugtable = (
Table()
.add(["jira號", '概要', '優先級', '嚴重程度', '經辦人', '狀態', '模塊'], todo_bug_list)
.set_global_opts(title_opts=ComponentTitleOpts(title="Bug遺留清單"))
)
return bugtable
def tab(self, bugStatus_pie, statusAndassignee2_bar, components_bar, componentsAndseverity2_bar, bugtable):
"""
一個Tab下添加多個圖表,並生成html文件
:param bugStatus_pie:
:param statusAndassignee2_bar:
:param components_bar:
:param componentsAndseverity2_bar:
:param bugtable:
:return:
"""
report_name = '測試報告'
tab = Tab()
tab.add(bugStatus_pie, "BUG完成狀態統計")
tab.add(statusAndassignee2_bar, "處理人完成BUG統計")
tab.add(components_bar, "各模塊BUG統計")
tab.add(componentsAndseverity2_bar, "各模塊BUG嚴重等級統計")
tab.add(bugtable, "BUG遺留清單")
time = datetime.datetime.now().strftime('%Y-%m-%d')
return tab.render('./report/' + str(report_name) + time + ".html")
run.py
from jira_bug.BugReport.jiraOperation import *
from jira_bug.BugReport.makeChart import *
username = "username" # jira賬號密碼
password = "password"
jql_ALL_BUG="""project = TES AND issuetype = Bug """ # sprint的jql,這里放了全部的BUG,可以按照需求調整
"""實例化jiraOperation類"""
report = jiraOperation()
jira = report.loginJira(username, password) # 登錄jira
jira_result = report.searchIssues(jira, jql_ALL_BUG) # 查詢jql
jira_result_df = report.getDataframe(jira_result) # 獲取BUG信息,輸出成DataFrame
"""執行jira數據的統計"""
count_status = report.count_status(jira_result_df) # 統計BUG狀態
count_statusAndassignee2 = report.count_statusAndassignee2(jira_result_df) # 統計處理人完成BUG情況
count_components = report.count_components(jira_result_df) # 統計每個模塊的BUG
count_componentsAndseverity2 = report.count_componentsAndseverity2(jira_result_df) # 統計每個模塊不同嚴重程度的BUG
todo_bug = report.todo_bug(jira_result_df) # 統計遺留BUG
"""實例化chart類"""
charts = chart()
bugStatus_pie = charts.bugStatus_pie(count_status) # 生成圖表--統計BUG狀態
statusAndassignee2_bar = charts.statusAndassignee2_bar(count_statusAndassignee2) # 生成圖表--統計處理人完成BUG情況
components_bar = charts.components_bar(count_components) # 生成圖表--統計每個模塊的BUG
componentsAndseverity2_bar = charts.componentsAndseverity2_bar(count_componentsAndseverity2) # 生成圖表--統計每個模塊不同嚴重程度的BUG
bug_list = charts.bug_list(todo_bug) # 生成圖表--統計遺留BUG
"""渲染出html,可在report文件下查看到生成的html文件"""
charts.tab(bugStatus_pie, statusAndassignee2_bar, components_bar, componentsAndseverity2_bar, bug_list)
效果


