最近,团队准备引入 Jira 做需求管理和任务跟踪。为了能更好地运用 Jira(挖坑),研究了下如何通过 Python 使用 Jira。目前主要是对 issue 进行增删改查操作,例如批量创建 issue,后期还准备将 Jira 的数据定时更新到 Superset 上,生成 Dashboard(或许还有自动生成迭代期报告?)。
0 连接服务器
首先,连接上部署 Jira 的服务器:
# 导入相关模块
import re
import pandas as pd
from jira import JIRA
jira = JIRA(server='http://127.0.0.1:8080', basic_auth=('user_name', 'password'))
连接成功后打印当前用户信息和所有项目:
jira.user(jira.current_user())
for j in jira.projects():
print('{0}-{1}'.format(j, j.name))
TEST-TEST
1 创建 issue
创建 issue 需要先设置 issue 的字段,然后以字典的形式作为参数传入用到 jira
模块的 create_issue(fields=None, prefetch=True, **fieldargs)
函数:
def createIssue(summary, fix_version, components, assignee, labels, start_date, end_date, project, issuetype, priority, desc=''):
''' Create issue
@param summary: issue summary, str
@param fix_versions: fix version, str
@param components: components, list
@param assignee: assignee, str
@param labels: labels, list
@param start_date: plan start date, str
@param end_date: plan end date, str
@param project: project name, str
@param issuetype: issue type name, str
@param priority: priority
@param desc: description, str, default ''
'''
# 将字符串转换为列表
labels = re.split(r',|,', re.sub(r'\s*', '', labels))
components = re.split(r',|,', re.sub(r'\s*', '', components))
# 将 components 转换为字典列表
component_list = []
for component in components:
component_list.append({'name': component})
issue_dict = {
'project': {'key': project}, #项目
'issuetype': {'name': issuetype}, #问题类型
'priority': {'name': priority}, #优先级
'summary': summary, #问题主题
'customfield_10303': start_date, #计划开始时间
'customfield_10304': end_date, #计划结束时间
'fixVersions': [{'name': fix_version}], #解决版本
'components': component_list, #相关模块
'assignee': {'name': assignee}, #经办人
'labels': labels, #标签
'description': desc, #问题描述
}
jira.create_issue(issue_dict)
print('创建成功')
可以在 notebook 或 shell,通过 input()
逐个输入 issue 所需字段,再通过 createIssue()
创建 issue:
def inputIssue():
''' Input issue
'''
def defaultInput(msg, default):
''' Use default values when input is empty
@param msg: prompt message, str
@param default: default value, str
@return t: result, str
'''
t = input(msg)
if t == '':
t = default
return t
def dateInput(raw_date):
''' Enter a formatted date string
@param raw_date: raw date, str
@return date: format date, str
'''
try:
date = re.search(r'(\d{4}-\d{2}-\d{2})', raw_date).group()
return date
except:
print("输入正确的时间格式(YYYY-MM-DD)")
dateInput(input("再次输入:"))
project = input("输入项目名称:")
issuetype = input("输入问题类型:")
summary = input("输入问题名称:")
start_date = dateInput(input("输入计划开始时间(YYYY-MM-DD):"))
end_date = dateInput(input("输入计划结束时间(YYYY-MM-DD):"))
labels = input("输入相关标签(多个以 , 区分):")
components = input("输入相关模块(多个以 , 区分):")
fix_version = input("输入解决版本:")
assignee = input("输入经办人:")
priority = defaultInput("输入优先级:", '2')
desc = defaultInput("输入问题描述:", '暂无')
createIssue(summary, fix_version, components, assignee, labels, start_date, end_date, project, issuetype, priority, desc)
也可以通过 pandas
的 read_csv()
,从 CSV 或 Excel 文件中导入数据,批量创建 issue:
df = pd.read_csv('sample.csv', names=['summary', 'fix_version', 'components', 'assignee', 'labels', 'start_date', 'end_date', 'issuetype', 'priority'])
for i in df.index:
issue = df.loc[i]
createIssue(issue['summary'], issue['fix_version'], issue['components'], issue['assignee'], issue['labels'], issue['start_date'], issue['end_date'], issue['issuetype'], issue['priority'])
2 删除 issue
也可以通过 pandas
的 read_csv()
,从 CSV 或 Excel 文件中导入数据,批量创建 issue:
def deleteIssue(issue_key):
''' Delete issue
@param issue_key: issue key, str
'''
issue = jira.issue(issue_key)
issue.delete()
print("删除成功")
3 更新 issue
在更新 issue 前,需要通过字段 key
获取 issue,然后更新指定字段的内容:
issue = jira.issue('TEST-42')
issue.update(summary='测试用 Python 更新 issue')
4 查询 issue
Jira 通过 JQL(JIRA Query Language,Jira 查询语言)进行搜索,语法类似于 SQL。可以通过 JQL 搜索符合条件的 issues,如通过 assignee = currentUser()
查找经办人为当前用户的 issues。
注意:Jira 的 JQL 不同于 Java Query Language
def searchIssues(jql, max_results=100):
''' Search issues
@param jql: JQL, str
@param max_results: max results, int, default 100
@return issues: result, list
'''
try:
issues = jira.search_issues(jql, maxResults=max_results)
return issues
except Exception as e:
print(e)
jql = '''
assignee = currentUser()
'''
issues = searchIssues(jql)
for issue in issues:
print('{0}: {1}'.format(issue.key, issue.fields.summary))
TEST-42: 测试用 Python 更新 issue
TEST-6: 测试用 Python 新建 issue
查询 issue 指定字段的内容:
def searchIssueContent(issue, content_type='summary'):
''' Search issue content
@param issue: issue, jira.resources.Issue
@param content_type: field, str, default 'summary'
@return result: result, str
@return result_list: result, list
'''
if content_type == 'comments':
result_list = [c.body for c in jira.comments(issue)]
return result_list
elif hasattr(issue.fields, content_type):
result = getattr(issue.fields, content_type)
if isinstance(result, list):
result_list = [c.name for c in result if hasattr(c, 'name')]
return result_list
return result
issue = jira.issue('TEST-42')
searchIssueContent(issue, 'comments')
[' !screenshot-1.png|thumbnail! ', '# 测试备注']
5 关于 Jira
Jira 是一款项目与事务跟踪工具,为敏捷团队的每个成员制定计划、跟踪并发布,被广泛应用于需求收集、项目计划、任务跟踪等领域。由于其功能强大、配置灵活,且具有丰富的扩展插件,可以满足团队在项目管理和开发协作上的大部分需求。
但由于 Jira 是基于敏捷开发的理念,且拥有复杂的配置和繁多的插件,Jira 的使用门槛较高。当团队决定引入 Jira 时,必须根据团队的特点和项目的需要,进行个性化的配置,并在实际应用的过程中,持续进行调整和优化(这个过程很敏捷==)。
这里吐槽一下 Jira 的使用体验,配置繁琐就罢了,其操作看板和 issue 的体验也不友好(看板用得最舒服的还是 Trello)。
参考 jira
模块的官方文档