microsoft / microsoft/azure-devops-python-api

Deleting Pull Request Attachments Prevents Reading Attachments

未关闭
#499 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

主要语言
Python
星标
684
派生
218
平均合并
8 天 10 小时
30 天内合并 PR
1

描述

Hello,

I recently ran in to this issue while attempting to manage pull request attachments. It could be a bug with the AZDO API, but I'm specifically using azure-devops-python-api.

Steps to Reproduce

  1. Create multiple pull request attachments via GitClient, and delete at least one. The specific order doesn't matter; you can create two attachments then delete one of them, or create a single attachment, delete it, and create a second attachment.
  2. Attempting to access any non-deleted attachment (via the attachment URL) results in the following error:
{
    "$id": "1",
    "innerException": null,
    "message": "TF400714: File ID 123456789 not found.",
    "typeName": "Microsoft.TeamFoundation.Framework.Server.FileIdNotFoundException, Microsoft.TeamFoundation.Framework.Server",
    "typeKey": "FileIdNotFoundException",
    "errorCode": 0,
    "eventId": 4005
}

Example Code

delete_attachment_bug.py

from azure.devops.v7_0.git.models import *
from azure.devops.v7_0.git.git_client import GitClient
from msrest.authentication import BasicAuthentication
from azure.devops.connection import Connection
from random import randint

import os

def fix_create_attachment(client: GitClient):
    """
    See https://github.com/microsoft/azure-devops-python-api/issues/322 for documentation of this issue.
    """

    def create_attachment(upload_stream, file_name, repository_id, pull_request_id, project=None):
        route_values = {}
        if project is not None:
            route_values['project'] = client._serialize.url('project', project, 'str')
        if file_name is not None:
            route_values['fileName'] = client._serialize.url('file_name', file_name, 'str')
        if repository_id is not None:
            route_values['repositoryId'] = client._serialize.url('repository_id', repository_id, 'str')
        if pull_request_id is not None:
            route_values['pullRequestId'] = client._serialize.url('pull_request_id', pull_request_id, 'int')
        # content = self._client.stream_upload(upload_stream, callback=callback)
        response = client._send(http_method='POST',
                                location_id='965d9361-878b-413b-a494-45d5b5fd8ab7',
                                version='7.0',
                                route_values=route_values,
                                content=upload_stream.read(),
                                media_type='application/octet-stream')
        return client._deserialize('Attachment', response)

    client.create_attachment = create_attachment

pat = os.environ.get("mypersonalaccesstoken")
auth = BasicAuthentication("", pat)
connection = Connection("https://dev.azure.com/someorganization/", auth)
client: GitClient = connection.clients.get_git_client()
fix_create_attachment(client)
pr_id = 123456
project_id = "MyProject"
repo_id = "MyRepo"

def create_attachment():
    with open("cool_pic.png", "rb") as file:
        # Create random name for attachment
        name = f"{randint(0,10000)}.png"
        attachment: Attachment = client.create_attachment(file, name, repo_id, pr_id, project_id)
        print(f"Created attachment: {name}\n(URL: {attachment.url})")

def delete_attachment(name):
    client.delete_attachment(name, repo_id, pr_id, project_id)
    print(f"Deleted attachment: {name}")

This code can be used along with the Python shell to reproduce the issue:

python -i delete_attachment_bug.py
>>> create_attachment()
>>> delete_attachment("nameFromPreviousCall")
>>> create_attachment()

Trying to access the most recently created attachment (via the attachment URL) results in the above error.

I'm using Python 3.7.4 and azure-devops==7.1.0b4.

I haven't been able to find a workaround yet. Note the example code includes a workaround for #322.

贡献指南

这个仓库没有索引到贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 delete_attachment_bug.py 以及 GitClient create_attachment 和 delete_attachment 调用开始,然后在 Python shell 中重现该序列。比较删除后的请求和返回的 attachment URL,以确定是客户端还是 Azure DevOps API 导致了 FileIdNotFoundException。当原因已确定,并且未删除的 attachment 在该序列之后仍可读取时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
azure, devops, python
领域
api, devops
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。