【问题标题】:How to extract WorkItems from query in VSTS (Azure DevOps) with Python REST API?如何使用 Python REST API 从 VSTS (Azure DevOps) 中的查询中提取 WorkItems?
【发布时间】:2019-03-19 12:14:17
【问题描述】:

我正在使用 Azure DevOps 的官方 Python REST API: https://github.com/Microsoft/azure-devops-python-api

感谢这些示例,我能够从 ids 中检索有关测试用例的信息。

如何通过查询 (WIQL) 做到这一点?

这是我目前的代码(带有修改后的标记和链接):

from vsts.vss_connection import VssConnection
from msrest.authentication import BasicAuthentication


token = "hcykwckuhe6vbnigsjs7r3ai2jefsdlkfjslkfj5mxizbtfu6k53j4ia"
team_instance = "https://tfstest.toto.com:8443/tfs/Development/"

credentials = BasicAuthentication("", token)
connection = VssConnection(base_url=team_instance, creds=credentials)


def print_work_items(work_items):
    for work_item in work_items:
        print(
            "{0} {1}: {2}".format(
                work_item.fields["System.WorkItemType"],
                work_item.id,
                work_item.fields["System.Title"],
            )
        )


WIT_CLIENT = (
    "vsts.work_item_tracking.v4_1.work_item_tracking_client.WorkItemTrackingClient"
)
wit_client = connection.get_client(WIT_CLIENT)


def get_TC_by_id(desired_ids):
    work_items = wit_client.get_work_items(ids=desired_ids, error_policy="omit")
    print_work_items(work_items)


def get_TC_from_query(query):
    # THIS FUNCTION IS NOT WORKING...
    work_items = wit_client.get_work_items(query=query, error_policy="omit")
    print_work_items(work_items)


get_TC_by_id([1035375])

get_TC_from_query(
    """\
SELECT
        [System.Id],
        [System.WorkItemType],
        [System.Title],
        [System.State],
        [System.AreaPath],
        [System.IterationPath]
FROM workitems
WHERE
        [System.TeamProject] = @project
        AND [System.WorkItemType] = 'Test Case'
ORDER BY [System.ChangedDate] DESC
"""
)

这是我得到的错误

  File "test_TFS.py", line 35, in get_TC_from_query
    work_items = wit_client.get_work_items(query=query, error_policy="omit")
TypeError: get_work_items() got an unexpected keyword argument 'query'

如何从查询中检索测试用例?

尤其是"vsts.work_item_tracking.v4_1.work_item_tracking_client.WorkItemTrackingClient"等“客户端”的值我不理解

谢谢大家!

