目前公司应用 Jira 作为项目管理工具,在每一次迭代实现后的复盘会上,咱们都须要针对本次迭代的 Bug 进行数据统计,以帮忙管理层能更直观的理解研发的代码品质

本篇文章将介绍如何利用统计 Jira 数据,并进行可视化

1. 筹备
首先,装置 Python 依赖库

# 装置依赖库pip3 install jirapip3 install html-tablepip3 install pyechartspip3 install snapshot_selenium

其中

  • jira 应用 jsql 语法从在我的项目中获取须要的数据
  • html-table 用于生成一个 HTML 格局的表格数据
  • pyecharts 和 snapshot_selenium 用于数据可视化

2. 实战一下
上面咱们通过 7 个步骤来实现下面的性能

2-1 登录获取客户端连贯对象

from jira import JIRAclass JiraObj(object):    def __init__(self, bug_style, project_type):        """        :param project_name        :param sprint: 迭代号码        :param bug_style: BUG状态        """        # Jira首页地址        self.server = 'https://jira.**.team'        # Jira登录账号信息        self.basic_auth = ('用户名', '明码')        # 创立一个客户端连贯信息        self.jiraClinet = JIRA(server=self.server, basic_auth=self.basic_auth)

2-2 依据我的项目类型获取看板 id

...        # 获取boards看板        # 所有看板信息        boards = [(item.id, item.name) for item in self.jiraClinet.boards()]        board_id = self.__get_board_id(boards, project_type)        print("看板id:", board_id)...    def __get_board_id(self, boards, project_type):        """        获取看板id        :param project_type:        :return:        """        board_id = 1        for item in boards:            if (project_type == PROJ_TYPE.Type1 and item[1] == 't1') or (                    project_type == PROJ_TYPE.Type2 and item[1] == 't2'):                board_id = item[0]                break        return board_id..

2-3 依据看板 id 获取迭代 id 及迭代名称

... # 获取我的项目Sprint,让用户进行抉择        sprints = self.jiraClinet.sprints(board_id=board_id)        for item in sprints:            if str(sprint_no) in item.name:                self.sprint_id = item.id                self.sprint_name = item.name                print(f"抉择Sprint,id:{self.sprint_id},name:{self.sprint_name}")                break...

2-4 依据我的项目名、Bug 类型、迭代 id 组成 jsql 语句,并查问数据

... def get_bug_status_jsql(self, bug_status: BUG_STATUS):        """        通过bug状态,获取jsql        :param bug_status:        :return:        """        status_jsql = ''        if bug_status == BUG_STATUS.ALL:            status_jsql = ' '        elif bug_status == BUG_STATUS.TO_VERIFY:            # 待验证(已解决)            status_jsql = ' AND status = 已解决 '        elif bug_status == BUG_STATUS.TO_FIXED:            # 待解决(关上、从新关上、解决中)            status_jsql = ' AND status in (关上, 从新关上, 解决中) '        elif bug_status == BUG_STATUS.CLOSED:            # 敞开            status_jsql = ' AND status = Closed '        elif bug_status == BUG_STATUS.TO_FIXED_CONTAIN_DELAY:            # 待解决(关上、从新关上、解决中、延期解决)            status_jsql = ' AND status in (关上, 延期解决, 从新关上, 解决中) '        return status_jsql...jql = f'project = {project_name} and issuetype = 故障  {self.get_bug_status_jsql(self.bug_style)} AND Sprint = {self.sprint_id} ORDER BY priority desc, updated DESC'        print(jql)        lists = self.get_issue_list(jql)...

2-5 生成本地 HTML 统计数据

须要留神的是,应用 a 标签组装的链接不能间接跳转,须要针对数据进行二次替换能力失常进行链接跳转

from HTMLTable import (    HTMLTable)... def gen_html_table(self, datas):        """        初始化表单款式        :return:        """        table = HTMLTable(caption=f'实时BUG统计【{self.project_name}】,一共{len(datas)}个')        # 表头行        table.append_header_rows((('ID', '状态', '优先级', '责任人', '终端', 'URL'),))        # 增加数据        table.append_data_rows(datas)        # 设置款式        table.caption.set_style({'font-size': '15px'})        # 其余款式设置        ...        # 替换数据,便于展现href地址        html = table.to_html().replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", '"')        with open(f"./output/{self.project_name}-bug_{current_time()}.html", 'w', encoding='utf-8') as file:            file.write(html)...# 生成本地文件的数据output_tuples = tuple([            (item.get("key"), item.get("status"), item.get("priority"), item.get('duty'), item.get('end_type'),             f'<a href="{item.get("url")}" target="_blank">点我查看</a>') for item in lists])# 生成本地HTML文件self.gen_html_table(output_tuples)..

