背景:jira上测试人员提的bug,对应的开发人员可以收到对应的邮件通知,但是对应的项目其他人员可能不知道目前bug的解决情况,可以将jira上对应的未清bug介入到企业微信,定时推送,实现bug透明化
1. 目录结构如下:
--config:主要配置一些固定的配置:jira地址,jira上bug的链接sql,对应的测试人员跟开发人员信息,对应企业微信群机器人链接等
--outstandingbug:主要处理未清bug的核心逻辑
--run_6_30:主要定义运行的脚本
2. 代码中的内容如下:
config.py代码内容
#jira链接地址
url = "https://jira.xxxxxxx.com/"
# 测试人员还有多少bug需要跟进的链接
url_tests = "https://jira.xxxxx-internal.com/issues/?jql=issuetype%20in%20(BUG%2C%20%E6%95%85%E9%9A%9C)" \
"%20AND%20status%20in%20(%E6%9C%AA%E5%BC%80%E5%90%AF%2C%20REOPENED%2C%20%E4%BF%AE%E5%A4%8D%E4%B8%AD%" \
"2C%20%22To%20Do%22%2C%20%E5%A4%84%E7%90%86%E4%B8%AD%2C%20%E8%BF%9B%E8%A1%8C%E4%B8%AD)%20AND%20creator%20" \
"in%20(currentUser())%20AND%20created%20%3E%3D%20{}%20ORDER%20BY%20priority%20DESC%2C%20updated%" \
"20DESC".format("2021-08-09")
url_tests_p0_p1 = "https://jira.xxxx-internal.com/issues/?jql=project%20%3D%20LOGISTIC%20AND%20issuetype%20%3D%20BUG%20AND%20status%20in%20(%E6%9C%AA%E5%BC%80%E5%90%AF%2C%20REOPENED%2C%20%E5%A4%84%E7%90%86%E4%B8%AD)%" \
"20AND%20priority%20in%20(%E7%B4%A7%E6%80%A5%2C%20%E9%87%8D%E8%A6%81)%20AND%20creator%20in%20" \
"(currentUser())%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC"
# 日期链接(发给开发的)
url_data_time = "https://jira.xxxx-internal.com/issues/?jql=project%20%3D%20LOGISTIC%20AND%20issuetype%20%3D%20BUG%20AND%20status%20in%20(%E6%9C%AA%E5%BC%80%E5%90%AF%2C%20REOPENED%2C%20%E5%A4%84%E7%90%86%E4%B8%AD)%20AND%20created%" \
"20%3E%3D%20{}%20AND%20assignee%20in%20(currentUser())%20ORDER%20BY%20priority%20DESC%2C%20" \
"updated%20DESC".format("2021-08-09")
url_minute = "https://jira.xxxxx-internal.com/issues/?jql=project%20%3D%20LOGISTIC%20AND%20issuetype%20%3D%20BUG%20AND%20status%20in%20(%E6%9C%AA%E5%BC%80%E5%90%AF%2C%20REOPENED%2C%20%E5%A4%84%E7%90%86%E4%B8%AD)%20AND%20created%20%3E%3D%20-{}m%20ORDER%20BY%20" \
"priority%20DESC%2C%20updated%20DESC"
# 测试群机器人链接
dsj_url_test = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 正式群机器人链接
dsj_url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# dsj_url = dsj_url_test
# 测试总群群机器人链接
dsj_url2 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# base jql语句
base_jql = "project = LOGISTIC AND issuetype = BUG AND status in (未开启, REOPENED, 处理中)"
# 具体时间(如:2020-09-09)的jql语句
jql = base_jql + " AND created >= {} ORDER BY priority DESC, updated DESC"
# 非具体时间(如:60分钟)的jql语句
jql1 = base_jql + " AND created >= -{}m ORDER BY priority DESC, updated DESC"
# 非具体时间(如:60分钟)的jql语句(紧急重要(P0P1)的bugs的jql语句)
jql2 = base_jql + " AND priority in (紧急, 重要) AND created >= -{}m ORDER BY priority DESC, updated DESC"
# 解决企业微信艾特具体人员时,艾特不到,对人员进行转换处理
people = {
"zhangsan": "zahngsan",
"lisi": "lisi"
}
outstansingbug.py中内容
#登录jira
import json
import requests
from jira import JIRA
from xpinyin import Pinyin
from config import *
def login(username='123', password='123'):
"""
登录
:return:
"""
jira = JIRA(url, auth=(username, password))
return jira
#因为jira上用户名可能是中文,所以要定义一个将转化成中文的函数
def china_to_py(text="中文"):
"""
中文转拼音
:return:str
"""
p = Pinyin()
result1 = p.get_pinyin(text)
s = result1.split('-')
result3 = ''.join(s[0:])
return result3
def list_list(list1=[], list2=[]):
"""
两个list相减,即两个list的差集
:return: list
"""
# v = list(set(list1).difference(set(list2)))
# return v
for i in list2:
if i in list1:
list1.remove(i)
return list1
def _list_list(list1=[], list2=[]):
"""
两个list相加,并去重
:return: list
"""
list_v = list1 + list2
return list(set(list_v))
def solve_people(str_v):
"""
解决企业微信艾特具体人员时,艾特不到,对人员进行转换处理
:param str_v:字符串目标
:return: list
"""
for i, ii in people.items():
str_v = str(str_v).replace(i, ii)
return eval(str_v)
#处理复核条件的sql信息
def get_jql(get_time="2021-08-09", yxj=True):
"""
获取符合条件的jql语句
:param get_time: 时间参数,支持两种格式,一种是具体年月日,如:2021-09-09,一种是分钟数,如60
:param yxj: bug优先级,默认为True,即优先级为全部,若False,则优先级为P0P1
:return: jql语句,str格式
"""
if len(str(get_time)) > 6:
sql = jql.format(get_time)
else:
if yxj:
sql = jql1.format(get_time)
else:
sql = jql2.format(get_time)
return sql
#获取符合条件的bug列表
def search_projects_bugs(get_time="2021-08-09", yxj=True):
"""
默认:2021-08-09至今,类型为bug,状态为:未开启, REOPENED, 修复中, 处理中的所有bug列表
:return:bug列表(list)
"""
try:
v = login().search_issues(get_jql(get_time, yxj), maxResults=600)
except:
v = []
return v
def get_bugs_creator(bug_key, name="china"):
"""
获取bug对应的测试人员,即bug创建人,默认中文
key:bug的key
:return:str
"""
issue = login().issue(bug_key)
if name == "china":
return str(issue.fields.creator)
else:
return china_to_py(str(issue.fields.creator))
def get_bugs_creators(bug_id_lists, name="china"):
"""
根据bug的批量id列表,获取bug对应的测试人员列表,即bug创建人,默认中文
:return:list
"""
creators = []
for i in bug_id_lists:
creator = get_bugs_creator(i)
creators.append(creator)
if name == "china":
return creators
else:
return eval(china_to_py(str(creators)))
#获取bug的开发人员
def get_bugs_developer(bug_key, name="china"):
"""
获取bug对应的开发解决人,默认中文
key:bug的key
:return:
"""
issue = login().issue(bug_key)
# 以下代码为解决重名时,企业微信艾特人错误而定制
if name == "china":
developer = str(issue.fields.assignee)
if developer == "张帅":
if get_bugs_creator(bug_key) == "张璠" or get_bugs_creator(bug_key) == "赵晶":
developer = "杭州_张帅"
else:
developer = "合肥_张帅"
return developer
else:
developer = china_to_py(str(issue.fields.assignee))
if developer == "zhangshuai":
if get_bugs_creator(bug_key, name="py") == "zhangfan" or get_bugs_creator(bug_key, name="py") == "zhaojing":
developer = "z_shuai"
else:
developer = "zhang_shuai"
return developer
def search_projects_bugs(get_time="2021-08-09", yxj=True):
"""
默认:2021-08-09至今,类型为bug,状态为:未开启, REOPENED, 修复中, 处理中的所有bug列表
:return:bug列表(list)
"""
try:
v = login().search_issues(get_jql(get_time, yxj), maxResults=600)
except:
v = []
return v
def get_project_bugs_creators(tp="china", get_time="2021-08-09", yxj=True):
"""
2021-08-09至今,收集所有项目未日清bug的所有人,默认中文
不允许重复,重复的已经过滤了
:return: list
"""
try:
v = get_project_bugs_repeat_creators(tp, get_time, yxj)
creator_v = list(set(v[0]))
except:
creator_v = []
return creator_v
#获取项目未清bug的所有人默认中文
def get_project_bugs_repeat_creators(tp="china", get_time="2021-08-09", yxj=True):
"""
2021-08-09至今,收集所有项目未日清bug的所有人,默认中文
允许人员重复
:return: tuple
"""
bug_ids = []
creators = []
for i in search_projects_bugs(get_time, yxj):
bug_ids.append(str(i))
for i in bug_ids:
if tp == "china":
creators.append(get_bugs_developer(i))
else:
creators.append(get_bugs_developer(i, "py"))
return creators, bug_ids
def split_list(l_1):
"""
分割list列表,目标把拼音人名和手机号码分割成2个list列表
:return: tuple
"""
l_2 = []
for i in l_1:
if i.isdigit():
l_1.remove(i)
l_2.append(i)
return l_1, l_2
def get_project_bugs_repeat_ceshi_people(tp="china", get_time="2021-08-09", yxj=True):
"""
2021-08-09至今,收集所有项目未日清bug的测试人员,默认中文
允许人员重复
:return: tuple
"""
bug_ids = []
creators = []
for i in search_projects_bugs(get_time, yxj):
bug_ids.append(str(i))
for i in bug_ids:
if tp == "china":
creators.append(get_bugs_creator(i))
else:
creators.append(get_bugs_creator(i, "py"))
return creators, bug_ids
#针对POP1未清bug文案处理
def push_notice_p0p1(i, ii, n):
"""
紧急,重要(P0,P1)的通知文本
:param i:
:param ii:
:param n:
:return:
"""
if n == 6:
minute = 60
else:
minute = 90
title_1 = "二、紧急,重要(P0,P1)的bug:"
text_1 = "1、今日下午5点至今,紧急,重要(P0,P1)的bug有 {} 位开发人员没有修复".format(i)
text_11 = "1、今日下午5点至今,紧急,重要(P0,P1)的未日清(未修复)bug为0"
t1 = ",请及时跟进:"
t2 = ",点个赞👍"
text_2 = ",".join(ii)
text_3 = "2、具体bug请点击如下链接:"
text_4 = url_minute.format(minute)
if i == 0:
_text = title_1 + "\n" + text_11 + t2
else:
_text = title_1 + "\n" + text_1 + t1 + text_2 + "\n" + text_3 + "\n" + text_4
return _text
def push_notice_p0p1_statistics_to_tests_6_and_6_30(i):
"""
下午6点及6:30统计:未日清bug (紧急,重要(P0,P1)) 的最终统计通知文本,发送给测试人员的,目的:需要测试人员进行跟进
:param i:
:return:
"""
title_1 = "一、紧急,重要(P0,P1)的bug对应的测试owner:"
text_1 = "1、今日下午17:00至今,共 {} 个紧急、重要(P0、p1)bug未日清(未修复)".format(i)
text_11 = "今日下午17:00至今,紧急、重要(P0、p1)未日清(未修复)bug为0"
t1 = ",其中需要如下测试owner进行跟进:"
t2 = ",不需要测试人员跟进!"
# text_2 = ",".join(ii)
if i == 0:
_text = title_1 + "\n" + text_11 + t2
else:
_text = title_1 + "\n" + text_1 + t1
return _text
#发送给开发人员查看的文案
def push_notice_no_p0p1(i, ii, iii):
"""
未日清bug的通知文本(2021-08-09至今上一个工作日5点前的未日清bug)
:param i: 未日清的bug数量
:param ii: 未日清的bug 对应的开发人员数量(已去重)
:param iii: 对应开发人员列表()已去重
:return:
"""
title_1 = "一、未日清的所有bug:"
# text_1 = "1、截止到目前,未日清的bug有 {} 位开发人员没有修复,请及时跟进:".format(i)
text_1 = "1、截止到目前(2021-08-09至今),未日清的bug有 {} 个没有修复,涉及 {} 位开发人员,请及时跟进:".format(i, ii)
text_2 = ",".join(iii)
text_3 = "2、具体bug请点击如下链接:"
text_4 = url_data_time
_text = title_1 + "\n" + text_1 + text_2 + "\n" + text_3 + "\n" + text_4
return _text
#发送给测试人员跟进的文案
def _push_notice_no_p0p1_statistics_to_tests(i, ii):
"""
9点钟统计:未日清bug的最终统计通知文本(2021-08-09至今上一个工作日5点前的未日清bug)发送给测试人员的,目的:需要测试人员进行跟进
:param i:
:return:
"""
title_1 = "二、未日清的所有bug对应的测试owner:"
# 下面注释的是第二天9点的文本
# text_1 = "1、2021-08-09至昨天(上个工作日,周{})下午17点前:共 {} 个bug未日清(未修复),其中需要如下测试owner进行跟进:". \
# format(get_yesterday_weekday(), i)
# 下面这个是2021-08-09至今的文本
text_1 = "1、截止到目前(2021-08-09至今),未日清的bug有 {} 个没有修复,涉及 {} 位测试owner,请及时push对应开发GG进行修复:". \
format(i, ii)
_text = title_1 + "\n" + text_1
return _text
def send_projects_xx(send_message, creators_lists, mobile_lists, to_url=dsj_url_test):
"""
默认发送测试群机器人
:param send_message:
:return:
"""
data = json.dumps({
"msgtype": "text",
"text": {
"content": send_message, # 发送的消息内容
"mentioned_list": creators_lists, # 圈出所有人
"mentioned_mobile_list": mobile_lists # 手机号
}
})
# 指定机器人发送消息
requests.post(to_url, data, auth=('Content-Type', 'application/json'))
def get_today_5dian_to_n_dian_creator(n=6, tp="china"):
"""
获取今天下午5点至今的未修复bug(P0P1)对应开发人员列表
:return:tuple
"""
if n == 6:
minute = 60
else:
minute = 90
creator_china = get_project_bugs_creators(tp, minute, False)
creator_py = eval(china_to_py(str(creator_china)))
creator_py = solve_people(creator_py)
return creator_china, creator_py
def get_today_5dian_to_n_dian_repeat_creator_and_bug_ids(n=6, tp="china"):
"""
获取今天下午5点至今的未修复bug(P0P1)对应测试人员列表及bug_id列表
:return:tuple
"""
if n == 6:
minute = 60
else:
minute = 90
creator_china, bug_ids = get_project_bugs_repeat_ceshi_people(tp, minute, False)
creator_py = eval(china_to_py(str(creator_china)))
creator_py = solve_people(creator_py)
return creator_china, creator_py, bug_ids
#执行未清bug的脚本
def run(n=5):
# creator_china, creator_py = get_2021_08_09_to_now_creator()
get_2021_08_09_to_now_developer_and_bug_ids = get_project_bugs_repeat_creators() #获取从2021-08-09到今天所有bug的id跟开发人员
developer_repeat_china = get_2021_08_09_to_now_developer_and_bug_ids[0] #获取从2021-08-09到今天所有bug的开发人员
# 过滤重复的中文姓名
developer_china = list(set(developer_repeat_china)) #set(developer_repeat_china)将得到的开发人员中的重复元素给去掉
developer_py = eval(china_to_py(str(developer_china))) #china_to_py(str(developer_china)将对应的中文转换成拼音的函数得到拼音结果
developer_py = solve_people(developer_py)#solve_people(developer_py)对开发人员进行处理防止出现企业微信艾特不到的情况
list_bug_id = get_2021_08_09_to_now_developer_and_bug_ids[1] #获取从2021-08-08到今天所有的bug的id
list_len = len(list_bug_id) #获取所有未清bug的数量
get_bugs_creators_china_repeat = get_bugs_creators(list_bug_id) #get_bugs_creators(list_bug_id)根据bug的批量id列表,获取bug对应的测试人员列表,即bug创建人,默认中文
get_bugs_creators_china = list(set(get_bugs_creators_china_repeat)) #将bug对应的测试人员的重复数据给清楚掉
get_bugs_creators_py_repeat = eval(china_to_py(str(get_bugs_creators_china_repeat))) #将bug对应的测试人员从中文转换成拼音
get_bugs_creators_py = list(set(get_bugs_creators_py_repeat))#将对应的bug对应的测试人员转换成列表
#对企业微信中测试人员的bug进行提醒的文案
text_to_test_1 = ""
for i in get_bugs_creators_china:
text_to_test_1 += "{}:{} 个".format(i, get_bugs_creators_china_repeat.count(i)) + "\n"
text_to_test_2 = "2、具体bug请点击如下链接:" + "\n" + url_tests
text_to_test_p0p1 = "2、具体bug请点击如下链接:" + "\n" + url_tests_p0_p1
text_to_test_11 = _push_notice_no_p0p1_statistics_to_tests(list_len, len(
get_bugs_creators_china)) + "\n" + text_to_test_1 + text_to_test_2
# 处理测试人员姓名的拼音,防止企业微信艾特不到
get_bugs_creators_py = solve_people(get_bugs_creators_py)
l_11, l_22 = split_list(get_bugs_creators_py)
if developer_china == []:
text = "构建失败,原因:人员列表为空,即登录失败!"
print(text)
send_projects_xx(text, ["zhuyixun"], [""], dsj_url_test)
else:
nnn = len(search_projects_bugs())
push_notice_text_5dian = push_notice_no_p0p1(nnn, len(developer_china), developer_china)
if n == 5:
print("5点前的人员developer_py:", developer_py)
l_1, l_2 = split_list(developer_py)
send_projects_xx(push_notice_text_5dian, l_1, l_2, dsj_url)
# 以下是发送给测试人员的
print("5diande", l_11, l_22)
send_projects_xx(text_to_test_11, l_11, l_22, dsj_url2)
else:
creator_china1, creator_py1 = get_today_5dian_to_n_dian_creator(n)
_push_notice_text_n_dian = push_notice_p0p1(len(creator_china1), creator_china1, n)
push_notice_text_n_dian = push_notice_text_5dian + "\n" + _push_notice_text_n_dian
total_creator = _list_list(creator_py1, developer_py)
print("5点前的人员:", developer_py)
print("5点后到现在的P0P1人员:", creator_py1)
print("total_creator", total_creator)
l_1, l_2 = split_list(total_creator)
send_projects_xx(push_notice_text_n_dian, l_1, l_2, dsj_url)
# 以下是发送给测试人员的# 处理测试人员姓名的拼音,防止企业微信艾特不到
p0p1creators_china_repeat, p0p1creators_py_repeat, p0p1bug_ids = get_today_5dian_to_n_dian_repeat_creator_and_bug_ids(
n)
p0p1creators_china = list(set(p0p1creators_china_repeat))
p0p1creators_py = list(set(p0p1creators_py_repeat))
_text_to_test = ""
for i in p0p1creators_china:
_text_to_test += "{}:{} 个".format(i, p0p1creators_china_repeat.count(i)) + "\n"
# 优先级为P0P1的通知
if len(p0p1bug_ids) == 0:
text_to_test = push_notice_p0p1_statistics_to_tests_6_and_6_30(len(p0p1bug_ids)) + "\n" + _text_to_test
else:
text_to_test = push_notice_p0p1_statistics_to_tests_6_and_6_30(
len(p0p1bug_ids)) + "\n" + _text_to_test + text_to_test_p0p1
# 以下是发送给测试人员的# 处理测试人员姓名的拼音,防止企业微信艾特不到
get_bugs_creators_py = solve_people(p0p1creators_py)
l_1, l_2 = split_list(get_bugs_creators_py)
print("6diandep0p1", l_1, l_2)
send_projects_xx(text_to_test, l_1, l_2, dsj_url2)
# 2021-08-09至现在的通知
print("6diande", l_11, l_22)
send_projects_xx(text_to_test_11, l_11, l_22, dsj_url2)
if __name__ == '__main__':
res=login()
print(res)
run_6_30.py中内容
import sys
sys.path.append('../')
import outstandingbug
def run():
try:
outstandingbug.run(6_30)
except:
outstandingbug.send_projects_xx("6点30分构建脚本异常", ["xxxx"], [""])
if __name__ == '__main__':
run()
3. 运行脚本以后对应的测试群里的通知如下:
4.对应的项目群通知如下:
5. 可以将此脚本跟jenkins进行配置实现定时调度