定时发送!凭借飞书机器人,测试团队 bug 情况随时能晓! - 飞书官网
解决方案

定时发送!凭借飞书机器人,测试团队bug情况随时能晓!

飞书

2024-12-23

作者:jackLi​
推荐理由​
一、关于我们​
二、需求分析​
三、方案调研​
四、开发流程​
作者:jackLi​
推荐理由​
如何快速了解测试团队人员缺陷状态情况?飞书机器人每日定时提醒,自动汇总统计jira缺陷情况,帮助最少时间了解最多信息量!​
一、关于我们​
  1. 我们是一家家政公司(好慷在家)测试团队开发同学;​
  1. 我们开源分享一切可分享的效率工具;​
  1. 我们都是热爱分享和学习。​
​
二、需求分析​
  1. 在使用飞书项目看板之前,和其他公司一样,使用项目管理工具是JIRA,JIRA提供很多restful api来进行查询数据;​
  1. JIRA操作繁琐、流程长,每天 都要关注测试进度情况,测试项目繁多,而且进度各不一样,如何在短时间内快速知道缺陷状态、分布、进度情况,就成了 首要任务。​
​
三、方案调研​
通过调研飞书开放能力和其他项目管理平台提供的api,发现结合飞书机器人或者飞书自动化流程,可以大大提高工作效率。目前可对外开放的模版格式如下图所示:​
项目地址:github.com​
​
四、开发流程​
1.环境​
​
250px|700px|reset
​
​
2.使用​
2.1更新pip​
​
​
pip install --upgrade pip​
​
2.2创建虚拟目录​
​
​
python -m venv 虚拟环境名称,名称是随意起的​
python -m venv tutorial-env​
​
2.3激活虚拟环境​
  • 当激活虚拟环境时命令行上会有个虚拟环境名前缀​
Unix或MacOS上激活虚拟环境​
​
​
source tutorial-env/bin/activate​
​
windows上激活虚拟环境​
​
​
tutorial-env\Scripts\activate.bat​
​
2.4项目依赖安装​
​
​
python3.7 -m pip install --upgrade pip​
pip install -r requirements.txt​
​
​
  • 如果引入其他新的依赖,可以执行冻结第三方库,就是将所有第三方库及版本号保存到requirements.txt文本文件中​
