1

I'm using the official Python REST API of Azure DevOps: https://github.com/Microsoft/azure-devops-python-api

Thanks to the samples I have been able to retrieve information on Test Cases from ids.

How to do it from queries (WIQL)?

Here is my code so far (with modified tokens and links):

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
"""
)

This is the error I get

  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'

How shall I retrieve Test Cases from a query?

In particular, I do not understand the values of the "client" such as "vsts.work_item_tracking.v4_1.work_item_tracking_client.WorkItemTrackingClient"

Thank you all!

Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107

2 Answers2

5

After posting a message (i.e. issue leading to a pull request) on the Github repository for VSTS examples, I got a hint to solve my issue.

The solution is to use:

  • a wiql query object with Wiql class
  • query_by_wiql function
  • transforming the results of the query (references with WorkItem id) to WorkItem with get_work_item function (or get_work_items to process several WorkItems in a single pass)

Here is my solution to this problem:

[UPDATED FOR VERSION 5.1 and azure-devops module replacing VSTS]

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)
Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107
1

It is faster to request items in bulk. However, there is a limit to how many items you can request at once, so you need to slice the list into 200 item chunks.

This will also handle different query styles (workitems or workitemLinks)

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')
Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107