【问题讨论】:

    标签: python rest tfs azure-devops azure-devops-rest-api


    【解决方案1】:

    在 VSTS 示例的 Github 存储库上发布消息(即导致 pull request 的问题)后,我得到了解决问题的提示。

    解决方法是使用:

    • 带有Wiql 类的wiql 查询对象
    • query_by_wiql函数
    • 使用get_work_item 函数(或get_work_items 一次处理多个WorkItem)将查询结果(带有WorkItem id 的引用)转换为WorkItem

    这是我对这个问题的解决方案:

    [已更新 5.1 版和替换 VSTS 的 azure-devops 模块]

    from azure.devops.connection import Connection
    from msrest.authentication import BasicAuthentication
    from azure.devops.v5_1.work_item_tracking.models import Wiql
    
    
    token = "hcykwckuhe6vbnigsjs7r3ai2jefsdlkfjslkfj5mxizbtfu6k53j4ia"
    team_instance = "https://tfstest.toto.com:8443/tfs/Development/"
    
    credentials = BasicAuthentication("", token)
    connection = Connection(base_url=team_instance, creds=credentials)
    
    
    def print_work_items(work_items):
        for work_item in work_items:
            print(
                "{0} {1}: {2}".format(
                    work_item.fields["System.WorkItemType"],
                    work_item.id,
                    work_item.fields["System.Title"],
                )
            )
    
    
    wit_client = connection.clients.get_work_item_tracking_client()
    
    
    def get_TC_from_query(query):
        query_wiql = Wiql(query=query)
        results = wit_client.query_by_wiql(query_wiql).work_items
        # WIQL query gives a WorkItemReference => we get the corresponding WorkItem from id
        work_items = (wit_client.get_work_item(int(result.id)) for result in results)
        print_work_items(work_items)
    

    【讨论】:

      【解决方案2】:

      批量请求项目更快。但是,您一次可以请求的项目数量是有限的,因此您需要将列表分成 200 个项目块。

      这还将处理不同的查询样式(workitemsworkitemLinks

      def get_TC_from_query(query):
          query_wiql = Wiql(query)
          query_result = wit_client.query_by_wiql(query_wiql)
          if query_result.query_result_type.lower() == 'workitemlink':
              items = [relation.target for relation in query_result.work_item_relations]
          elif query_result.query_result_type.lower() == 'workitem':
              items = query_result.work_items
          else:
              raise AttributeError(f"Incorrect type for {query_result.query_result_type}")
      
          # get_work_items can only handle 200 items per search
          size_chunks = 200
          for idx in range(0, len(items), size_chunks):
              search_items = items[idx:idx+size_chunks]
              yield from wit_client.get_work_items([x.id for x in search_items], expand='all')
      

      【讨论】:

        【解决方案3】:

        我正在尝试将其用于“workitemlinks”,但不断收到错误:TypeError: 'WorkItemQueryResult' object is not iterable

        知道我做错了什么吗?

        下面是我的代码sn-p:

        """
        WIT samples
        """
        import datetime
        import logging
        
        from samples import resource
        from utils import emit
        
        from azure.devops.v5_1.work_item_tracking.models import Wiql
        
        logger = logging.getLogger(__name__)
        
        
        def print_work_item(work_item):
            emit(
                "{0} {1}: {2}".format(
                    work_item.fields["System.WorkItemType"],
                    work_item.id,
                    work_item.fields["System.Title"]
                )
            )
        
        
        @resource("work_items")
        def get_work_items(context):
            wit_client = context.connection.clients.get_work_item_tracking_client()
        
            desired_ids = range(1, 51)
            work_items = wit_client.get_work_items(ids=desired_ids, error_policy="omit")
        
            for id_, work_item in zip(desired_ids, work_items):
                if work_item:
                    print_work_item(work_item)
                else:
                    emit("(work item {0} omitted by server)".format(id_))
        
            return work_items
        
        
        @resource("work_items")
        def get_work_items_as_of(context):
            wit_client = context.connection.clients.get_work_item_tracking_client()
        
            desired_ids = range(1, 51)
            as_of_date = datetime.datetime.now() + datetime.timedelta(days=-7)
            work_items = wit_client.get_work_items(
                ids=desired_ids, as_of=as_of_date, error_policy="omit"
            )
        
            for id_, work_item in zip(desired_ids, work_items):
                if work_item:
                    print_work_item(work_item)
                else:
                    emit("(work item {0} omitted by server)".format(id_))
        
            return work_items
        
        
        @resource("wiql_query")
        def wiql_query(context):
            wit_client = context.connection.clients.get_work_item_tracking_client()
            wiql = Wiql(
                query=
                    """
                        SELECT
                            [System.Id],
                            [System.WorkItemType],
                            [System.Title],
                            [System.AssignedTo],
                            [System.State],
                            [System.Tags]
                        FROM workitemLinks
                        WHERE
                            (
                                [Source].[System.TeamProject] = 'Sandbox'
                                AND [Source].[System.WorkItemType] <> ''
                                AND [Source].[System.State] <> ''
                            )
                            AND (
                                [System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward'
                            )
                            AND (
                                [Target].[System.TeamProject] = "Sandbox"
                                AND [Target].[System.WorkItemType] <> ''
                            )
                        MODE (Recursive)
                    """
            )
            # We limit number of results to 30 on purpose
            wiql_results = wit_client.query_by_wiql(wiql) #, top=30).work_items
           # emit("Results: {0}".format(len(wiql_results)))
            if wiql_results:
                # WIQL query gives a WorkItemReference with ID only
                # => we get the corresponding WorkItem from id
                work_items = (
                    wit_client.get_work_items(int(res.id)) for res in wiql_results
                )
                for work_item in work_items:
                    print_work_item(work_item)
                return work_items
            else:
                return []
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-05-09
          • 1970-01-01
          • 1970-01-01
          • 2020-07-03
          • 2022-07-17
          • 1970-01-01
          • 2022-09-23
          • 1970-01-01
          相关资源
          最近更新 更多