Python+Pyecharts+Pandas 实现分析Jira中的数据并生成图表


虽然jira有现成的可视化图表,但是用不习惯,所以自己写了一个,方便每个sprint复盘时分析BUG情况
参考文章:https://blog.csdn.net/qq_36701194/article/details/103923356

思路:

  1. 利用python获取jira中的BUG数据
  2. 按需求统计数据,并生成满足图表要求的数据格式
  3. 利用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)

效果


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM