You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python获取Azure DevOps用户故事关联工作项时MODE关键字错误如何解决?

解决Azure DevOps WIQL查询中MODE(Recursive)的报错问题

问题场景

使用Python的Azure DevOps模块,想要以树形结构(父-子链接)获取指定用户故事的关联工作项,原代码中使用了包含MODE (Recursive)的WIQL查询,但执行wit_client.query_by_wiql(wiql=wiql_query)时触发错误:

Exception has occurred: AzureDevOpsServiceError
The MODE keyword can not be used inside work item query. The error is caused by «Recursive»

原代码如下:

from azure.devops.connection import Connection
from msrest.authentication import BasicAuthentication
from azure.devops.v7_1.work_item_tracking.models import Wiql
from variable import personal_access_token,org,project

# Replace with your personal access token and organization URL
personal_access_token = personal_access_token
organization_url = org
project_name = project

# Create a connection to the Azure DevOps organization
credentials = BasicAuthentication('', personal_access_token)
connection = Connection(base_url=organization_url, creds=credentials)

# Get the work item tracking client
wit_client = connection.clients.get_work_item_tracking_client()

# Define a WIQL (Work Item Query Language) query to get work items
wiql_query = Wiql(
    query=f"""
    SELECT
        [System.Id],
        [System.WorkItemType],
        [System.Title],
        [System.AssignedTo],
        [System.State],
        [System.Tags]
    FROM workitems
    WHERE
        (
            [Source].[System.TeamProject] = 'DevOps RnD'
            AND [Source].[System.Id] = 326797
        )
    AND (
            [System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward'
        )
    ORDER BY [System.Id]
    MODE (Recursive)
    """
)

wiql_result = wit_client.query_by_wiql(wiql=wiql_query)

错误原因

MODE (Recursive)是Azure DevOps网页端查询树状工作项的专属语法,不支持通过Work Item Tracking API执行的WIQL语句,API层面需要用其他方式实现递归获取层级工作项。

解决方案

方法一:递归获取树形结构(推荐)

通过获取根工作项的关联关系,递归遍历所有子项,直接构建树形结构:

from azure.devops.connection import Connection
from msrest.authentication import BasicAuthentication
from variable import personal_access_token, org, project
import json

# 初始化Azure DevOps连接
credentials = BasicAuthentication('', personal_access_token)
connection = Connection(base_url=org, creds=credentials)
wit_client = connection.clients.get_work_item_tracking_client()

def build_work_item_hierarchy(work_item_id, project_name):
    # 获取当前工作项,展开关联关系
    work_item = wit_client.get_work_item(
        work_item_id,
        expand='Relations',
        project=project_name,
        fields=['System.Id', 'System.WorkItemType', 'System.Title', 'System.State', 'System.AssignedTo']
    )
    
    # 构建当前工作项的基础信息
    item_data = {
        'id': work_item.id,
        'work_item_type': work_item.fields['System.WorkItemType'],
        'title': work_item.fields['System.Title'],
        'state': work_item.fields['System.State'],
        'assigned_to': work_item.fields.get('System.AssignedTo', {}).get('displayName', '未分配'),
        'children': []
    }
    
    # 遍历关联关系,找到所有子项(Hierarchy-Forward链接)
    if hasattr(work_item, 'relations'):
        for relation in work_item.relations:
            if relation.rel == 'System.LinkTypes.Hierarchy-Forward':
                # 从链接URL中提取子项ID
                child_id = int(relation.url.split('/')[-1])
                # 递归获取子项的层级结构
                child_data = build_work_item_hierarchy(child_id, project_name)
                item_data['children'].append(child_data)
    
    return item_data

# 调用函数获取树形结构
root_item_id = 326797
target_project = 'DevOps RnD'
hierarchy_result = build_work_item_hierarchy(root_item_id, target_project)

# 格式化输出结果
print(json.dumps(hierarchy_result, indent=2, ensure_ascii=False))

方法二:WIQL批量获取后自行构建树形

通过WIQL一次性获取所有层级的工作项(包括根项和所有子项),再手动处理父子关系:

from azure.devops.connection import Connection
from msrest.authentication import BasicAuthentication
from azure.devops.v7_1.work_item_tracking.models import Wiql
from variable import personal_access_token, org, project

# 初始化连接
credentials = BasicAuthentication('', personal_access_token)
connection = Connection(base_url=org, creds=credentials)
wit_client = connection.clients.get_work_item_tracking_client()

# 定义WIQL查询,获取根项及所有子项
wiql_query = Wiql(
    query=f"""
    SELECT
        [System.Id],
        [System.WorkItemType],
        [System.Title],
        [System.AssignedTo],
        [System.State],
        [System.Tags]
    FROM workitems
    WHERE
        [System.TeamProject] = 'DevOps RnD'
        AND (
            [System.Id] = 326797
            OR [System.Id] IN (
                SELECT [System.Id]
                FROM workitems
                WHERE [System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Reverse'
                AND [Source].[System.Id] = 326797
            )
        )
    ORDER BY [System.Id]
    """
)

# 执行查询
wiql_result = wit_client.query_by_wiql(wiql=wiql_query)

# 获取所有工作项详情
work_items = []
for item_ref in wiql_result.work_items:
    work_item = wit_client.get_work_item(item_ref.id, expand='Relations')
    work_items.append(work_item)

# 手动构建树形结构(示例逻辑)
def build_hierarchy_from_flat_list(work_items, root_id):
    item_map = {item.id: item for item in work_items}
    hierarchy = None
    
    for item in work_items:
        item_data = {
            'id': item.id,
            'title': item.fields['System.Title'],
            'children': []
        }
        # 查找父项
        if hasattr(item, 'relations'):
            for relation in item.relations:
                if relation.rel == 'System.LinkTypes.Hierarchy-Reverse':
                    parent_id = int(relation.url.split('/')[-1])
                    if parent_id in item_map:
                        item_map[parent_id].children.append(item_data)
        # 定位根项
        if item.id == root_id:
            hierarchy = item_data
    return hierarchy

# 构建并输出树形结构
root_item_id = 326797
final_hierarchy = build_hierarchy_from_flat_list(work_items, root_item_id)

方法对比

  • 方法一:逻辑直观,直接递归构建树形,适合层级较深的场景,每次获取单个工作项,API调用次数等于工作项总数。
  • 方法二:通过一次WIQL查询获取所有项,API调用次数少,但需要额外处理父子关系,适合层级较浅的场景。

内容的提问来源于stack exchange,提问作者DEEPAK YADAV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 16:32:04