程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

如何用 Python 統計 Jira 數據並可視化

編輯:Python

目前公司使用 Jira 作為項目管理工具,在每一次迭代完成後的復盤會上,我們都需要針對本次迭代的 Bug 進行數據統計,以幫助管理層能更直觀的了解研發的代碼質量

本篇文章將介紹如何利用統計 Jira 數據,並進行可視化

1. 准備
首先,安裝 Python 依賴庫

# 安裝依賴庫
pip3 install jira
pip3 install html-table
pip3 install pyecharts
pip3 install snapshot_selenium
復制代碼

其中

  • jira 使用 jsql 語法從在項目中獲取需要的數據
  • html-table 用於生成一個 HTML 格式的表格數據
  • pyecharts 和 snapshot_selenium 用於數據可視化

2. 實戰一下
下面我們通過 7 個步驟來實現上面的功能

2-1 登錄獲取客戶端連接對象

from jira import JIRA
class 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 類型,就能統計出所需要的數據並繪制成圖表

以上就是本次分享的所有內容,如果你覺得文章還不錯,歡迎關注公眾號:Python編程學習圈,每日干貨分享,內容覆蓋Python電子書、教程、數據庫編程、Django,爬蟲,雲計算等等。或是前往編程學習網,了解更多編程技術知識。


作者:編程學習網
鏈接:https://juejin.cn/post/7124196366288420901
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved