skip to Main Content

I am experiencing an issue with my deployment pipeline where the final ‘apply’ stage does not trigger, even though there are no explicit dependencies or conditions set to control its execution. Below is an overview of the template I use to deploy each environment:

Pipeline:

trigger:
  batch: true
  branches:
    include:
      - main

pr:
  branches:
    include:
      - main

stages:
- template: templates/deploy.yml
  parameters:
    environment: Dev

- template: templates/deploy.yml
  parameters:
    environment: Uat

- template: templates/deploy.yml
  parameters:
    environment: Prd

Template:

stages:
- stage: Terraform_Plan_${{ parameters.environment }}
  displayName: Plan
  condition: always()
  jobs:
  - job: Terraform_Plan_${{ parameters.environment }}
    displayName: Plan Terraform
    pool: 'selfhosted'
    steps:

    - powershell: |
          # set it to true or false
          Write-Host "##vso[task.setvariable variable=anyTfChanges;isOutput=true]true"

      displayName: Detect any Terraform changes
      name: anyTfChanges


- stage: Any_Tf_Changes_${{ parameters.environment }}
  displayName: Terraform Changes
  dependsOn: Terraform_Plan_${{ parameters.environment }}
  variables:
     anyTfChanges: $[ stageDependencies.Terraform_Plan_${{ parameters.environment }}.Terraform_Plan_${{ parameters.environment }}.outputs['anyTfChanges.anyTfChanges'] ]
  condition: and(eq('true', 'true'), eq(dependencies.Terraform_Plan_${{ parameters.environment }}.outputs['Terraform_Plan_${{ parameters.environment }}.anyTfChanges.anyTfChanges'], 'true'))
 
  jobs:
    - job: Terraform_Changes_${{ parameters.environment }}
      displayName: Detect Terraform Changes
      steps:
      - checkout: none
      - powershell: |
          Write-Host "hello world"
        displayName: Terraform changes detected

- stage: Terraform_Apply_${{ parameters.environment }}
  displayName: Apply ${{ parameters.environment }}
  jobs:
  - deployment: Apply
    environment: ${{ parameters.environmentDisplayName }}
    displayName: Apply Terraform
    pool: 'selfhosted'
    strategy:
      runOnce:
        deploy:
          steps:
          - checkout: self
          - script: |
              Write-Host "hello world"

Despite the configuration, the last ‘apply’ stage does not run in last prd stages:

enter image description here

Does anyone know why this might be happening or what I might be missing in the configuration that prevents this stage from running?

Thanks in advance for any help or insights!

2

