Azure DevOps Pipelines 中的条件阶段执行
Posted
技术标签:
【中文标题】Azure DevOps Pipelines 中的条件阶段执行【英文标题】:Conditional Stage Execution in Azure DevOps Pipelines 【发布时间】:2021-03-20 23:16:45 【问题描述】:我希望 Azure DevOps 管道中的一个阶段根据前一阶段中设置的变量的内容来执行。
这是我的管道:
stages:
- stage: plan_dev
jobs:
- job: terraform_plan_dev
steps:
- bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
name: terraform_plan
- stage: apply_dev
dependsOn: plan_dev
condition: eq(stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'], '2')
jobs:
- deployment: "apply_dev"
...
如果plan_dev
阶段没有显示任何变化,则该想法是跳过apply_dev
阶段。背景是我们在plan_dev
阶段手动批准部署,如果没有要批准的更改,我们希望跳过该阶段。
不幸的是,这似乎不起作用。无论变量terraform_plan_exitcode
是否设置为期望值(2),都会跳过apply_dev
阶段。
对于语法,我遵循documentation here 说:
stageDependencies.StageName.JobName.outputs['StepName.VariableName']
【问题讨论】:
【参考方案1】:我也看到过同样的问题。您需要使用 dependencies 变量而不是 stageDependencies:
stages:
- stage: plan_dev
jobs:
- job: terraform_plan_dev
steps:
- bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
name: terraform_plan
- stage: apply_dev
dependsOn: plan_dev
condition: eq(dependencies.plan_dev.outputs['terraform_plan_dev.terraform_plan.terraform_plan_exitcode'], '2')
jobs:
- deployment: "apply_dev"
以下是我使用 Terraform Plan + 条件应用的更完整示例:
stages:
- stage: Build_zip_plan
displayName: Build portal, zip files and terraform plan
jobs:
- job: Build_portal_zip_files_terraform_plan
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Cache@2
displayName: 'Register TF cache'
inputs:
key: terraform | $(Agent.OS) | $(Build.BuildNumber) | $(Build.BuildId) | $(Build.SourceVersion) | $(prefix)
path: $ parameters.tfExecutionDir
- task: TerraformInstaller@0
displayName: 'Install Terraform'
inputs:
terraformVersion: $ parameters.tfVersion
- task: TerraformTaskV1@0
displayName: 'Terraform Init'
inputs:
provider: 'azurerm'
command: 'init'
workingDirectory: $ parameters.tfExecutionDir
backendServiceArm: $ parameters.tfStateServiceConnection
backendAzureRmResourceGroupName: $ parameters.tfStateResourceGroup
backendAzureRmStorageAccountName: $ parameters.tfStateStorageAccount
backendAzureRmContainerName: $ parameters.tfStateStorageContainer
backendAzureRmKey: '$(prefix)-$(environment).tfstate'
- task: TerraformTaskV1@0
displayName: 'Terraform Plan'
inputs:
provider: 'azurerm'
command: 'plan'
commandOptions: '-input=false -out=deployment.tfplan -var="environment=$(environment)" -var="prefix=$(prefix)" -var="tenant=$(tenant)" -var="servicenow=username=\"$(servicenowusername)\",instance=\"$(servicenowinstance)\",password=\"$(servicenowpassword)\",assignmentgroup=\"$(servicenowassignmentgroup)\",company=\"$(servicenowcompany)\"" -var="clientid=$(clientid)" -var="username=$(username)" -var="password=$(password)" -var="clientsecret=$(clientsecret)" -var="mcasapitoken=$(mcasapitoken)" -var="portaltenantid=$(portaltenantid)" -var="portalclientid=$(portalclientid)" -var="customerdisplayname=$(customerdisplayname)" -var="reportonlymode=$(reportonlymode)"'
workingDirectory: $ parameters.tfExecutionDir
environmentServiceNameAzureRM: $ parameters.tfServiceConnection
- task: PowerShell@2
displayName: 'Check Terraform plan'
name: "Check_Terraform_Plan"
inputs:
filePath: '$(Build.SourcesDirectory)/Pipelines/Invoke-CheckTerraformPlan.ps1'
arguments: '-TfPlan ''$ parameters.tfExecutionDir /deployment.tfplan'''
pwsh: true
- stage:
dependsOn: Build_zip_plan
displayName: Terraform apply
condition: eq(dependencies.Build_zip_plan.outputs['Build_portal_zip_files_terraform_plan.Check_Terraform_Plan.TFChangesPending'], 'yes')
jobs:
- deployment: DeployHub
displayName: Apply
pool:
vmImage: 'ubuntu-latest'
environment: '$(prefix)'
strategy:
runOnce:
deploy:
steps:
- checkout: self
- task: Cache@2
displayName: 'Get Cache for TF Artifact'
inputs:
key: terraform | $(Agent.OS) | $(Build.BuildNumber) | $(Build.BuildId) | $(Build.SourceVersion) | $(prefix)
path: $ parameters.tfExecutionDir
- task: TerraformInstaller@0
displayName: 'Install Terraform'
inputs:
terraformVersion: $ parameters.tfVersion
- task: TerraformTaskV1@0
displayName: 'Terraform Apply'
inputs:
provider: 'azurerm'
command: 'apply'
commandOptions: 'deployment.tfplan'
workingDirectory: $ parameters.tfExecutionDir
environmentServiceNameAzureRM: $ parameters.tfServiceConnection
【讨论】:
在找到答案之前我已经为此奋斗了一天,似乎您可以使用 stageDependencies 提取到用于作业的变量中,但在条件下它必须来自依赖项。你不喜欢一致的语法吗??【参考方案2】:@Marius 是正确的。所以这行得通
stages:
- stage: plan_dev
jobs:
- job: terraform_plan_dev
steps:
- bash: echo '##vso[task.setvariable variable=terraform_plan_exitcode;isOutput=true]2'
name: terraform_plan
- stage: apply_dev
dependsOn: plan_dev
variables:
varFromA: $[ stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'] ]
condition: eq(dependencies.plan_dev.outputs['terraform_plan_dev.terraform_plan.terraform_plan_exitcode'], 2)
jobs:
- job: apply_dev
steps:
- bash: echo 'apply $(varFromA)'
name: terraform_apply
当你引用 stage to stage dependencies 时,你有不同的语法
"dependencies":
"<STAGE_NAME>" :
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs":
"jobName.stepName.variableName": "value"
,
"...":
// another stage
当您跨阶段引用作业时,您有不同的语法
"stageDependencies":
"<STAGE_NAME>" :
"<JOB_NAME>":
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs":
"stepName.variableName": "value"
,
"...":
// another job
,
"...":
// another stage
当你在一个阶段有工作要做工作时,我们再次使用dependecies
语法有什么好笑的
"dependencies":
"<JOB_NAME>":
"result": "Succeeded|SucceededWithIssues|Skipped|Failed|Canceled",
"outputs":
"stepName.variableName": "value1"
,
"...":
// another job
这有点令人困惑,并认为 this in this as
当您在某个级别的阶段、工作和从工作到工作或从一个阶段到另一个阶段引用同一级别时,您有dependencies
语法
当您想从更深层次(例如从工作到阶段)进行参考时,您应该使用stageDependencies
有趣的是,在上面的例子中,我在舞台上使用了这个:
variables:
varFromA: $[ stageDependencies.plan_dev.terraform_plan_dev.outputs['terraform_plan.terraform_plan_exitcode'] ]
但这是在运行时评估并从作业中评估的,因此它是正确的并且被正确评估。
我希望它为之前的答案增加了价值。
【讨论】:
用于调试:如何查看您在答案中显示的 JSON 输出?有没有机会让它可见? 没有。这是模式,至少我不知道如何打印出这样的上下文。听起来绝对是非常有用的东西。但我们就在我们所在的地方。以上是关于Azure DevOps Pipelines 中的条件阶段执行的主要内容,如果未能解决你的问题,请参考以下文章
Azure Pipelines 托管代理无法访问 DevOps 项目源
Azure DevOps Pipelines 上的 Android SDK 构建工具
如何在 Azure DevOps Pipelines 上指定 Android SDK 构建工具版本
Azure DevOps -> Pipelines -> Library -> 访问 Azure Key Vault -> Key Vault 不允许从所有网络访问
Azure DevOps Pipelines - 仅在上一次运行成功时运行 YAML 管道
在 Azure DevOps Git 存储库中使用来自 Azure Pipelines 的 Python 包版本标记 Git 存储库