Sharing templates seems like a really simple thing to want to do especially when you have similar projects that use the same steps to build or deploy code. In this post I am going to go through how does Azure Pipelines support this and how can we version shared templates.
As a C# developer I build code the same way in multiple projects, I use GitVersion for versioning my code and the DotNetCoreCLI tasks to restore, build and publish my code into and artifact, for example
steps:
- task: gitversion/setup@0
displayName: 'Install GitVersion'
inputs:
versionSpec: '5.x'
- task: gitversion/execute@0
displayName: 'Determine Version'
inputs:
additionalArguments: '/updateprojectfiles'
- task: DotNetCoreCLI@2
displayName: 'Restore Packages'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build Code'
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--no-restore --configuration release'
- task: DotNetCoreCLI@2
displayName: 'Publish Code'
inputs:
command: 'publish'
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/release'
projects: 'src/**/*.csproj'
publishWebProjects: false
modifyOutputPath: false
zipAfterPublish: true
- publish: '$(Build.ArtifactStagingDirectory)'
displayName: 'Publish App Artifact'
artifact: 'myapp'
There is probably a dozen projects/repositories where this exists now and say I wanted to add a security scan to all my projects that may take some time. A shared template would allow this to be maintained and updated in one place.
So how can we create a shared template that is used across multiple repositories in Azure DevOps?
Firstly we need to create a repository that contains the shared template code, I called my repository ‘shared-templates’, I added a folder called ‘code’ and added the above code into a template called ‘build-code.yml’ and added a parameter to pass in the name of the artifact
parameters:
- name: artifactName
type: string

Now I have added the first version of the code I am going to tag the repo with a version

The shared templates repository is now ready for use, let’s update a pipeline to now use this. The current pipeline looks something like this:
trigger: none
pool:
vmImage: 'ubuntu-latest'
steps:
- task: gitversion/setup@0
displayName: Install GitVersion
inputs:
versionSpec: '5.x'
- task: gitversion/execute@0
displayName: Determine Version
inputs:
additionalArguments: '/updateprojectfiles'
- task: DotNetCoreCLI@2
displayName: Restore Packages
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: Build Code
inputs:
command: build
projects: '**/*.csproj'
arguments: '--no-restore --configuration release'
- task: DotNetCoreCLI@2
displayName: Publish Code
inputs:
command: publish
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/release'
projects: 'src/**/*.csproj'
publishWebProjects: false
modifyOutputPath: false
zipAfterPublish: true
- publish: '$(Build.ArtifactStagingDirectory)'
displayName: 'Publish App Artifact'
artifact: 'myapp'
In order to use the external repository we need to add a resources section to the pipeline to look for the shared-templates repository and which branch to look at
resources:
repositories:
- repository: templates
type: git
name: shared-templates
ref: main
The next thing is to replace all the previous steps with a template step and then tag the repository with the version from GitVersion
trigger: none
pool:
vmImage: 'ubuntu-latest'
resources:
repositories:
- repository: templates
type: git
name: shared-templates
ref: main
steps:
- template: 'code/build-code.yml@templates'
parameters:
artifactName: 'myapp'
- bash: |
git tag $(SemVer)
echo 'Created tag'
git push --tags
echo 'tags pushed'
displayName: 'Creating Tag'
This will get the latest version of the shared-templates when it is ran, if we wanted to get a specific version we can reference a tag like one we created earlier. The above would then become
trigger: none
pool:
vmImage: 'ubuntu-latest'
resources:
repositories:
- repository: templates
type: git
name: shared-templates
ref: ref/tags/v1.0
steps:
- template: 'code/build-code.yml@templates'
parameters:
artifactName: 'myapp'
- bash: |
git tag $(SemVer)
echo 'Created tag'
git push --tags
echo 'tags pushed'
displayName: 'Creating Tag'
And that’s it, a way of sharing templates that can be used in multiple projects and can also be versioned to mitigate breaking changes in shared code.
I hope this has been useful, it’s certainly a technique I will be using more of in my Azure Pipelines.
One thought on “Azure Pipelines – Shared Templates and Versioning”
Comments are closed.