Answers


  1. Refer this MS doc: Specify conditions, it says: The default condition for a stage is condition: succeeded()

    If any of the parent stages do not succeed, then all the child stages are skipped, except for those where conditions are specified and evaluate to true. That’s why in your case, the stage "Plan" always runs, the stage "Terraform Changes" runs whenever "anyTfChanges" is true, the last stage "Apply" runs only when all the previous stages have succeeded as there is no condition specified. Since in your case, not all the previous stages are green, the final "Apply" stage is getting skipped..

    So try adding the same condition condition: and(eq('true', 'true'), eq(dependencies.Terraform_Plan_${{ parameters.environment }}.outputs['Terraform_Plan_${{ parameters.environment }}.anyTfChanges.anyTfChanges'], 'true')) in the "Apply" stage as well, as shown below:

    stages:
    - stage: Terraform_Plan_${{ parameters.environment }}
      displayName: Plan
      condition: always()
      jobs:
      - job: Terraform_Plan_${{ parameters.environment }}
        displayName: Plan Terraform
        pool: 'selfhosted'
        steps:
    
        - powershell: |
              # set it to true or false
              Write-Host "##vso[task.setvariable variable=anyTfChanges;isOutput=true]true"
    
          displayName: Detect any Terraform changes
          name: anyTfChanges
    
    
    - stage: Any_Tf_Changes_${{ parameters.environment }}
      displayName: Terraform Changes
      dependsOn: Terraform_Plan_${{ parameters.environment }}
      variables:
         anyTfChanges: $[ stageDependencies.Terraform_Plan_${{ parameters.environment }}.Terraform_Plan_${{ parameters.environment }}.outputs['anyTfChanges.anyTfChanges'] ]
      condition: and(eq('true', 'true'), eq(dependencies.Terraform_Plan_${{ parameters.environment }}.outputs['Terraform_Plan_${{ parameters.environment }}.anyTfChanges.anyTfChanges'], 'true'))
     
      jobs:
        - job: Terraform_Changes_${{ parameters.environment }}
          displayName: Detect Terraform Changes
          steps:
          - checkout: none
          - powershell: |
              Write-Host "hello world"
            displayName: Terraform changes detected
    
    - stage: Terraform_Apply_${{ parameters.environment }}
      displayName: Apply ${{ parameters.environment }}
      condition: and(eq('true', 'true'), eq(dependencies.Terraform_Plan_${{ parameters.environment }}.outputs['Terraform_Plan_${{ parameters.environment }}.anyTfChanges.anyTfChanges'], 'true'))
      jobs:
      - deployment: Apply
        environment: ${{ parameters.environment }}
        displayName: Apply Terraform
        pool: 'selfhosted'
        strategy:
          runOnce:
            deploy:
              steps:
              - checkout: self
              - script: |
                  Write-Host "hello world"
    
    Login or Signup to reply.
  2. There seems to be some misunderstandings on the YAML pipeline default behaviors. Please note that,

    • Since there are no explicit dependencies set for stage Apply ${{ parameters.environment }}, by default, it depends on the stage just before it in the YAML file.
    • Since there are no explicit conditions set for stage Apply ${{ parameters.environment }}, it will use the default condition, which means this stage runs if all direct and indirect dependencies have succeeded, as if you specified condition: succeeded().
    • In addition, when you specify your own condition property for a stage / job / step, you overwrite its default condition: succeeded(). Therefore, you may consider adding the same condition in stage Apply ${{ parameters.environment }} as that you defined for stage Any_Tf_Changes_${{ parameters.environment }}.
    • Furthermore, please also make sure you take into account the state of the parent stage Apply ${{ parameters.environment }} when writing your own conditions, since overwriting the default condition can lead to your stage running even if the build is cancelled or failed.
      enter image description here

    With those being said, if your actual expectation is to run the stage Terraform_Apply_${{ parameters.environment }} only if the stage Any_Tf_Changes_${{ parameters.environment }} is succeeded. You can try adding the expression eq(dependencies.Any_Tf_Changes_${{ parameters.environment }}.result, 'Succeeded') in the condition of the apply stage. Here is the part of stage Terraform_Apply_${{ parameters.environment }} of the YAML pipeline for your reference.

    - stage: Terraform_Apply_${{ parameters.environment }}
      displayName: Apply ${{ parameters.environment }}
      condition: and(
          eq('true', 'true'),
          eq(dependencies.Terraform_Plan_${{ parameters.environment }}.outputs['Terraform_Plan_${{ parameters.environment }}.anyTfChanges.anyTfChanges'], 'true'),
          eq(dependencies.Any_Tf_Changes_${{ parameters.environment }}.result, 'Succeeded')
        )
      variables:
        anyTfChanges: $[ stageDependencies.Terraform_Plan_${{ parameters.environment }}.Terraform_Plan_${{ parameters.environment }}.outputs['anyTfChanges.anyTfChanges'] ]
        deps: $[convertToJson(dependencies)]
        stageDeps: $[convertToJson(stageDependencies)]
      jobs:
      - deployment: Apply
        environment: ${{ parameters.environmentDisplayName }}
        displayName: Apply Terraform
        # pool: 'selfhosted'
        strategy:
          runOnce:
            deploy:
              steps:
              - checkout: self
              - powershell: |
                  Write-Host "hello world"
                  Write-Host "$(anyTfChanges)"
                  Write-Host "deps is $(deps)"
                  Write-Host "stageDeps is $(stageDeps)"
    

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search