When the number of YAML pipelines you work with in Azure DevOps increases, you might find the need for centralizing some parts of the configuration variables for your pipeline(s). Maybe some configuration that is shared between multiple application components or even some values that are shared between multiple teams or managed by a central team.

To make this happen, you might be tempted to do either one of the following:

  1. Copy the configuration variables to every individual pipeline. The disadvantage of this is that you are now copying these values around and if one of them changes, this gives a lot of work and the risk of missing one or more of the necessary updates
  2. Use variable groups that you know from the Classic Build and Release definitions to manage central configuration. But if you do this, you loose some of the benefits of pipelines-as-code again.

Luckily there is now an alternative available, by combining some of the new YAML Pipelines features, namely variable templates and repository resources. In this post I want to share how I built a solution where configuration variables were centralized in one repository and used them from YAML pipelines in other repositories.

Let’s start by assuming that you have a number of pipelines, that all look somewhat like this:

pool:
  name: 'Azure Pipelines'
  vmImage: windows-latest

variables:
- allCompanyVariable: someValue
- allComponentsVariable: someValue

steps:
  - script: |
    echo $(allCompanyVariable)
    echo $(allComponentsVariable)

Of course the repetition is in these two variables and we want to centralize them out into some kind of configuration. To do this, I created a new repository named Shared-Configuration. In this repository I added a directory configuration with two files all-company.yml and my-department.yml, containing configuration values that need to be shared with multiple pipelines across multiple repositories.

These files are very straight forward and look like this:

variables:
  allCompanyVariable: someCompanyWideThingy
  foo: bar
To use these values, we have to update the dependent pipelines. First we have to add a repository resource declaration. Here we specify that we want to pull another Git repository into the scope of our builds and want to be able to reference files from it. We do this by adding the following YAML at the top of our pipeline:
resources:
  repositories:
  - repository: sharedConfigurationRepository
    type: git
    name: Shared-Configuration
This means that the repository Shared-Configuration is pulled into the scope of our pipeline and can be referenced using the identifier sharedConfigurationRepository. With that the repository is in scope, we can reference variable template files that are in this repository as follows:
variables:
- template: configuration/all-company.yml@sharedConfigurationRepository
- template: configuration/my-department.yml@sharedConfigurationRepository

Here we again declare variables, but instead of specifying key/value pairs we are now pulling in all variables from the referenced files. To do this, the full path to the file has to be specified along with a the identifier of the repository that holds this file. If the @-sign and the identifier are omitted, the path is assumed to be in the same repository as the pipeline definition.

Putting all of this together, the following syntax can be used for pulling variables defined in other, shared repositories into your YAML pipeline:

pool:
  name: 'Azure Pipelines'
  vmImage: windows-latest


resources:
  repositories:
  - repository: sharedConfigurationRepository
    type: git
    name: Shared-Configuration


variables:
- template: configuration/all-company.yml@sharedConfigurationRepository
- template: configuration/my-department.yml@sharedConfigurationRepository


steps:
- script: |
    echo $(allCompanyVariable)
    echo foo value is $(foo)

 

Happy coding!

Resources: