python資料統計之禪道bug統計

橘德德呀發表於2021-08-17

背景

通過定期輸出 每條產品的 BUG 情況,以此來反饋開發解決問題、測試跟進問題的情況;釘釘群推送提醒開發及時解決

以此我這邊開始著手準備編寫一個小工具,最終達到目的:自動定期傳送統計報告,報告維度(資料 + html展示)。

技術選型

python + markdown + pymysql + html + jenkins + 釘釘機器人

實現思路

python主要用到sshtunnel,pysql庫跳板機連線mysql資料庫,loguru庫日誌記錄,yaml記錄專案引數,request調取釘釘介面

  1. 讀取禪道資料庫資料及狀態,封裝sql類,把各維度統計資料通過dic格式返回
  2. 禪道bug彙總資料進行進行拼接,生成模板寫入markdown檔案。(釘釘會支援簡單markdown格式,表格等等不支援)
  3. 禪道bug明細資料,生成html頁面(沒找到合適的三方庫只能手動擼)
  4. 調取釘釘自定義介面,進行資料請求。
  5. jenkins實現定期推送+html頁面展示

主要程式碼

1、禪道sql封裝

ps.公司服務國外的所以時區+8H

from datetime import datetime
from middleware.config_handler import db_connect
"""針對產品返回所有bug資訊"""
def sql_pakeage(productid):
    """
    BUG狀態統計SQL封裝
    :param productid:
    :return:
    """
    bug_sql = "select count(*) from zt_bug where product in %s and deleted='0'"% (
    productid)

    resolved_bug_sql = "select count(*) from zt_bug where product in %s and deleted = '0' and `status` = 'resolved' and resolution <> 'postponed' " % (
        productid)

    not_resolved_bug_sql = "select count(*) from zt_bug where product in %s  and deleted = '0' and `status` =  'active' " % (
        productid)

    postponed_bug_sql = "select count(*) from zt_bug where product in %s and deleted = '0' and `status` <> 'closed' and resolution = 'postponed' " % (
        productid)

    closed_bug_sql = "select count(*) from zt_bug where product in %s and deleted = '0' and `status` = 'closed' " % (
        productid)

    return  bug_sql,resolved_bug_sql,not_resolved_bug_sql,postponed_bug_sql,closed_bug_sql


def  test_product_bug(productid):
    """
    產品BUG情況統計
    :param productid:
    :return:
    """
    #總bug數
    all_bug=db_connect.query_sql_df(sql_pakeage(productid)[0])

    #已解決bug數
    resolved_bug = db_connect.query_sql_df(sql_pakeage(productid)[1])

    # 未解決BUG數(當前顯示BUG狀態為未解決的。包含當前還沒被解決的、之前遺留的未解決、以及reopen的BUG(累計資料))
    not_resolved_bug = db_connect.query_sql_df(sql_pakeage(productid)[2])

    # 延期BUG數
    postponed_bug= db_connect.query_sql_df( sql_pakeage(productid)[3])

    # 已關閉BUG數
    closed_bug = db_connect.query_sql_df(sql_pakeage(productid)[4])

    statistics_bug = { "總BUG數":all_bug[0],"已解決BUG": resolved_bug[0], "未解決BUG": not_resolved_bug[0], "已關閉BUG": closed_bug[0],
                      "延期解決BUG": postponed_bug[0]}
    print(statistics_bug)

    return  statistics_bug

