即使前一个作业被跳过,Azure Pipelines也不会跳过后续的作业

人工智能 2026-07-10

我试着通过谷歌搜索和咨询AI,但似乎还是搞不清楚以下问题。

我有一个流水线,依次是 Build -> Detect IaC changes -> IaC -> Deploy Dev/Test。其中IaC(Infrastructure as Code,基础设施即代码)正在部署Azure DevOps资源。你大概也能猜到,我只想在确实有变更时才部署IaC,因为这会额外花费几分钟。这个逻辑已经实现,但我遇到的问题是:如果 Detect IaC changes 判断没有IaC变更,因此跳过 IaC 这个作业,那么后续的流水线 Deploy Dev/Test 也会被跳过……其实不应该。

我的主流水线大致如下:

jobs:
  - template: '../../../infra/devops/deploy-azure-resources.yml'
    parameters:
      ...
      forceIaC: ${{ parameters.forceIaC }}
  - template: '../../../infra/devops/deploy-app-service.yml'
    parameters:
      dependsOn: ['iac']
      ...
      appName: ${{variables.appName}}
      useDeploymentSlots: true

deploy-azure-reosurces.yml 看起来大致如下:

jobs:
  - job: detect_iac_changes
    displayName: 'Detect IaC changes'
    steps:
      - checkout: self
        fetchDepth: 2

      - task: PowerShell@2
        name: detection
        displayName: 'Detect bicep file changes'
        inputs:
          targetType: 'inline'
          script: |
            if ('${{ parameters.forceIaC }}' -eq 'true') {
              Write-Host "ForceIaC is enabled. Skipping detection."
              Write-Host "##vso[task.setvariable variable=shouldDeployIaC;isOutput=true]true"
              return
            }

            $bicepChanges = git diff --name-only HEAD~1 HEAD | Where-Object { $_ -eq '${{ parameters.bicepFile }}' }

            if ($bicepChanges) {
              Write-Host "Bicep file '${{ parameters.bicepFile }}' has changed."
              Write-Host "##vso[task.setvariable variable=shouldDeployIaC;isOutput=true]true"
            } else {
              Write-Host "No changes detected in '${{ parameters.bicepFile }}'. Skipping deployment."
              Write-Host "##vso[task.setvariable variable=shouldDeployIaC;isOutput=true]false"
            }

  - job: iac
    displayName: 'Deploy IaC'
    dependsOn: detect_iac_changes
    condition: eq(dependencies.detect_iac_changes.outputs['detection.shouldDeployIaC'], 'true')
    steps:
      - checkout: self

      - task: AzureResourceManagerTemplateDeployment@3
        displayName: 'Run bicep file'
        inputs:
          deploymentScope: 'Subscription'
          connectedServiceName: '${{ parameters.serviceConnection }}'
          location: 'westeurope'
          csmFile: '${{ parameters.bicepFile }}'
          overrideParameters: '-environmentCode ${{ parameters.environmentCode }}'

      - task: PowerShell@2
        displayName: 'Purge Cache'
        inputs:
          targetType: 'inline'
          script: |
            az cache purge

deploy-app-service.yml 看起来大致如下:

parameters:
  - name: dependsOn
    type: object
    default: []
  - name: environmentName
    displayName: 'Environment name'
    default: ''
  - name: jobName
    displayName: 'Name of the deployment job'
    default: 'deploy'

jobs:
  - deployment: ${{ parameters.jobName }}
    environment: ${{ parameters.environmentName }}
    dependsOn: ${{ parameters.dependsOn }}
    strategy:
      runOnce:
...

我猜这与 dependsOn: ['iac'] 有关,但我并不确定需要做出哪些不同的改动,才能让被跳过的作业也被视作依赖来“接受”?

解决方案

我在你分享的流水线代码中没有看到任何条件。

要实现这一点,你需要使用 condition 属性。

下面我给出主流水线及用于提供条件执行值的子流水线:

return-false.yml

jobs:
- job: ReturnFalse
  steps:
  - bash: |
      echo "##vso[task.setvariable variable=result;isOutput=true]false"
    name: setOutput

return-true.yml

jobs:
- job: ReturnTrue
  steps:
  - bash: |
      echo "##vso[task.setvariable variable=result;isOutput=true]true"
    name: setOutput

dummy.yml

steps:
- bash: |
    echo 'Dummy hello world'
  name: dummyPrint

main.yml - 这个文件使用上述文件,然后按条件执行作业或其他流水线脚本:

trigger: none

jobs:
- template: return-true.yml

- job: Step1
  dependsOn: ReturnTrue
  variables:
    shouldRun: $[ dependencies.ReturnTrue.outputs['setOutput.result'] ]

  steps:
  - bash: echo "This runs only when value is true - should be printed"
    condition: eq(variables['shouldRun'], 'true')

  - bash: echo "This step always runs"

- job: DummyConditionalStepShouldRun
  dependsOn: Step1
  condition: eq(dependencies.ReturnTrue.outputs['setOutput.result'], 'true')
  steps:
  - template: dummy.yml

- template: return-false.yml

- job: Step2
  dependsOn: ReturnFalse
  variables:
    shouldRunForStep2: $[ dependencies.ReturnFalse.outputs['setOutput.result'] ]

  steps:
  - bash: echo "This runs only when value is true - should NOT be printed"
    condition: eq(variables['shouldRunForStep2'], 'true')

  - bash: echo "This step always runs"

- job: DummyConditionalStepShouldNOTRun
  dependsOn: Step2
  condition: eq(dependencies.ReturnFalse.outputs['setOutput.result'], 'true')
  steps:
  - template: dummy.yml

- job: AlwaysRunJob
  dependsOn: [Step2, Step1]
  condition: always()
  steps:
  - bash: echo "This job always runs"

为了完整起见,你也可以互换使用 if

parameters:
- name: message
  type: string

steps:
- script: echo Hello ${{parameters.message}}

- ${{ if ne(parameters.message, 'Production') }}:
  - script: |
      echo This step only runs if parameter passed was different than 'Production'
- script: |
      echo This step only runs if parameter passed was different than 'Production'
  condition: ne('${{ parameters.message }}', 'Production')

编辑

在你更新之后,下面是对我有用的设置。在你的脚本中,我没有看到主文件中声明参数:

parameters:
- name: testFlag
  type: string

对我有用的一个示例:

jobs:
  - job: check_flag
    displayName: 'Check flag'
    steps:
      - task: PowerShell@2
        name: check
        displayName: 'Check flag'
        inputs:
          targetType: 'inline'
          script: |
            if ('${{ parameters.testFlag }}' -eq 'true') {
              Write-Host "param is true: ${{ parameters.testFlag }}"
            } else {
              Write-Host "param is different from true: ${{ parameters.testFlag }}"
            }

以及来自 main.yml 的用法

parameters:
- name: testFlag
  type: string

...

- template: dummy-with-param.yml
  parameters:
    testFlag: ${{ parameters.testFlag }}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章