​
pip freeze > requirements.txt​
​
  • 如果pip不起作用,可以从pypi上下载最新的源码包(​
​
​
python setup.py install ​
​
2.5项目配置说明​
修改配置​
(1)配置jira、飞书机器人​
config/config.json​
​
​
{​
"jira": {​
"url": "https://jira.xxxx.com", jira地址"url_browse": "https://jira.xxxx.com/browse/", 用于机器人发送消息模板点击链接地址"username": "", jira账号"password": "" jira密码​
},​
"feishu": {​
"webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/xxxx", 飞书机器人webhook"secret":"xxxx" 飞书机器人秘钥​
},​
"timing_task":{​
"week":"1-5", 每周一至五"hour":9, 上午9点30分执行一次"minute":30 ​
}​
}​
(2)jira账号和姓名(一般配置测试团队成员信息)​
config/userInfo.json​
​
​
{​
"userInfo":[​
{ "username": "wangml", "name": "王美玲" },​
{ "username": "chenyaojie", "name": "陈耀杰" },​
{ "username": "liancm", "name": "练春木" },​
{ "username": "linzx", "name": "林志祥" },​
{ "username": "wangjunq", "name": "王俊奇" },​
{ "username": "xuby", "name": "许冰艳" },​
{ "username": "kanglt", "name": "康丽婷" },​
{ "username": "liyc", "name": "李银池" }​
]​
​
}​
​
2.6单元测试启动​
  • pytest​
​
​
pytest​
​
  • unittest​
​
python -m unittest -v src.test.unit_test.TestFeishuRobot​
# python -m unittest 文件名.类名.方法名​
​
2.7 项目服务启动​
​
​
python main.py​
​
2.8服务器部署启动​
第一种方式:​
​
​
nohup python main.py >> feishu-robot-python-main.log 2>&1 &​
​
第二种方式:使用pm2进程守护启动​
3.飞书机器人​
使用飞书机器人发送消息,本质是使用Python的requests类库发送http请求,请求地址即为创建机器时保存的webhook链接,发送的内容实际为json串,请求header为{'Content-Type': 'application/json; charset=utf-8'}​
3.1 发送纯文本​
文本消息@用法说明 // @ 单个用户 名字 // @ 所有人 所有人​
{ "receive_id": "oc_xxx", "content": " {\"text\":\"<at user_id=\\\"ou_xxx\\\">Tom</at> text content\"}", "msg_type": "text" }​
@单个用户时,user_id填open_id,必须是有效值,否则取名字展示,没有@效果;@所有人必须满足所在群开启@所有人功能。​
3.2可发送的消息类型​
自定义机器人添加完成后,就能向其 webhook 地址发送 POST 请求,从而在群聊中推送消息了。支持推送的消息格式有文本、富文本、图片消息,也可以分享群名片等。 参数msg_type代表消息类型,可传入: text(文本)/ post(富文本)/ image(图片)/ share_chat(分享群名片)/ interactive(消息卡片)。具体使用方法可查看下文的官方文档。​
3.3请求发送后的返回信息汇总​
  • 消息发送成功:​
{“Extra”:null,“StatusCode”:0,“StatusMessage”:“success”}​
  • webhook地址无效:​
{“code”:19001,“msg”:“param invalid: incoming webhook access token invalid”}​
  • 关键词校验失败:​
{“code”:19024,“msg”:“Key Words Not Found”}​
  • IP校验失败:​
{“code”:19022,“msg”:“Ip Not Allowed”}​
  • 签名校验失败:​
{“code”:19021,“msg”:“sign match fail or timestamp is not within one hour from current time”}​
3.4 飞书机器人使用常见问题​
  • 自定义机器人的webhook地址有 V1、V2 版本,如何兼容?答:请参考帮助文档如何在群聊中使用机器人的附录部分“旧版 webhook (自定义机器人) 使用说明”。同时,推荐使用V2版本的自定义机器人。​
  • 使用webhook的自定义机器人是否可以@单个成员、或者@所有人?答:V2版本的自定义机器人,支持@单个成员、或者@所有人。​
  • 配置使用webhook的自定义机器人时,参数text是否有长度要求?答:建议 JSON 的长度不超过 30k,序列化后的 pb 不超过 100k,图片最好小于 10MB。​
3.5机器人扩展应用场景​
  • 服务器监测报警​
  • 天气情况、生日提醒和新闻资讯等的推送​
  • 个人开发应用的用户反馈​
  • 轻量级的埋点统计​
3.6脚本解析​
3.6.1 jira数据获取​
3.6.2 登录鉴权​
Jira的访问是有权限的,在访问Jira项目时首先要进行认证,Jira Python库提供了3种认证方式:​
  • 通过Cookis方式认证(用户名,密码)​
  • 通过Basic Auth方式认证(用户名,密码)​
  • 通过OAuth方式认证​
  • 认证方式只需要选择一种即可,以下代码为使用Cookies方式认证。​
请求示例:​
​
​
from jira import ​
JIRA jira = JIRA(auth=("username", "pwd"), options={'server': 'https://...'})​
# 参数xauth不是通信协议的basic_auth,连接方式请参考文首最新的官方文档,其他文章均为basic_auth,导致连不上​
projects = jira.projects()​
print(projects)​
输出:是一个数组,每个项目由<>包围,key是关键字,name是项目名​
​
​
[<JIRA Project: key='NEW', name='项目', id='10433'>, <JIRA Project: key='', name='', id='10467'>, <JIRA Project: key='', name='重构', id='10501'>, <JIRA Project: key='P2020021451', name='', id='10502'>, <JIRA Project: key='', name='工作', id='10481'>, <JIRA Project: key='', name='工作', id='10490'>, <JIRA Project: key='', name='申请', id='10446'>, <JIRA Project: key='', name='*', id='10613'>]​
​
  • 获取数组中每个元素下标的key​
​
​
print("open_issues:",open_issues[0].key)# type(open_issues)为 <class 'jira.client.ResultList'>​
​
3.7 使用jira jql获取缺陷数据​
  • 查询每个bug的详细信息,需要加上fields参数​
查询问题,支持JQL语句,一定要增加json_result参数,会返回bug详细信息,fields为指定显示的字段​
​
​
# 查询问题,支持JQL语句,一定要增加json_result参数,会返回bug详细信息,fields为指定显示的字段​
issues = jira.search_issues('project = P2020021451 AND component = 销售管理模块', fields="summary, priority, status", maxResults=-1, json_result='true')​
​
print(issues)​
[字段说明]​
  • 项目project;​
  • 模块名称components;​
  • 标题summary;​
  • 缺陷类型issuetype;​
  • 具体描述内容description;​
  • 经办人assignee;​
  • 报告人reporter;​
  • 解决结果resolution;​
  • bug状态status;​
  • 优先级priority;​
  • 创建时间created;​
  • 更新时间updated;​
  • 评论comments*​
返回内容​
​
​
{​
'expand': 'schema,names',​
'startAt': 0,​
'maxResults': 1000,​
'total': 77,​
'issues': [{​
'expand': 'operations,versionedRepresentations,editmeta,changelog,renderedFields',​
'id': '66559',​
'self': 'https://jira.**.net.cn/rest/api/2/issue/66559',​
'key': 'P2020021451-173',​
'fields': {​
'summary': '***为非必填项',​
'priority': {​
'self': 'https://jira.**.net.cn/rest/api/2/priority/3',​
'iconUrl': 'https://jira.**.net.cn/images/icons/priorities/medium.svg',​
'name': '中',​
'id': '3'​
},​
'status': {​
'self': 'https://jira.**.net.cn/rest/api/2/status/10540',​
'description': '',​
'iconUrl': 'https://jira.**.net.cn/images/icons/statuses/generic.png',​
'name': '开发处理中',​
'id': '10540',​
'statusCategory': {​
'self': 'https://jira.**.net.cn/rest/api/2/statuscategory/4',​
'id': 4,​
'key': 'indeterminate',​
'colorName': 'yellow',​
'name': '处理中'​
}​
}​
}​
}, {​
'expand': 'operations,versionedRepresentations,editmeta,changelog,renderedFields',​
'id': '57443',​
'self': 'https://jira.**.net.cn/rest/api/2/issue/57443',​
'key': 'P2020021451-4',​
'fields': {​
'summary': '**开发功能',​
'priority': {​
'self': 'https://jira.**.net.cn/rest/api/2/priority/2',​
'iconUrl': 'https://jira.**.net.cn/images/icons/priorities/high.svg',​
'name': '高',​
'id': '2'​
},​
'status': {​
'self': 'https://jira.**.net.cn/rest/api/2/status/10332',​
'description': '',​
'iconUrl': 'https://jira.**.net.cn/images/icons/statuses/generic.png',​
'name': '需求完成',​
'id': '10332',​
'statusCategory': {​
'self': 'https://jira.**.net.cn/rest/api/2/statuscategory/3',​
'id': 3,​
'key': 'done',​
'colorName': 'green',​
'name': '完成'​
}​
}​
}​
}]​
}​
​
​
返回的jira对象便可以对Jira进行操作,主要的操作包括:​
  • 1.项目​
  • 2.问题​
  • 3.搜索​
  • 4.关注者​
  • 5.评论​
  • 6.附件​
  • 7.项目(Project)#​
  • 8.jira.projects(): 查看所有项目列表​
  • 9.jira.project("项目的Key"): 查看单个项目​
项目对象的主要属性及方法​
​
​
key: 项目的Key​
name: 项目名称​
description: 项目描述​
lead: 项目负责人​
projectCategory: 项目分类​
components: 项目组件​
versions: 项目中的版本​
raw: 项目的原始API数据​
​
3.7.1 项目​
​
​
print(jira.projects()) # 打印所有你有权限访问的项目列表​
project = jira.project('某个项目的Key')​
print(project.key, project.name, project.lead) ​
​
3.7.2 问题(Issue)​
Issue是Jira的核心,Jira中的任务,用户Story,Bug实质上都是一个Issue。​
单个问题对象可以通过jira.issue("问题的Key")得到,问题的主要属性和方法如下:​
​
​
id: 问题的id​
key: 问题的Key​
permalink(): 获取问题连接​
fields: 问题的描述,创建时间等所有的配置域​
raw: 问题的原始API数据​
​
3.7.3 配置域(Fields)​
一般问题的ields中的属性分为固定属性和自定义属性,自定义属性格式一般为类似customfield_10012这种。常用的问题的Fields有:​
​
​
assignee:经办人​
created: 创建时间​
creator: 创建人​
labels: 标签​
priorit: 优先级​
progress:​
project: 所示项目​
reporter: 报告人​
status: 状态​
summary: 问题描述​
worklog: 活动日志​
updated: 更新时间​
watches: 关注者​
comments: 评论​
resolution: 解决方案​
subtasks: 子任务​
issuelinks: 连接问题​
lastViewed: 最近查看时间​
attachment​
​
​
issue = jira.issue('JRA-1330')​
print(issue.key, issue.fields.summary, issue.fields.status)​
​
3.7.4 关注者、评论、附件​
​
​
jira.watchers(): 问题的关注者​
jira.add_watcher(): 添加关注者​
jira.remove_watcher(): 移除关注者​
jira.comments(): 问题的所有评论​
jira.comment(): 某条评论​
jira.add_comment():添加评论​
comment.update()/delete(): 更新/删除评论​
jira.add_attachment(): 添加附件​
​
​
​
issue = jira.issue('JRA-1330')​
​
print(jiaa.watchers(issue)) # 所有关注者​
jira.add_watcher(issue, 'username') # 添加关注者​
​
print(jira.comments(issue)) # 所有评论​
comment = jira.comment(issue, '10234') # 某条评论​
jira.add_comment(issue, 'new comment') # 新增评论​
comment.update(body='update comment') # 更新评论​
comment.delete() # 删除该评论​
​
print(issue.fields.attachment) # 问题附件​
jira.add_attachment(issue=issue, attachment='/some/path/attachment.txt') # 添加附件​
​
3.7.5 创建/分配/转换问题​
​
​
# 创建问题​
issue_dict = {​
'project': {'id': 123},​
'summary': 'New issue from jira-python',​
'description': 'Look into this one',​
'issuetype': {'name': 'Bug'},​
}​
new_issue = jira.create_issue(fields=issue_dict)​
​
# 批量创建问题​
issue_list = [​
{​
'project': {'id': 123},​
'summary': 'First issue of many',​
'description': 'Look into this one',​
'issuetype': {'name': 'Bug'},​
},​
{​
'project': {'key': 'FOO'},​
'summary': 'Second issue',​
'description': 'Another one',​
'issuetype': {'name': 'Bug'},​
},​
{​
'project': {'name': 'Bar'},​
'summary': 'Last issue',​
'description': 'Final issue of batch.',​
'issuetype': {'name': 'Bug'},​
}]​
issues = jira.create_issues(field_list=issue_list)​
​
# 分配问题​
jira.assign_issue(issue, 'newassignee')​
​
# 转换问题​
jira.transition_issue(issue, '5', assignee={'name': 'pm_user'}, resolution={'id': '3'})​
​
3.7.6搜索​
Jira配有一套专门的搜索语言,称为JQL(Jira Query Language),Jira的Python库便是基于JQL语法进行搜索的,返回的是搜索到的问题列表。​
​
​
jira.search_issues('JQL语句')​
#默认最大结果数未1000,可以通过maxResults参数配置,该参数为-1时不限制数量,返回所有搜索结果。​
​
jira.search_issues('project=PROJ and assignee = currentUser()', maxResults=-1)​
通过python内置的dir()方法解析出每个事件都有哪些属性(字段),然后从中找出我们需要获取的数据,保存下来.​
dir(i),dir(i.fields)运行结果示例(里面列出了事件的属性)​
预约飞书企业效能顾问 深度诊断企业痛点,定制专属 AI 办公方案

先进团队,先用飞书

欢迎联系我们,飞书效能顾问将为您提供全力支持
分享先进工作方式
输送行业最佳实践
全面协助组织提效
标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题

字节跳动旗下 AI 工作平台

联系我们立即试用