2
votes

For our Terraform Deployment, we use an Azure DevOps pipeline that has 3 stages:

  1. plan
  2. apply (manual approval)
  3. test

For the apply stage we use a deployment job with an environment that has a manual approval (check). What we would like to have is "skipping" the apply and test stage, if the plan stage has shows no changes. Therefore we try to use the following yaml configuration for the apply stage:

  - stage: ApplyShared
    dependsOn: PlanShared
    jobs:
      - job: CheckSharedChanges
        steps:
          - task: DownloadPipelineArtifact@2
            inputs:
              artifactName: TerraformBuild
              downloadPath: $(System.DefaultWorkingDirectory)
          - bash: |
              # using a file for indicating changes in TF plan, since
              # you cannot pass variables between stages in Azure DevOps
              if [ -f ".shared-changes" ]; then
                  echo '##vso[task.setvariable variable=shared_changes]yes'
              fi
            name: Check
      - deployment: ApplyShared
        dependsOn: CheckSharedChanges
        # this condition seems to be ignored, if there is a manual
        # approval on the stage
        condition: eq(dependencies.CheckSharedChanges.outputs['Check.shared_env'], 'yes')
        displayName: 'Apply - shared'
        # we configured a manual approval (check) for this environment,
        # so the pipeline stops and asks for an operator to approve the deployment
        environment: 'infra-shared'

According to this issue on the MS Developer Community, a condition on a stage with an approval is not checked before the approval, so the approach does not work.

My question is: do you know any other way to implement this?

Edit

There now exists a hacky workaround for this issue, see this SO post

2

2 Answers

2
votes

A stage can consist of many jobs, and each job can consume several resources. Before the execution of a stage can begin, all checks on all the resources used in that stage must be satisfied. Azure Pipelines pauses the execution of a pipeline prior to each stage, and waits for all pending checks to be completed. That's why the condition doesn't work in your scenario. Check more information here:

https://docs.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&tabs=check-pass

There is already a similar idea on roadmap, you may track the following link:

https://developercommunity.visualstudio.com/idea/697467/manually-triggered-stages-in-yaml-multi-stage-pipe.html

Currently, you may consider starting a manual run and skip a few stages in your pipeline:

enter image description here

0
votes

This is now available: https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/manual-validation?view=azure-devops&tabs=yaml

- task: ManualValidation@0
  timeoutInMinutes: 1440 # task times out in 1 day
  inputs:
    notifyUsers: |
      [email protected]
      [email protected]
    instructions: 'Please validate the build configuration and resume'
    onTimeout: 'resume'

The onTimeout can also be set to reject. If this is inserted the stage/job will be in a pending state until someone goes in and reviews where the instructions will be on the screen. Will be very close to what the class releases offered for the manual intervention task. This task is only available in YAML pipelines.