azure-devops 将工作项导出为 csv 并包含所有评论/讨论

问题描述 投票:0回答:2

如果我在 Azure Devops 中查询我的工作项,当我添加要显示的列时,只有

comments count
discussions
,但是是否有任何位置可以在我的输出保存的 csv 中包含工作项的所有注释文件?我需要将每个工作项目的评论存档在 csv 中。

我可以通过 azure 桌面 Web UI 执行此操作吗?或者我是否需要使用 azure api 编写自己的脚本来查看评论并将其添加到工作项

csv azure-devops export comments
2个回答
1
投票

我可以通过 azure 桌面 Web UI 执行此操作吗?或者我需要 使用azure api编写我自己的脚本来查看评论并添加 他们到一个工作项目

对于你的第一个问题,答案是“否”。既然你想要一个工作项的所有评论,那么内置的 UI 功能将无法实现你的要求。 对于你的第二个问题,答案是

from azure.devops.connection import Connection from msrest.authentication import BasicAuthentication import requests import csv import os #get all the comments of a work item def get_work_items_comments(wi_id): #get a connection to Azure DevOps organization_url = 'https://dev.azure.com/xxx' personal_access_token = 'xxx' credentials = BasicAuthentication('', personal_access_token) connection = Connection(base_url=organization_url, creds=credentials) work_item_tracking_client = connection.clients.get_work_item_tracking_client() #get the work item work_item = work_item_tracking_client.get_work_item(wi_id) #get the comments of the work item comments_ref = work_item._links.additional_properties['workItemComments']['href'] #send a request to get the comments response = requests.get(comments_ref, auth=('', personal_access_token)) #get the comments comments = response.json()['comments'] return comments #return work item id, work item title and related work item comments def get_work_items_results(wi_id): #get a connection to Azure DevOps organization_url = 'https://dev.azure.com/xxx' personal_access_token = 'xxx' credentials = BasicAuthentication('', personal_access_token) connection = Connection(base_url=organization_url, creds=credentials) work_item_tracking_client = connection.clients.get_work_item_tracking_client() #get the work item work_item = work_item_tracking_client.get_work_item(wi_id) #get the title of the work item title = work_item.fields['System.Title'] #get the work item id id = work_item.id #get the comments of the work item items = get_work_items_comments(wi_id) array_string = [] for item in items: text = item['text'] array_string.append(text) print(item['text']) return id, title, array_string #Save the work item id, work item title and related work item comments to a csv file #create folder workitemresults if not exist if not os.path.exists('workitemresults'): os.makedirs('workitemresults') with open('workitemresults/comments_results.csv', 'w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(['Workitem ID','Workitem Title','Workitem Comments']) #===if you want multiple work items, just for loop in this place and replace the value 120 in this place, 120 is the workitem id on my side.=== writer.writerow(get_work_items_results(120))

上面的代码是捕获一个工作项的评论和信息。它在我这边工作得很好(我已经在代码中提到了应该放置“for 循环”的位置,在该位置使用 for 循环您可以捕获多个工作项):

enter image description here

enter image description here 在我的情况下,如果我只想要文本内容:

#remove <div> and </div> from the text text = text.replace('<div>','') text = text.replace('</div>','')

结果:

enter image description here


0
投票


注1
:此脚本用纯文本替换html以生成有效的.csv,这意味着任何格式都将丢失 注 2
:这大约需要 15 分钟。 5000张门票 from datetime import datetime from bs4 import BeautifulSoup from tqdm import tqdm from azure.devops.connection import Connection from azure.devops.exceptions import AzureDevOpsServiceError from msrest.authentication import BasicAuthentication import requests import csv import os EXPORT_DIR_PATH = "exports" # The path of the directory to export the tickets to ORGANIZATION_URL = "https://dev.azure.com/<company>" # The root path of your DevOps instance PERSONAL_ACCESS_TOKEN = "<token>" # A personal access token, which you can generate under "User settings" --> "Personal access tokens" --> "New Token" FIRST_WORK_ITEM_ID = 0 # The ID of the first work item you want to export LAST_WORK_ITEM_ID = 1000 # The ID of the last work item you want to export (note that any IDs for which no work item can be found will be skipped) def html_to_plain_text(html: str) -> str: return ' '.join(BeautifulSoup(html, "html.parser").get_text().split()) def get_comments_of_work_item(work_item) -> dict: """ Returns all comments of a given work item :param work_item: :return: """ comments_ref = work_item._links.additional_properties["workItemComments"]["href"] response = requests.get(comments_ref, auth=("", PERSONAL_ACCESS_TOKEN)) return response.json()["comments"] def get_work_item(devops_client, wi_id: int) -> (int, str, str, str, list[str]): """ Returns a work item as a tuple :param devops_client: :param wi_id: :return: """ # Get the work item try: work_item = devops_client.get_work_item(wi_id) except AzureDevOpsServiceError: # print(f"Work item #{wi_id} not found") return None, None, None # Get the work item's comments comments = [] for comment in get_comments_of_work_item(work_item): comments.append(f"{comment['createdBy']['displayName']}: {html_to_plain_text(comment['text'])}") return (work_item.id, work_item.fields["System.WorkItemType"], work_item.fields["System.AssignedTo"]["displayName"] if "System.AssignedTo" in work_item.fields else None, work_item.fields["System.Title"], html_to_plain_text(work_item.fields["System.Description"]) if "System.Description" in work_item.fields else None, comments) def connect_to_devops() -> any: """ Connects to the devops :return: A connected client """ credentials = BasicAuthentication("", PERSONAL_ACCESS_TOKEN) connection = Connection(base_url=ORGANIZATION_URL, creds=credentials) return connection.clients.get_work_item_tracking_client() if __name__ == "__main__": if not os.path.exists(EXPORT_DIR_PATH): os.makedirs(EXPORT_DIR_PATH) datetime_str = datetime.now().strftime(f"%Y%m%d-%H%M%S") file_path = os.path.join(EXPORT_DIR_PATH, f"work_items_{datetime_str}.csv") with open(file_path, "w", newline="", encoding="utf-8") as csvfile: writer = csv.writer(csvfile, delimiter=";") writer.writerow(["ID", "Assigned To", "Title", "Description", "Comments"]) client = connect_to_devops() total_exported_tickets = 0 for i in (pbar := tqdm(range(FIRST_WORK_ITEM_ID, LAST_WORK_ITEM_ID + 1))): pbar.set_description(f"Downloading work item #{i}") work_item_line = get_work_item(client, i) if work_item_line[0] is not None: writer.writerow(work_item_line) total_exported_tickets += 1 break print(f"Finished: Exported {total_exported_tickets} tickets to '{file_path}'")

	
© www.soinside.com 2019 - 2024. All rights reserved.