python 操作 TFS 的 Work Item

发布于 2024-06-13 03:40:15 字数 5679 浏览 12 评论 0

因工作需要,现需要将 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

旧街凉风

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

玍銹的英雄夢

文章 0 评论 0

我不会写诗

文章 0 评论 0

十六岁半

文章 0 评论 0

浸婚纱

文章 0 评论 0

qq_kJ6XkX

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文