利用Python統(tǒng)計(jì)Jira數(shù)據(jù)并可視化

    目錄

    大家好,我是安果!

    目前公司使用 Jira 作為項(xiàng)目管理工具,在每一次迭代完成后得復(fù)盤(pán)會(huì)上,我們都需要針對(duì)本次迭代得 Bug 進(jìn)行數(shù)據(jù)統(tǒng)計(jì),以幫助管理層能更直觀得了解研發(fā)得代碼質(zhì)量

    本篇內(nèi)容將介紹如何利用統(tǒng)計(jì) Jira 數(shù)據(jù),并進(jìn)行可視化

    1. 準(zhǔn)備

    首先,安裝 Python 依賴(lài)庫(kù)

    #?安裝依賴(lài)庫(kù)pip3?install?jirapip3?install?html-tablepip3?install?pyechartspip3?install?snapshot_selenium

    其中

    • jira 使用 jsql 語(yǔ)法從在項(xiàng)目中獲取需要得數(shù)據(jù)
    • html-table 用于生成一個(gè) HTML 格式得表格數(shù)據(jù)
    • pyecharts 和 snapshot_selenium 用于數(shù)據(jù)可視化

    2. 實(shí)戰(zhàn)一下

    下面我們通過(guò) 7 個(gè)步驟來(lái)實(shí)現(xiàn)上面得功能

    2-1 登錄獲取客戶端連接對(duì)象

    from?jira?import?JIRAclass?JiraObj(object):????def?__init__(self,?bug_style,?project_type):????????"""????????:param?project_name????????:param?sprint:?迭代號(hào)碼????????:param?bug_style:?BUG狀態(tài)????????"""????????#?Jira首頁(yè)地址????????self.server?=?'https://jira.**.team'????????#?Jira登錄賬號(hào)信息????????self.basic_auth?=?('用戶名',?'密碼')????????#?創(chuàng)建一個(gè)客戶端連接信息????????self.jiraClinet?=?JIRA(server=self.server,?basic_auth=self.basic_auth)

    2-2 根據(jù)項(xiàng)目類(lèi)型獲取看板 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 根據(jù)看板 id 獲取迭代 id 及迭代名稱(chēng)

    ...?#?獲取項(xiàng)目Sprint,讓用戶進(jìn)行選擇????????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  根據(jù)項(xiàng)目名、Bug 類(lèi)型、迭代 id 組成 jsql 語(yǔ)句,并查詢(xún)數(shù)據(jù)

    ...?def?get_bug_status_jsql(self,?bug_status:?BUG_STATUS):????????"""????????通過(guò)bug狀態(tài),獲取jsql????????:param?bug_status:????????:return:????????"""????????status_jsql?=?''????????if?bug_status?==?BUG_STATUS.ALL:????????????status_jsql?=?'?'????????elif?bug_status?==?BUG_STATUS.TO_VERIFY:????????????#?待驗(yàn)證(已解決)????????????status_jsql?=?'?AND?status?=?已解決?'????????elif?bug_status?==?BUG_STATUS.TO_FIXED:????????????#?待解決(打開(kāi)、重新打開(kāi)、處理中)????????????status_jsql?=?'?AND?status?in?(打開(kāi),?重新打開(kāi),?處理中)?'????????elif?bug_status?==?BUG_STATUS.CLOSED:????????????#?關(guān)閉????????????status_jsql?=?'?AND?status?=?Closed?'????????elif?bug_status?==?BUG_STATUS.TO_FIXED_CONTAIN_DELAY:????????????#?待解決(打開(kāi)、重新打開(kāi)、處理中、延期處理)????????????status_jsql?=?'?AND?status?in?(打開(kāi),?延期處理,?重新打開(kāi),?處理中)?'????????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 統(tǒng)計(jì)數(shù)據(jù)

    需要注意得是,使用 a 標(biāo)簽組裝得鏈接不能直接跳轉(zhuǎn),需要針對(duì)數(shù)據(jù)進(jìn)行二次替換才能正常進(jìn)行鏈接跳轉(zhuǎn) 

    from?HTMLTable?import?(????HTMLTable)...?def?gen_html_table(self,?datas):????????"""????????初始化表單樣式????????:return:????????"""????????table?=?HTMLTable(caption=f'實(shí)時(shí)BUG統(tǒng)計(jì)【{self.project_name}】,一共{len(datas)}個(gè)')????????#?表頭行????????table.append_header_rows((('ID',?'狀態(tài)',?'優(yōu)先級(jí)',?'責(zé)任人',?'終端',?'URL'),))????????#?添加數(shù)據(jù)????????table.append_data_rows(datas)????????#?設(shè)置樣式????????table.caption.set_style({'font-size':?'15px'})????????#?其他樣式設(shè)置????????...????????#?替換數(shù)據(jù),便于展示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)...#?生成本地文件得數(shù)據(jù)output_tuples?=?tuple([????????????(item.get("key"),?item.get("status"),?item.get("priority"),?item.get('duty'),?item.get('end_type'),?????????????f'<a?href="{item.get(" rel="external nofollow" url")}"?target="_blank">點(diǎn)我查看</a>')?for?item?in?lists])#?生成本地HTML文件self.gen_html_table(output_tuples)..

    2-6 數(shù)據(jù)統(tǒng)計(jì)

    首先,這里按 Bug 責(zé)任人進(jìn)行分組,然后按數(shù)目進(jìn)行降序排列

    然后,按 Bug 優(yōu)先等級(jí)進(jìn)行降序排列

    最后,獲取每一個(gè)端得 Bug 總數(shù)

    ...????????#?2、統(tǒng)計(jì)每個(gè)人(按數(shù)目)????????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總數(shù)排序:",?datas_by_count)????????#?3、統(tǒng)計(jì)每個(gè)人(按優(yōu)先級(jí))????????datas_by_priority?=?{}????????for?item?in?datas_by_count:????????????#?責(zé)任人????????????name?=?item[0]????????????#?5個(gè)優(yōu)先級(jí)對(duì)應(yīng)得數(shù)目????????????counts?=?self.get_assignee_count(lists,?name)????????????datas_by_priority[name]?=?counts????????#?排序(按優(yōu)先級(jí)多條件降序排列)????????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優(yōu)先級(jí)排序:",?datas_by_priority)????????#?4、根據(jù)終端進(jìn)行統(tǒng)計(jì)分類(lèi)????????keys,?values?=?self.get_end_type_count(lists)...

    2-7 可視化

    針對(duì)上面得 3 組數(shù)據(jù),使用 pyecharts 繪制成柱狀圖和餅狀圖

    ...??????def?draw_image(self,?datas_by_count,?datas_by_priority,?keys,?values):????????"""????????繪制圖片????????:param?values:????????:param?keys:????????:param?datas_by_count:?按bug總數(shù)排序結(jié)果????????:param?datas_by_priority:?按bug優(yōu)先級(jí)排序結(jié)果????????:return:????????"""????????#?1、按BUG總數(shù)排序繪制????????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總數(shù)",?[item[1]?for?item?in?datas_by_count])????????#?render?會(huì)生成本地?HTML?文件,默認(rèn)會(huì)在當(dāng)前目錄生成?render.html?文件????????#?也可以傳入路徑參數(shù),如?bar.render("mycharts.html")????????#?bar.render(path=f'{sprint_name}-BUG總數(shù).html')????????make_snapshot(snapshot,?bar.render(),?"./output/1.png")????????#?2、按優(yōu)先級(jí)排序繪制????????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優(yōu)先級(jí).html')????????make_snapshot(snapshot,?bar2.render(),?"./output/2.png")????????#?3、根據(jù)終端來(lái)繪制餅圖????????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. 總結(jié)

    通過(guò)上面得操作,每次只需要輸入項(xiàng)目類(lèi)型、迭代版本號(hào)、要統(tǒng)計(jì)得 Bug 類(lèi)型,就能統(tǒng)計(jì)出所需要得數(shù)據(jù)并繪制成圖表

    到此這篇關(guān)于利用Python統(tǒng)計(jì)Jira數(shù)據(jù)并可視化得內(nèi)容就介紹到這了,更多相關(guān)Python統(tǒng)計(jì)Jira數(shù)據(jù)內(nèi)容請(qǐng)搜索之家以前得內(nèi)容或繼續(xù)瀏覽下面得相關(guān)內(nèi)容希望大家以后多多支持之家!

    聲明:所有內(nèi)容來(lái)自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
    發(fā)表評(píng)論
    更多 網(wǎng)友評(píng)論1 條評(píng)論)
    暫無(wú)評(píng)論

    返回頂部

    主站蜘蛛池模板: 国产激情精品一区二区三区| 国产精品一区三区| 久久精品无码一区二区日韩AV| 插我一区二区在线观看| 中文字幕一区在线观看视频 | 国产成人精品无人区一区| 久久福利一区二区| 一区二区在线免费视频| 精品人妻一区二区三区浪潮在线| 国产vr一区二区在线观看| 怡红院一区二区三区| 精品人妻码一区二区三区| 久久综合一区二区无码| 日本香蕉一区二区三区| 国产91精品一区二区麻豆网站| 国产在线精品一区二区高清不卡 | 波多野结衣中文字幕一区| 亚洲国产精品一区二区久| 国产人妖视频一区二区| 亚洲国产成人久久一区久久| 另类ts人妖一区二区三区| 亚洲精品精华液一区二区| 亚洲视频一区二区三区| 一区二区三区四区精品视频| 国产一区二区三区高清在线观看| 在线精品日韩一区二区三区| 日本无卡码一区二区三区| 搡老熟女老女人一区二区| 国产一区二区三区91| 日韩精品无码视频一区二区蜜桃| 美女视频免费看一区二区| 在线观看国产一区亚洲bd| 国产欧美色一区二区三区| 亚洲另类无码一区二区三区| 亚洲色一区二区三区四区| 国模私拍福利一区二区| 亚洲一区二区三区丝袜| 韩国理伦片一区二区三区在线播放| 国产suv精品一区二区33| 无码人妻AⅤ一区二区三区| 无码人妻一区二区三区免费看|