python 操作 TFS 的 Work Item
因工作需要,现需要将 jira 切换到微软的 TFS(Team Foundation Server),并自动化创建 TFS 的任务 (即 Work Item)。根据该需求,我首先使用了它的 REST API 进行尝试,但发现有些麻烦,后面找到了一个 python 库 dohq-tfs,该库 文档 友好,操作简单方便,很适合快速的开发相应的脚本。
条件准备
1. 安装库
使用 pip 安装 dohq-tfs 库,如下:
pip install dohq-tfs
2. 获取 Token
登录到 TFS 系统,点击个人头像,找到安全性选项,在安全性选项下添加一个 个人访问令牌
,即个人 token,复制该 token 信息,后续脚本中要用到。(经测试通过 dohq-tfs 库创建 Work Item 时直接使用用户和密码无法成功,而使用 token 却是可以的)
操作 TFS
我们知道创建 Work Item 肯定是在 TFS 的某个项目下进行创建的。这里需要说明的是,无论是通过脚本创建 work item 还是获取 work item,首先需要知道 work item 里面有哪些字段信息。我这里获取 Work Item 的字段信息方法是: 先手动在 TFS 上创建一个 Work Item,然后获取该 Work Item 的 API 即可知道 Work Item 有哪些字段信息。
例如:我在 TFS 系统 (网址为 https://tfshost.com.cn/tfs/ ) 的名为 XB 的项目下创建了一个任务项(Work Item),该任务项的 id 为 233,则该 Work Item 的 api 一般为: https://tfshost.com.cn/tfs/XB/_apis/wit/workitems/233?api-version=1.0&api-version=1.0
(TFS 官网 也有 Work Item 的 api 组成介绍)。该 api 网址返回的是一些 json 格式的数据信息,具体如下:
{
"id":233,
"rev":5,
"fields":{
"System.AreaPath":"XB",
"System.TeamProject":"XB",
"System.IterationPath":"XB",
"System.WorkItemType":"Task",
"System.State":"New",
"System.Reason":"New",
"System.AssignedTo":"张三",
"System.CreatedDate":"2020-03-09T02:16:28.847Z",
"System.CreatedBy":"张三",
"System.ChangedDate":"2020-03-09T07:01:45.317Z",
"System.ChangedBy":"张三",
"System.Title":"自动创建的任务",
"Microsoft.VSTS.Common.StateChangeDate":"2020-03-09T02:16:28.847Z",
"Microsoft.VSTS.Common.Priority":2,
"Microsoft.VSTS.Scheduling.FinishDate":"2020-03-25T16:00:00Z",
"Microsoft.VSTS.Scheduling.OriginalEstimate":20.0,
"Microsoft.VSTS.Scheduling.CompletedWork":20222.0,
"System.Description":"这是一个使用脚本自动创建 tfs 的任务",
"System.Tags":"测试"
},
...
}
上面只列出了一部分,通过上面信息我们知道,一个工作项中,状态信息对应的字段是:System.State,指派人对应的字段是:System.AssignedTo,标题对应的字段是:System.Title 等等等等。知道了这些,我们就能得心应手的使用 python 库操作 TFS 了。
下面是对操作 TFS 的 Work Item 的一些总结,我只对一些常用功能进行了封装。(运行环境 python3.6 或以上)
from tfs import TFSAPI, TFSClientError
# 声明在哪个项目下操作 Work Item
project = 'XB'
# token 信息
token = '64ugrjrfxwweazg5yd2cn3ulwm4tuqebdxkldyctabwihpqbnmpo'
client = TFSAPI('https://tfshost.com.cn/tfs/', project=project, pat=token)
# 获取某个 work item 的信息
def get_tfs_fields(work_id: int):
"""
:param work_id:
:return:
"""
workitem = client.get_workitem(work_id)
# 获取 workitem id
# print(workitem.data['id'])
field_names = workitem.field_names
# print(workitem.revisions)
for field_name in field_names:
print(f'{field_name}:{workitem.get(field_name)}')
def create_tfs_task(fields: dict, work_type: str = 'Task') -> int:
"""
创建一个 work item
:param work_type: 任务类型
:param fields: {'System.Title': '自动创建任务',
'System.Description': '这是一个使用脚本自动创建 tfs 的任务',
'System.AssignedTo': '张三',
}
:return:
"""
try:
workitem = client.create_workitem(work_type, fields)
except TFSClientError as e:
print(f'error:{e}')
return 0
else:
# print(workitem.get('AssignedTo'))
# print(workitem.id)
return int(workitem.id)
def add_child_task(parent_id: int, child_id: int):
"""
给父任务添加子任务
:param parent_id: 父任务 ID
:param child_id: 子任务 ID
:return:
"""
try:
parent_workitem = client.get_workitem(parent_id)
child_workitem = client.get_workitem(child_id)
parent_link_raw = [
{
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": parent_workitem.url,
"attributes": {
"isLocked": False
}
}
]
child_workitem.add_relations_raw(relations_raw=parent_link_raw)
except TFSClientError as e:
print(f'error:{e}')
return False
else:
return True
def update_tfs_task(work_id: int, data: dict):
"""
更新 work item 信息
:param work_id:
:param data:{"System.State": "进行中"}
:return:
"""
try:
workitem = client.get_workitem(work_id)
# workitem['System.State'] = "进行中"
for key, value in data.items():
workitem[key] = value
except TFSClientError as e:
print(f'error:{e}')
def search_tfs_task(title: str, work_type: str = 'Task'):
"""
根据条件查询 work item 信息,查询语句可根据自己需求定制,这里只是列了根据标题和任务类型查询
:param work_type:
:param title:
:return:
"""
query = f"""SELECT [System.Id],[System.WorkItemType]
FROM workitems
WHERE[System.WorkItemType] = '{work_type}' AND [System.Title] = '{title}'
ORDER BY[System.ChangedDate]
"""
try:
wiql = client.run_wiql(query)
ids = list(wiql.workitem_ids) or []
# print(f"Found WI with ids={ids}")
# # raw = wiql.result
# workitems = wiql.workitems
# print(workitems[0]['Title'])
except Exception as e:
print(f'error:{e}')
return False
else:
return ids
更多操作方法请查看 官网
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论