Azure DevOps中触发CD流水线前能否合并同提交的多个CI构建?
该需求完全可以实现,可通过以下配置完成:
核心配置步骤
1. 开启CD流水线资源触发的批处理能力
修改CD-Pipeline.yml中的资源触发配置,新增batch: true参数,该参数会自动合并同一分支的多个触发请求,避免多CI同时完成时重复触发CD:
resources: pipelines: - pipeline: databasepipeline source: CI-Database trigger: branches: include: - main batch: true # 新增配置 - pipeline: dotnetpipeline source: CI-Dotnet trigger: branches: include: - main batch: true # 新增配置
2. 给CI流水线增加提交标识标签
在两条CI流水线的步骤末尾新增打标签步骤,将当前代码提交的SHA作为标签附加到CI构建上,方便后续CD校验:
# CI-Database.yml和CI-Dotnet.yml都添加以下步骤 - pwsh: | Write-Host "##vso[build.addbuildtag]Commit_$(Build.SourceVersion)" displayName: 绑定提交SHA标签
3. CD流水线新增前置CI完成校验阶段
在CD的部署阶段前增加校验逻辑,确认同一提交SHA对应的两条CI都已构建成功后再执行部署,避免单CI完成就触发部署的问题:
# 加到CD-Pipeline.yml的stages最前方 - stage: CheckCICompleted displayName: 校验同提交CI构建状态 jobs: - job: CheckStatus timeoutInMinutes: 10 # 可根据CI平均执行时长调整 steps: - pwsh: | $commitSha = "$(Build.SourceVersion)" $orgUri = "$(System.CollectionUri)" $project = "$(System.TeamProject)" $header = @{Authorization = "Bearer $(System.AccessToken)"} # 校验Database CI是否完成 $dbPipeId = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/pipelines?name=CI-Database&api-version=7.1-preview.1" -Headers $header).value.id $dbBuilds = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/build/builds?definitions=$dbPipeId&branchName=refs/heads/main&resultFilter=succeeded&tagFilters=Commit_$commitSha&api-version=7.1-preview.6" -Headers $header).value # 校验Dotnet CI是否完成 $dotnetPipeId = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/pipelines?name=CI-Dotnet&api-version=7.1-preview.1" -Headers $header).value.id $dotnetBuilds = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/build/builds?definitions=$dotnetPipeId&branchName=refs/heads/main&resultFilter=succeeded&tagFilters=Commit_$commitSha&api-version=7.1-preview.6" -Headers $header).value # 未完成则等待重试 $retry = 0 while($dbBuilds.Count -eq 0 -or $dotnetBuilds.Count -eq 0) { if($retry -gt 10) { Write-Error "CI构建等待超时,存在未完成的关联CI" exit 1 } Start-Sleep -Seconds 30 $dbBuilds = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/build/builds?definitions=$dbPipeId&branchName=refs/heads/main&resultFilter=succeeded&tagFilters=Commit_$commitSha&api-version=7.1-preview.6" -Headers $header).value $dotnetBuilds = (Invoke-RestMethod -Uri "$orgUri/$project/_apis/build/builds?definitions=$dotnetPipeId&branchName=refs/heads/main&resultFilter=succeeded&tagFilters=Commit_$commitSha&api-version=7.1-preview.6" -Headers $header).value $retry++ } # 输出可用的CI构建ID,后续部署可直接拉取对应构件 Write-Host "##vso[task.setvariable variable=dbBuildId;isOutput=true]$($dbBuilds[0].id)" Write-Host "##vso[task.setvariable variable=dotnetBuildId;isOutput=true]$($dotnetBuilds[0].id)" name: GetValidCIBuilds displayName: 校验CI完成状态
4. 新增幂等校验避免重复部署
在部署步骤开头增加已部署校验,已经完成部署的提交直接跳过,彻底杜绝重复部署问题:
# 加到DeployDEV阶段的steps最前方 - pwsh: | $commitSha = "$(Build.SourceVersion)" $header = @{Authorization = "Bearer $(System.AccessToken)"} $deployedBuilds = (Invoke-RestMethod -Uri "$(System.CollectionUri)/$(System.TeamProject)/_apis/build/builds?definitions=$(System.DefinitionId)&branchName=refs/heads/main&resultFilter=succeeded&tagFilters=Deployed_$commitSha&api-version=7.1-preview.6" -Headers $header).value if($deployedBuilds.Count -gt 0) { Write-Host "当前提交已完成部署,直接跳过" exit 0 } # 部署成功后打标签标记 Write-Host "##vso[build.addbuildtag]Deployed_$commitSha" displayName: 重复部署校验
简化替代方案
如果项目规模不大,也可以直接将两条CI合并为一条流水线,用并行Job分别执行Database和Dotnet的构建,全部Job执行完成后直接触发CD,无需额外校验逻辑,实现成本更低。
内容的提问来源于stack exchange,提问作者David C
相关产品推荐
相关产品推荐

