如何用Azure DevOps C#客户端获取PR关联构建状态并完成PR?
获取Azure DevOps PR关联构建状态并自动完成PR的正确方式
一、解决构建状态为空的问题:正确获取PR关联构建状态
默认调用GetPullRequestByIdAsync时,不会返回PR的关联状态(包括构建任务),必须指定PullRequestExpand.Statuses扩展参数才能加载这部分数据。
方法1:通过GitHttpClient获取PR的构建状态
using Microsoft.TeamFoundation.SourceControl.WebApi; using Microsoft.VisualStudio.Services.WebApi; // 初始化已有的GitHttpClient实例 var gitClient = connection.GetClient<GitHttpClient>(); // 查询PR时指定扩展参数,加载状态集合 var pullRequest = await gitClient.GetPullRequestByIdAsync( repositoryId: repoId, pullRequestId: pullRequestId, expand: PullRequestExpand.Statuses // 关键:指定加载状态数据 ); // 从Statuses中筛选出构建类型的状态条目 var buildStatuses = pullRequest.Statuses .Where(s => s.Context.Type == "build") .ToList(); // 遍历检查每个构建的状态 foreach (var buildStatus in buildStatuses) { // buildStatus.State 表示构建状态:NotSet、Pending、Succeeded、Failed等 // buildStatus.Description 包含构建ID、结果等详细信息 Console.WriteLine($"构建状态:{buildStatus.State}, 详情:{buildStatus.Description}"); }
方法2:通过BuildHttpClient直接查询关联PR的构建
如果需要更完整的构建信息(如执行时间、日志链接),可以用BuildHttpClient根据PR ID筛选关联构建:
using Microsoft.TeamFoundation.Build.WebApi; // 初始化BuildHttpClient实例 var buildClient = connection.GetClient<BuildHttpClient>(); // 查询关联当前PR的所有构建任务 var builds = await buildClient.GetBuildsAsync( project: projectName, repositoryId: repoId, sourcePullRequestId: pullRequestId // 用PR ID过滤构建 ); // 检查每个构建的执行结果 foreach (var build in builds) { bool isBuildSuccess = build.Status == BuildStatus.Completed && build.Result == BuildResult.Succeeded; Console.WriteLine($"构建ID {build.Id}: 状态={build.Status}, 结果={build.Result}, 是否成功={isBuildSuccess}"); }
二、判断所有构建成功后完成PR
结合你的需求,完整流程是循环检查构建状态→确认全部成功→调用更新接口完成PR。注意用异步调用替代.Result避免线程阻塞,同时确保用户拥有绕过分支策略的权限。
完整示例代码:
using System.Threading.Tasks; public async Task CompletePrWhenBuildsSucceedAsync(VssConnection connection, Guid repoId, int pullRequestId, string projectName) { var gitClient = connection.GetClient<GitHttpClient>(); var buildClient = connection.GetClient<BuildHttpClient>(); // 循环检查构建状态(可根据需求调整重试间隔和次数) bool allBuildsSucceeded = false; int retryCount = 0; const int maxRetries = 20; const int retryIntervalSeconds = 30; while (!allBuildsSucceeded && retryCount < maxRetries) { // 获取关联PR的所有构建 var builds = await buildClient.GetBuildsAsync( project: projectName, repositoryId: repoId, sourcePullRequestId: pullRequestId ); // 判断是否所有构建都已完成且成功 allBuildsSucceeded = builds.All(b => b.Status == BuildStatus.Completed && b.Result == BuildResult.Succeeded); if (!allBuildsSucceeded) { await Task.Delay(TimeSpan.FromSeconds(retryIntervalSeconds)); retryCount++; } } if (allBuildsSucceeded) { // 完成PR(基于你的代码调整为异步调用) var updatedPr = new GitPullRequest() { Status = PullRequestStatus.Completed, CompletionOptions = new GitPullRequestCompletionOptions() { SquashMerge = true, DeleteSourceBranch = true, BypassPolicy = true } }; var completedPr = await gitClient.UpdatePullRequestAsync(updatedPr, repoId, pullRequestId); Console.WriteLine($"PR {pullRequestId} 已成功完成"); } else { Console.WriteLine($"超时:PR {pullRequestId} 的关联构建未全部成功"); } }
关键注意点
- 必须指定
PullRequestExpand.Statuses,否则GitHttpClient返回的Statuses集合为空。 - 使用BuildHttpClient时,
sourcePullRequestId参数必须准确关联目标PR。 - 异步操作优先用
await,避免.Result导致的线程阻塞或死锁。 BypassPolicy=true生效的前提是当前用户拥有"绕过分支策略"的权限。
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

