Python+Pyecharts+Pandas 实现分析Jira中的数据并生成图表
虽然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)
效果
作者: 是小鱼呀
出处:https://www.cnblogs.com/sophia12138/p/15814287.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!