Azure DevOps自动创建develop到main的PR及脚本故障排查
问题分析与修复方案
问题1:误判已有活跃PR
原因
- 未过滤PR状态:你调用的检查PR的API默认返回所有状态的PR(包括已关闭、已完成的历史PR),而非仅活跃状态。即使当前没有活跃PR,只要历史上存在过develop到main的PR,
$resultActivePR.count就会大于0,触发误判。 - 判断逻辑不准确:Azure DevOps API返回的PR列表结构包含
count和value数组,直接使用$resultActivePR.count可能受历史数据影响,应基于value数组的实际长度判断活跃PR数量。
修复
- 修改检查PR的API地址,添加
searchCriteria.status=active参数过滤仅活跃PR:$uriCheckActivePR = "https://dev.azure.com/$organization/$teamProject/_apis/git/repositories/$repoName/pullrequests?searchCriteria.targetRefName=$branchTarget&searchCriteria.sourceRefName=$branchSource&searchCriteria.status=active&api-version=5.1" - 更新判断逻辑,基于
value数组长度判断:if ($resultActivePR.value.Count -gt 0) { Write-Host "PR exists already" Return }
问题2:无法创建PR
原因
- JSON格式错误:手动拼接的请求体使用了单引号,但JSON规范要求属性名和值必须用双引号,导致API无法解析请求。
- Token未正确接收:脚本未声明参数接收传入的
-token值,$token变量未定义,生成的认证信息无效,API请求因权限不足被拒绝。 - (可选)权限不足:构建服务账号(如
[项目名] Build Service)可能没有创建PR的权限,需确保其拥有Contributor或更高级别的权限。
修复
- 添加参数声明:在脚本开头添加参数定义,接收传入的token:
param( [Parameter(Mandatory=$true)] [string]$token ) - 用
ConvertTo-Json生成合法请求体:避免手动拼接JSON的错误:$prBody = @{ sourceRefName = $branchSource targetRefName = $branchTarget title = "Sync changes from $branchSource" } | ConvertTo-Json $result = Invoke-RestMethod -Uri $uriCreatePR -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $prBody - 验证权限:在Azure DevOps项目设置的「权限」中,确保构建服务账号拥有创建PR的权限(可添加到Contributor组)。
完整修改后的脚本片段
param( [Parameter(Mandatory=$true)] [string]$token ) $user = "PrivateToken" $branchTarget = "refs/heads/main" $branchSource = "refs/heads/develop" $branchTragetPath = $branchTarget -replace "refs/heads/", "" $teamProject = "team" $repoName = "$(Build.Repository.Name)" $organization = "org" $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token))) $uriBranchStatus = "https://dev.azure.com/$organization/$teamProject/_apis/git/repositories/$repoName/stats/branches?name=$branchTragetPath&api-version=5.1" $uriCheckActivePR = "https://dev.azure.com/$organization/$teamProject/_apis/git/repositories/$repoName/pullrequests?searchCriteria.targetRefName=$branchTarget&searchCriteria.sourceRefName=$branchSource&searchCriteria.status=active&api-version=5.1" $uriCreatePR = "https://dev.azure.com/$organization/$teamProject/_apis/git/repositories/$repoName/pullrequests?api-version=5.1" $resultStatus = Invoke-RestMethod -Uri $uriBranchStatus -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} if ($resultStatus.behindCount -eq 0) { Write-Host "Current branch contains last changes from main" Return } $resultActivePR = Invoke-RestMethod -Uri $uriCheckActivePR -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} if ($resultActivePR.value.Count -gt 0) { Write-Host "PR exists already" Return } $prBody = @{ sourceRefName = $branchSource targetRefName = $branchTarget title = "Sync changes from $branchSource" } | ConvertTo-Json $result = Invoke-RestMethod -Uri $uriCreatePR -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $prBody Write-Host "Created PR" $result.pullRequestId
内容的提问来源于stack exchange,提问作者user989988
相关产品推荐
相关产品推荐