2-6 数据统计

首先,这里按 Bug 责任人进行分组,而后按数目进行降序排列

而后,按 Bug 优先等级进行降序排列

最初,获取每一个端的 Bug 总数

...        # 2、统计每个人(按数目)        datas_by_count = {}        for item in lists:            datas_by_count[item.get("duty")] = datas_by_count.get(item.get("duty"), 0) + 1        # 降序排序        datas_by_count = sorted(datas_by_count.items(), key=lambda item: item[1], reverse=True)        # print("按Bug总数排序:", datas_by_count)        # 3、统计每个人(按优先级)        datas_by_priority = {}        for item in datas_by_count:            # 责任人            name = item[0]            # 5个优先级对应的数目            counts = self.get_assignee_count(lists, name)            datas_by_priority[name] = counts        # 排序(按优先级多条件降序排列)        datas_by_priority = sorted(datas_by_priority.items(),                                   key=lambda item: (item[1][0], item[1][1], item[1][2], item[1][3]), reverse=True)        # print("按Bug优先级排序:", datas_by_priority)        # 4、依据终端进行统计分类        keys, values = self.get_end_type_count(lists)...

2-7 可视化

针对下面的 3 组数据,应用 pyecharts 绘制成柱状图和饼状图

...      def draw_image(self, datas_by_count, datas_by_priority, keys, values):        """        绘制图片        :param values:        :param keys:        :param datas_by_count: 按bug总数排序后果        :param datas_by_priority: 按bug优先级排序后果        :return:        """        # 1、按BUG总数排序绘制        bar = (            Bar().set_global_opts(                title_opts=opts.TitleOpts(title=f"{self.project_name}", subtitle=f"{self.sprint_name}")))        bar.add_xaxis([item[0] for item in datas_by_count])        bar.add_yaxis(f"BUG总数", [item[1] for item in datas_by_count])        # render 会生成本地 HTML 文件,默认会在当前目录生成 render.html 文件        # 也能够传入门路参数,如 bar.render("mycharts.html")        # bar.render(path=f'{sprint_name}-BUG总数.html')        make_snapshot(snapshot, bar.render(), "./output/1.png")        # 2、按优先级排序绘制        bar2 = (            # Bar(init_opts=opts.InitOpts(theme=ThemeType.INFOGRAPHIC))            Bar()                .add_xaxis([item[0] for item in datas_by_priority])                .add_yaxis(self.__get_priority(BUG_PRIORITY.Highest), [item[1][0] for item in datas_by_priority],                           color='#6aa84f')                .add_yaxis(self.__get_priority(BUG_PRIORITY.High), [item[1][1] for item in datas_by_priority],                           color='#a2c4c9')                .add_yaxis(self.__get_priority(BUG_PRIORITY.Medium), [item[1][2] for item in datas_by_priority],                           color="#ff9900")                .add_yaxis(self.__get_priority(BUG_PRIORITY.Low), [item[1][3] for item in datas_by_priority],                           color="#ea9999")                .add_yaxis(self.__get_priority(BUG_PRIORITY.Lowest), [item[1][4] for item in datas_by_priority],                           color="#980000")                .set_global_opts(                title_opts=opts.TitleOpts(title=f"{self.project_name}", subtitle=f"{self.sprint_name}"))        )        # bar2.render(path=f'{sprint_name}-BUG优先级.html')        make_snapshot(snapshot, bar2.render(), "./output/2.png")        # 3、依据终端来绘制饼图        if len(keys) > 0 and len(values) > 0:            c = (                Pie()                    .add("", [list(z) for z in zip(keys, values)])                    .set_global_opts(title_opts=opts.TitleOpts(title="各端BUG散布"))                    .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))            )            make_snapshot(snapshot, c.render(), f"./output/{self.project_name}_end.png")        # 4、合并两张图片        self.concatenate_img(['./output/1.png', './output/2.png'], img_name=f'./output/{self.sprint_name}_bug.png',                             axis=1)...

3. 总结
通过下面的操作,每次只须要输出我的项目类型、迭代版本号、要统计的 Bug 类型,就能统计出所须要的数据并绘制成图表

最近整顿了几百 G 的 Python 学习材料,蕴含新手入门电子书、教程、源码等等,收费分享给大家!想要的返回 “Python 编程学习圈”,发送 “J” 即可收费取得