def test_product_bug_near(day, product):
    """
        最近總的BUG情況統計統計
        :param: day 根據輸入天數
        :return:
        """
    now = (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') #伺服器時區要 + 8h
    recent_sevenday = (datetime.datetime.now() - datetime.timedelta(days=day)).strftime("%Y-%m-%d %H:%M:%S")
    new_near_bug = db_connect.query_sql_df("""SELECT count(*) from zt_bug b where  b.product in %s and openedDate between "%s" and "%s";"""%(product, recent_sevenday, now))
    open_bug = db_connect.query_sql_df("""SELECT count(*) from zt_bug b where  b.product  in %s and  b.STATUS = "active" and openedDate between "%s" and "%s";"""%(product, recent_sevenday, now))
    close_bug = db_connect.query_sql_df("""SELECT count(*) from zt_bug b where  b.product  in %s and  b.STATUS = "closed" and openedDate between "%s" and "%s";"""%(product, recent_sevenday, now))
    close_unbug = db_connect.query_sql_df("""SELECT count(*) from zt_bug b where  b.product  in %s and  b.STATUS = "resolved" and openedDate between "%s" and "%s";"""%(product, recent_sevenday, now))
    statistics_bug = { "本週新增BUG數":new_near_bug[0], "本週未解決BUG數":open_bug[0],"本週已解決BUG數":close_bug[0],"本週已解決待驗證BUG數":close_unbug[0]}
    return statistics_bug

def bug_count(day, product):
    """
    最近總的BUG情況統計明細資料
    :param: day 根據輸入天數
    :return:
    """
    now = (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') #伺服器時區要 + 8h
    now_day = datetime.datetime.now().strftime('%Y-%m-%d')
    recent_sevenday = (datetime.datetime.now()-datetime.timedelta(days=day)).strftime("%Y-%m-%d %H:%M:%S")
    bug_sql = """
SELECT p.name,b.title,b.assignedTo,b.severity,b.type,b.status,b.openedBy, CAST(openedDate AS CHAR) AS openedDate from zt_bug b left join zt_product p on b.product = p.id 
where b.STATUS <> 'closed' and b.product in %s and openedDate between "%s" and "%s";"""%(product, recent_sevenday, now)
    print(bug_sql)
    recent_sevenday_bug = db_connect.query_sql_df(bug_sql)
    return recent_sevenday_bug

​2、釘釘介面推送

import json
import urllib.request

from config.path_config import data_file
from handler.loguru_handler import logger
def send_bug(url, data_file):
    # url = r"https://oapi.dingtalk.com/robot/send?access_token=XXXXXXX"
    logger.info("構建釘釘機器人的webhook")
    header = {"Content-Type": "application/json","Charset": "UTF-8"}

    with open(data_file, "r", encoding="utf-8") as f:
        conntent = f.read()

    data = {
        "msgtype": "markdown",
        "markdown": {
            "title": "測試bug統計",
            "text": conntent
        },
        "at": {
             "isAtAll": False     #@全體成員(在此可設定@特定某人)
        }
    }
    logger.info(f"構建請求內容:{data}")
    sendData = json.dumps(data)
    sendData = sendData.encode("utf-8")
    request = urllib.request.Request(url=url, data=sendData, headers=header)
    logger.info("傳送請求")
    opener = urllib.request.urlopen(request)
    logger.info("請求求發回的資料構建成為檔案格式")
    res = opener.read()
    logger.info(f"返回結果為:{res}")


​3、bug明細轉html檔案

def bug_html(lis ,html_file):
    """
    對查詢bug明細轉html檔案
    :param lis
    :param html_file
    """
    conten_title = []
    for key in lis[0]:
        conten_title.append(key)
    a = "</th><th>".join(conten_title)
    con_title = "<tr><th>" + a + "</th></tr>"
    conten_val = []
    con = ""
    for i in range(0, len(lis)):
        for index, v in enumerate(lis[i]):
            if index ==0:
                lis[i][v] ="<tr><td>" + lis[i][v]
            con = con + str(lis[i][v]) + "</td><td>"
        con = con[0:-2] +"r>"
        con = con + "\n"
    head = """<meta charset="utf-8">
    <style type="text/css">
    table.tftable {font-size:12px;color:#333333;width:100%;border-width: 1px;border-color: #9dcc7a;border-collapse: collapse;}
    table.tftable th {font-size:12px;background-color:#abd28e;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;text-align:left;}
    table.tftable tr {background-color:#ffffff;}
    table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;}
    </style>\n<table id="tfhover" class="tftable" border="1">\n"""
    last =  "</table>"
    htm = head + con_title + con + last

    with open(html_file, "w", encoding="utf-8") as f:
        f.write(htm)

另外功能基類以及呼叫傳送程式碼比較簡單就不展示了。

業務統計

按周統計(月份統計同理):

新增,新增日期為本週內的(包括本週內被解決或關閉的 BUG)

已解決,解決日期為本週內的。被開發設定為已解決的。其中可能有部分是上週遺留下來的,體現了開發在本週的變化情況(包括設計如此、重複 BUG、外部原因、無法重現、不予解決、轉為需求),不包含延期處理

已關閉,關閉日期為本週內的。是測試驗證過,確實已經解決的,包括其中有的是上週遺留下來的

未解決,當前顯示 BUG 狀態為未解決的。包含當前還沒被解決的、之前遺留的未解決、以及 reopen 的 BUG(累計資料)

延期解決,當前顯示 BUG 狀態為 延期處理的。BUG 狀態中新增一個延期解決 (累計資料)

應用截圖

釘釘通知

python資料統計之禪道bug統計

明細資料展示

python資料統計之禪道bug統計

 

 

相關文章