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

Jira测试计划关联测试用例状态更新遇401认证错误求助

Jira测试用例状态修改401错误排查与解决

我需要将Jira测试计划RO-6666中关联到测试执行RO-6665的10个测试用例状态从'TODO'改为'PASS',但执行代码时出现「Failed to retrieve issue details. Status code 401」错误,已核对令牌与权限仍未解决,原代码如下:

import os
from jira import JIRA
import requests
import json


# Define your Jira server URL, username, and API token
JIRA_SERVER = 'example tokens'
JIRA_USER = 'example tokens'
JIRA_API_TOKEN = 'example tokens'

# Define the Jira issue key for the test plan and execution
test_plan_key = 'RO-6666'
execution_key = 'RO-6665'

# Define the new status to set (e.g., 'PASS')
new_status = 'PASS'

# Set the Jira API endpoints for issue retrieval and transition
issue_url = f"{JIRA_SERVER}/rest/api/2/issue/{execution_key}"
transitions_url = f"{issue_url}/transitions"

# Define Jira options with headers for authentication and content type
jira_options = {
    'server': JIRA_SERVER,
    'headers': {
        'Content-Type': 'application/json'
    }
}

# Authenticate using basic auth (username and API token)
auth = (JIRA_USER, JIRA_API_TOKEN)

# Step 1: Get the issue details
response = requests.get(issue_url, headers=jira_options['headers'], auth=auth)
if response.status_code != 200:
    print(f"Failed to retrieve issue details. Status code: {response.status_code}")
    exit()

issue_data = response.json()
current_status = issue_data["fields"]["status"]["name"]

# Check if the current status is 'TODO'
if current_status != 'TODO':
    print(f"Test execution {execution_key} is not in 'TODO' status. Current status: {current_status}")
else:
    # Step 2: Get available transitions for the issue
    response = requests.get(transitions_url, headers=jira_options['headers'], auth=auth)
    if response.status_code != 200:
        print(f"Failed to retrieve available transitions. Status code: {response.status_code}")
        exit()

    transitions_data = response.json()

    # Find the transition ID for the 'PASS' status
    for transition in transitions_data["transitions"]:
        if transition["to"]["name"] == new_status:
            transition_id = transition["id"]
            break
    else:
        print(f"Transition to '{new_status}' status not found.")
        exit()

    # Step 3: Perform the transition to update the status
    transition_data = {"transition": {"id": transition_id}}
    response = requests.post(transitions_url, headers=jira_options['headers'], json=transition_data, auth=auth)

    if response.status_code == 204:
        print(f"Test execution {execution_key} status updated to '{new_status}'.")
    else:
        print(f"Failed to update status. Status code: {response.status_code}")

问题分析与修复方案

核心问题点

  1. 认证方式错误:Jira Cloud的基础认证要求将邮箱:API令牌进行Base64编码后放在请求头,原代码直接传入元组的方式不生效。
  2. 逻辑偏差:原代码试图修改测试执行本身的状态,而非其中关联的测试用例。测试用例是独立的Issue,需要单独处理。
  3. URL配置不规范:示例URL未替换为实际有效地址,导致请求失败。

修正后的完整代码

import requests
import json
import base64

# 替换为你的实际Jira配置
JIRA_SERVER = 'https://your-domain.atlassian.net'
JIRA_EMAIL = 'your-work-email@example.com'
JIRA_API_TOKEN = 'your-generated-api-token'

# 目标测试计划和执行Key
test_plan_key = 'RO-6666'
execution_key = 'RO-6665'
target_status = 'PASS'

# 生成符合要求的认证头
auth_str = f"{JIRA_EMAIL}:{JIRA_API_TOKEN}"
auth_base64 = base64.b64encode(auth_str.encode('utf-8')).decode('utf-8')
headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Basic {auth_base64}'
}

def fetch_test_execution_cases(exec_key):
    """获取测试执行关联的所有测试用例"""
    api_url = f"{JIRA_SERVER}/rest/raven/1.0/api/testexec/{exec_key}/testcases"
    resp = requests.get(api_url, headers=headers)
    if resp.status_code != 200:
        print(f"获取测试用例列表失败,状态码: {resp.status_code}")
        return []
    return resp.json()

def get_status_transition_id(issue_key, target_name):
    """获取Issue到目标状态的转换ID"""
    api_url = f"{JIRA_SERVER}/rest/api/2/issue/{issue_key}/transitions"
    resp = requests.get(api_url, headers=headers)
    if resp.status_code != 200:
        print(f"获取状态转换列表失败,状态码: {resp.status_code}")
        return None
    for transition in resp.json().get('transitions', []):
        if transition['to']['name'] == target_name:
            return transition['id']
    print(f"未找到到'{target_name}'的状态转换")
    return None

def update_case_status(issue_key, transition_id):
    """更新单个测试用例的状态"""
    api_url = f"{JIRA_SERVER}/rest/api/2/issue/{issue_key}/transitions"
    payload = {"transition": {"id": transition_id}}
    resp = requests.post(api_url, headers=headers, json=payload)
    if resp.status_code == 204:
        print(f"测试用例{issue_key}状态已更新为{target_status}")
    else:
        print(f"更新测试用例{issue_key}失败,状态码: {resp.status_code}")

# 执行流程
test_cases = fetch_test_execution_cases(execution_key)
if not test_cases:
    print("未找到与测试执行关联的测试用例")
    exit()

for case in test_cases:
    case_key = case['key']
    # 可选:检查当前状态是否为TODO
    case_resp = requests.get(f"{JIRA_SERVER}/rest/api/2/issue/{case_key}", headers=headers)
    if case_resp.status_code == 200:
        current_status = case_resp.json()['fields']['status']['name']
        if current_status != 'TODO':
            print(f"测试用例{case_key}当前状态为{current_status},跳过更新")
            continue
    # 获取转换ID并更新状态
    transition_id = get_status_transition_id(case_key, target_status)
    if transition_id:
        update_case_status(case_key, transition_id)

关键说明

  • 认证修正:使用Base64编码邮箱和API令牌,完全符合Jira Cloud的认证规范。
  • 测试用例获取:通过Xray插件的API获取测试执行关联的测试用例(Jira测试管理通常依赖Xray)。
  • 逐个处理:遍历每个测试用例,检查状态后执行状态转换,确保只修改目标用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:04:50