azure-devopsyamlazure-pipelinescontinuous-deploymentazure-pipelines-yaml

Azure Pipelines using YAML for multiple environments (stages) with different variable values but no YAML duplication


Let's suppose I have 3 environments on Azure: Dev, Test and Prod. I have the same pipeline for building and deploying the resources and the code for each one of the environments except for two differences:

What is the correct approach for this scenario? Because at least 3 come to my mind, none of which is perfect:

Option 1: I guess I could create a single pipeline on Azure DevOps (triggered by any of 3 branches) with 3 stages for each environment and for each stage add a condition to run depending on the source branch, like this:

condition: eq(variables['Build.SourceBranch'], 'refs/heads/a-branch-name')

and in each stage reference different variables. But this would introduce code duplication in each stage - when adding or modifying a step I would have to remember to edit 3 stages - not desirable.

Option 2: Create 3 separate YAML files in my repository, each one of them with specified trigger branch and referencing the same variable names, then create 3 different pipeline on Azure DevOps, each one of them with different variable values. But this would also introduce code duplication.

Option 3: Create 1 build-and-deploy.yaml file as a template with the steps defined in it and then create another 3 YAML files referring to that template, each with different trigger branch and with different variable values in each Azure Pipeline, like this:

trigger:
  branches:
    include:
    - a-branch-name

steps:
- template: build-and-deploy.yaml
  parameters:
      parameterName1: $(parameterValue1)
      parameterName2: $(parameterValue2)

This seems to be the best option but I haven't seen it used anywhere in the examples so maybe I'm just unaware of downsides of it, if there are any.


Solution

  • Here's how to do it with a shared pipeline config that gets included into env-specific pipelines.

    To support 2 environments (dev and prod) you'd need:

    pipeline-shared.yml:

    variables:
      ARTIFACT_NAME: ApiBuild
      NPM_CACHE_FOLDER: $(Pipeline.Workspace)/.npm
    
    stages:
      - stage: Build
        displayName: Build
        pool:
          vmImage: 'ubuntu-latest'
          demands: npm
        jobs:
          ...
    
      - stage: Release
        displayName: Release
        dependsOn: Build
        pool:
          vmImage: 'ubuntu-latest'
        jobs:
          ...
    

    pipeline-dev.yml:

    # Trigger builds on commits to branches
    trigger:
      - dev
    
    # Do not trigger builds on PRs
    pr: none
    
    extends:
      template: pipeline-shared.yml
    

    pipeline-prod.yml

    trigger:
      - master
    
    pr: none
    
    extends:
      template: pipeline-shared.yml