Azure DevOps Pipeline Templates and External Repositories

Working with Azure DevOps you can use YAML to create the build and deployment pipelines. To make this easier and more repeatable you can also use something called templates. However, if you want to use them in multiple repositories you don’t want to repeat yourself. There is a method to get these shared as I will demo below.

When I format my folders for holding the YAML files, I like to mirror how they were built in the UI editor in Azure DevOps website. That is with Tasks like DotNetCli and Group Tasks that are a collection of Tasks to complete a job like Build Dotnet Core Application.

DevOps
–Tasks
—-DotNetCli.yml
–GroupTasks
—-BuildDotnetApp.yml

In this method the ‘BuildDotnetApp.yml’ would inherit the ‘DotNetCli.yml’ and other Group Tasks could also inherit it as well. This makes them more reusable and dynamic, plus easier to upgrade if you need to change a Task version or add a new parameter.

This would be the Dot Net Core CLI Task:

parameters:
  diplayName: 'DotNetCoreCLI'
  projects: ''
  arguments: ''
  command: build
  customScript: ''
  continueOnError: false

steps:
- task: DotNetCoreCLI@2
  displayName: ${{parameters.diplayName}}
  inputs:
    publishWebProjects: false
    command: ${{parameters.command}}
    projects: ${{parameters.projects}}
    arguments: ${{parameters.arguments}}
    zipAfterPublish: false
    custom: ${{parameters.customScript}}
    continueOnError: ${{parameters.continueOnError}}

And can then be called in like below. Remember that the folder path is relative to where this file is hosted.

steps:
- template: ../Tasks/_DotNetCoreCLI.yml
  parameters:
    diplayName: 'Restore .NetCore Projects'
    projects:  '**/MicroServices/**/*.API.csproj'
    arguments: '--packages $(Build.SourcesDirectory)\packages'
    command: restore

- template: ../Tasks/_DotNetCoreCLI.yml
  parameters:
    diplayName: 'Build .NetCore Projects'
    projects:  '**/*.csproj'
    arguments: '--configuration $(BuildConfiguration) --output $(Build.SourcesDirectory)\bin\$(BuildConfiguration)'
    command: build

You can read more on using templates in the Azure DevOps Documentation.
https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops

Now we have these great reusable templates, we don’t want them sitting in a multiple repository to then be maintained in multiple times.

The idea here would to move these files to a single repository for example ‘deployment-files’, which will contain all them files to then be referenced later.

The first thing we need to do is reference this new repository in the applications pipeline file. Below is a standard azure pipeline file for building the dotnet application. It has array of stages with the first stage being the CI Build, a single job and the default agent pool.

stages:
  - stage: 'CIBuild'
    displayName: 'CI  Service'
    jobs:
      - job: CI_Service
        displayName: CI Service
        continueOnError: false
        pool:
          displayName: "CI Service"
          name: Default
        workspace:
          clean: all
        timeoutInMinutes: 120
        cancelTimeoutInMinutes: 2
        steps:

To add a reference to another repository you will need to add the following to the top of the file.

This reference will have a alias name, type of repository, location to the repository and a reference to the git branch reference as below.

resources:
  repositories:
    - repository: DeploymentTemplates #alias name
      type: git #type of repository
      name: deployment-files #repository name
      ref: 'refs/heads/main' #git branch reference

This is making a reference to another Azure DevOps Repository in the same Organisation, which might work for some setup, but others might have them in different repositories or different vendors like GitHub. The other alternative to this method above is you might want to get the reference from a Pipeline Artifacts after a build, which you can also do by following the instructions in this documentation. https://docs.microsoft.com/en-us/azure/devops/pipelines/process/resources?view=azure-devops&tabs=schema

With this reference, it means you have access to the repository, but it doesn’t do a git pull as far as I could tell. This might just be for repositories in the same system like Azure DevOps, but it does make things simple as your not download more resources when running the pipeline.

Now you have access to the repository you can call upon the templates in the same method as you normally would with once slight change. You need to reference the file relative to the location it is in the deployment files repository, not the current applications. The other part is you need to add ‘@alias name’ to the end of the path, so it knows where to get the files from. For our example it would look like this.

steps:
- template: DevOps/Tasks/_DotNetCoreCLI.yml@DeploymentTemplates
  parameters:
    diplayName: 'Restore .NetCore Projects'
    projects:  '**/MicroServices/**/*.API.csproj'
    arguments: '--packages $(Build.SourcesDirectory)\packages'
    command: restore

- template: DevOps/Tasks/_DotNetCoreCLI.yml@DeploymentTemplates
  parameters:
    diplayName: 'Build .NetCore Projects'
    projects:  '**/*.csproj'
    arguments: '--configuration $(BuildConfiguration) --output $(Build.SourcesDirectory)\bin\$(BuildConfiguration)'
    command: build

Notice I am not using  the ‘../Task’, but directly referencing the  path ‘DevOps/Task’. Also I have added the ‘@DeploymentTemplates’ to the end of the path.

Here is the full example.

Deployment Files Repository:
Location = ‘DevOps/Tasks’

parameters:
  diplayName: 'DotNetCoreCLI'
  projects: ''
  arguments: ''
  command: build
  customScript: ''
  continueOnError: false

steps:
- task: DotNetCoreCLI@2
  displayName: ${{parameters.diplayName}}
  inputs:
    publishWebProjects: false
    command: ${{parameters.command}}
    projects: ${{parameters.projects}}
    arguments: ${{parameters.arguments}}
    zipAfterPublish: false
    custom: ${{parameters.customScript}}
    continueOnError: ${{parameters.continueOnError}}



Application Repository:
Location = ‘azurepipeline.yml’

resources:
  repositories:
    - repository: DeploymentTemplates #alias name
      type: git #type of repository
      name: deployment-files #repository name
      ref: 'refs/heads/main' #git branch reference
stages:
  - stage: 'CIBuild'
    displayName: 'CI  Service'
    jobs:
      - job: CI_Service
        displayName: CI Service
        continueOnError: false
        pool:
          displayName: "CI Service"
          name: Default
        workspace:
          clean: all
        timeoutInMinutes: 120
        cancelTimeoutInMinutes: 2
	steps:
	- template: DevOps/Tasks/_DotNetCoreCLI.yml@DeploymentTemplates
	  parameters:
	    diplayName: 'Restore .NetCore Projects'
	    projects:  '**/MicroServices/**/*.API.csproj'
	    arguments: '--packages $(Build.SourcesDirectory)\packages'
	    command: restore
	
	- template: DevOps/Tasks/_DotNetCoreCLI.yml@DeploymentTemplates
	  parameters:
	    diplayName: 'Build .NetCore Projects'
	    projects:  '**/*.csproj'
	    arguments: '--configuration $(BuildConfiguration) --output $(Build.SourcesDirectory)\bin\$(BuildConfiguration)'
	    command: build


Published by Chris Pateman - PR Coder

A Digital Technical Lead, constantly learning and sharing the knowledge journey.

Leave a message please

This site uses Akismet to reduce spam. Learn how your comment data is processed.