Azure Pipeline自动创建PR需求及相关技术问题咨询
实现分支X自动创建/更新到分支Y的ADO PR流水线
核心方案
通过Azure Pipeline YAML结合Azure DevOps REST API,实现分支X变更触发后,自动检测是否存在从X到Y的开启状态PR,再根据结果执行创建PR(含审阅人、工作项关联)或更新现有PR(追加审阅人、关联新工作项)的操作。
具体实现步骤
1. 流水线触发配置
限定仅分支X有变更时触发流水线,YAML配置如下:
trigger: branches: include: - refs/heads/X # 替换为你的分支X名称 paths: exclude: - README.md # 可选,排除无需触发的文件路径
2. 配置流水线权限
- 为流水线服务账号分配仓库Contributor权限,用于创建/更新PR
- 确保服务账号拥有项目级读取工作项权限,用于关联工作项
- 在流水线代理作业设置中勾选允许脚本访问OAuth令牌,让脚本能调用ADO API
3. 检测现有开启状态的PR
用PowerShell脚本调用ADO REST API,查询是否存在从X到Y的活跃PR,并将结果存入流水线变量:
$orgName = "$(System.TeamFoundationCollectionUri)" $projectName = "$(System.TeamProject)" $repoName = "$(Build.Repository.Name)" $sourceBranch = "refs/heads/X" $targetBranch = "refs/heads/Y" # 查询活跃PR $prUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/pullrequests?sourceRefName=$sourceBranch&targetRefName=$targetBranch&status=active&api-version=7.1-preview.1" $prResponse = Invoke-RestMethod -Uri $prUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Get # 输出PR ID到流水线变量 if ($prResponse.count -gt 0) { Write-Host "##vso[task.setvariable variable=ExistingPrId;]$($prResponse.value[0].pullRequestId)" Write-Host "找到已存在的活跃PR: $($prResponse.value[0].pullRequestId)" } else { Write-Host "未找到从X到Y的活跃PR" }
4. 提取变更作者与关联工作项
4.1 获取提交作者
提取当前触发提交的作者邮箱(去重),存入变量供后续添加审阅人使用:
$orgName = "$(System.TeamFoundationCollectionUri)" $projectName = "$(System.TeamProject)" $repoName = "$(Build.Repository.Name)" # 获取当前提交的作者信息 $commitsUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/commits?searchCriteria.fromCommitId=$(Build.SourceVersion)&searchCriteria.toCommitId=$(Build.SourceVersion)&api-version=7.1-preview.1" $commits = Invoke-RestMethod -Uri $commitsUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Get $authors = $commits.value | Select-Object -ExpandProperty author -Unique | Select-Object -ExpandProperty email Write-Host "##vso[task.setvariable variable=PrReviewers;]$($authors -join ',')"
4.2 获取关联工作项
提取当前构建关联的工作项ID,存入变量供PR关联使用:
$orgName = "$(System.TeamFoundationCollectionUri)" $projectName = "$(System.TeamProject)" # 获取构建关联的工作项 $workItemsUrl = "$orgName/$projectName/_apis/build/builds/$(Build.BuildId)/workitems?api-version=7.1-preview.2" $workItems = Invoke-RestMethod -Uri $workItemsUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Get $workItemIds = $workItems.value | Select-Object -ExpandProperty id | ForEach-Object { "`"$_`"" } $workItemIdsStr = "[$($workItemIds -join ',')]" Write-Host "##vso[task.setvariable variable=LinkedWorkItems;]$workItemIdsStr"
5. 创建或更新PR
根据ExistingPrId变量的值,分支执行创建PR或更新现有PR的操作:
$orgName = "$(System.TeamFoundationCollectionUri)" $projectName = "$(System.TeamProject)" $repoName = "$(Build.Repository.Name)" $sourceBranch = "refs/heads/X" $targetBranch = "refs/heads/Y" if (-not $(ExistingPrId)) { # 创建新PR $reviewersList = $(PrReviewers) -split ',' | ForEach-Object { @{id = $_ } } $workItemsList = $(LinkedWorkItems) | ConvertFrom-Json | ForEach-Object { @{id = $_ } } $createPrBody = @{ sourceRefName = $sourceBranch targetRefName = $targetBranch title = "Auto-merge branch X to Y" description = "Automatically created by pipeline $(Build.BuildNumber)" reviewers = $reviewersList workItemRefs = $workItemsList } | ConvertTo-Json -Depth 3 $createPrUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/pullrequests?api-version=7.1-preview.1" Invoke-RestMethod -Uri $createPrUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Post -Body $createPrBody -ContentType "application/json" Write-Host "成功创建从X到Y的PR" } else { # 添加新审阅人 $reviewersBody = $(PrReviewers) -split ',' | ForEach-Object { @{id = $_ } } | ConvertTo-Json $addReviewerUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/pullrequests/$(ExistingPrId)/reviewers?api-version=7.1-preview.1" Invoke-RestMethod -Uri $addReviewerUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Post -Body $reviewersBody -ContentType "application/json" # 关联新工作项 $workItemsBody = $(LinkedWorkItems) | ConvertFrom-Json | ForEach-Object { @{id = $_ } } | ConvertTo-Json $linkWorkItemUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/pullrequests/$(ExistingPrId)/workitems?api-version=7.1-preview.1" Invoke-RestMethod -Uri $linkWorkItemUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Post -Body $workItemsBody -ContentType "application/json" # 更新PR描述 $updatePrBody = @{ description = "Updated by pipeline $(Build.BuildNumber). Latest commit: $(Build.SourceVersion)" } | ConvertTo-Json $updatePrUrl = "$orgName/$projectName/_apis/git/repositories/$repoName/pullrequests/$(ExistingPrId)?api-version=7.1-preview.1" Invoke-RestMethod -Uri $updatePrUrl -Headers @{Authorization = "Bearer $(System.AccessToken)"} -Method Patch -Body $updatePrBody -ContentType "application/json" Write-Host "成功更新现有PR: $(ExistingPrId)" }
优化建议
- 去重审阅人:更新PR前调用
GET /pullrequests/{prId}/reviewers接口,对比现有审阅人后再添加,避免重复 - 动态PR标题:从提交信息中提取主题作为PR标题,提升可读性
- 重试机制:给REST API调用添加
Retry-Command逻辑,应对网络波动 - 通知触发:添加发送通知的任务,告知相关人员PR已创建/更新
内容的提问来源于stack exchange,提问作者Walter Svenddal
相关产品推荐
相关产品推荐

