如何编程下载TFS工作项附件 完成TFS向GitLab迁移
TFS工作项附件批量下载及迁移实现方案
基于官方.NET客户端的稳定实现(无文件损坏问题)
该方案适配TFS 2017/2018/2019全版本,是经过生产环境迁移验证的可靠方式:
- 前置准备:在项目中安装与当前TFS大版本匹配的
Microsoft.TeamFoundationServer.ClientNuGet包,避免版本兼容导致的接口报错 - 核心注意点:禁止直接用无认证的HTTP客户端请求附件URL,否则会被重定向到TFS登录页,下载到的是HTML内容而非原文件,表现为文件损坏
- 核心实现代码:
using Microsoft.TeamFoundation.WorkItemTracking.WebApi; using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; using Microsoft.VisualStudio.Services.Common; using System.IO; // 初始化TFS连接 var tfsCollectionUrl = new Uri("http://你的TFS服务地址/tfs/目标项目集合名称"); var credentials = new VssBasicCredential(string.Empty, "你申请的TFS个人访问令牌"); using var connection = new Microsoft.VisualStudio.Services.WebApi.VssConnection(tfsCollectionUrl, credentials); using var workItemClient = connection.GetClient<WorkItemTrackingHttpClient>(); // 拉取所有需要迁移的工作项ID var queryResult = await workItemClient.QueryByWiqlAsync(new Wiql { Query = "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '你的项目名称'" }); var targetWorkItemIds = queryResult.WorkItems.Select(item => item.Id).ToList(); // 批量拉取工作项完整信息,包含附件关联数据 var workItemDetails = await workItemClient.GetWorkItemsAsync(targetWorkItemIds, expand: WorkItemExpand.Relations); foreach (var workItem in workItemDetails) { if (workItem.Relations == null) continue; // 筛选出附件类型的关联项 var attachedFiles = workItem.Relations.Where(rel => rel.Rel == "AttachedFile"); foreach (var attachment in attachedFiles) { var attachmentId = Guid.Parse(attachment.Url.Split('/').Last()); var fileName = Path.GetFileName(new Uri(attachment.Url).AbsolutePath); // 通过官方客户端方法拉取附件流,自动带认证信息 using var attachmentStream = await workItemClient.GetAttachmentContentAsync(attachmentId); // 按工作项ID分目录存储,方便后续和GitLab议题做映射 var savePath = Path.Combine("D:\\TFS附件备份", workItem.Id.ToString()); Directory.CreateDirectory(savePath); using var outputFile = File.Create(Path.Combine(savePath, fileName)); await attachmentStream.CopyToAsync(outputFile); } }
轻量脚本实现方案(无需.NET开发环境)
如果不想编写C#程序,也可以用Python/Shell等脚本直接调用TFS REST API实现,流程完全一致:
- 申请拥有工作项读取权限的个人访问令牌作为认证凭证
- 调用工作项查询接口获取所有目标工作项的ID列表
- 逐个请求工作项详情接口,提取所有关联类型为
AttachedFile的附件地址 - 请求附件地址时必须在请求头携带认证信息,将返回的二进制流直接保存为对应文件名即可
GitLab迁移配套操作
附件全部备份到本地后,创建GitLab议题时,可将对应工作项目录下的附件调用GitLab上传接口上传,拿到GitLab侧的附件访问地址后,替换原工作项描述中的附件引用,即可完成附件和议题的关联映射,不需要手动逐个上传。
内容的提问来源于stack exchange,提问作者B. Cratty
相关产品推荐
相关产品推荐

