Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Azure DevOps Server 2019
Use templates to define your logic once and then reuse it several times. Templates combine the content of multiple YAML files into a single pipeline. You can pass parameters into a template from your parent pipeline.
Extend from a template
Insert a template
Extend from a template and use an include template with variables
One common scenario is to have a pipeline with stages for development, testing, and production that uses both an includes template for variables and an extends template for stages and jobs.
In the following example, variables-template.yml
defines a set of virtual machine variables that are then used in azure-pipeline.yml
.
# variables-template.yml
variables:
- name: devVmImage
value: 'ubuntu-latest'
- name: testVmImage
value: 'ubuntu-latest'
- name: prodVmImage
value: 'ubuntu-latest'
The following file, stage-template.yml
defines a reusable stage configuration with three parameters (name
, vmImage
, steps
) and a job named Build
.
# stage-template.yml
parameters:
- name: name
type: string
default: ''
- name: vmImage
type: string
default: ''
- name: steps
type: stepList
default: []
stages:
- stage: ${{ parameters.name }}
jobs:
- job: Build
pool:
vmImage: ${{ parameters.vmImage }}
steps: ${{ parameters.steps }}
The following pipeline, azure-pipelines.yml
, imports variables from variables-template.yml
, and then uses the stage-template.yml
template for each stage. Each stage (Dev, Test, Prod) is defined with the same template but with different parameters, leading to consistency across stages while allowing for customization. The 'Prod' stage includes an environment variable as an example of something you might use for authentication. To learn more about defining parameters, see Template parameters.
# azure-pipelines.yml
trigger:
- main
variables:
- template: variables-template.yml
stages:
- template: stage-template.yml
parameters:
name: Dev
vmImage: ${{ variables.devVmImage }}
steps:
- script: echo "Building in Dev"
- template: stage-template.yml
parameters:
name: Test
vmImage: ${{ variables.testVmImage }}
steps:
- script: echo "Testing in Test"
- template: stage-template.yml
parameters:
name: Prod
vmImage: ${{ variables.prodVmImage }}
steps:
- script: echo "Deploying to Prod"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
Reference template paths
Template paths can be an absolute path within the repository or relative to the file that does the including.
To use an absolute path, the template path must start with a /
. All other paths are considered relative.
Here's an example nested hierarchy.
|
+-- fileA.yml
|
+-- dir1/
|
+-- fileB.yml
|
+-- dir2/
|
+-- fileC.yml
Then, in fileA.yml
you can reference fileB.yml
and fileC.yml
like this.
steps:
- template: dir1/fileB.yml
- template: dir1/dir2/fileC.yml
If fileC.yml
is your starting point, you can include fileA.yml
and fileB.yml
like this.
steps:
- template: ../../fileA.yml
- template: ../fileB.yml
When fileB.yml
is your starting point, you can include fileA.yml
and fileC.yml
like this.
steps:
- template: ../fileA.yml
- template: dir2/fileC.yml
Alternatively, fileB.yml
could refer to fileA.yml
and fileC.yml
using absolute paths like this.
steps:
- template: /fileA.yml
- template: /dir1/dir2/fileC.yml
Store templates in other repositories
You can keep your templates in other repositories. For example, suppose you have a core pipeline that you want all of your app pipelines to use. You can put the template in a core repo and then refer to it from each of your app repos:
# Repo: Contoso/BuildTemplates
# File: common.yml
parameters:
- name: 'vmImage'
default: 'ubuntu-22.04'
type: string
jobs:
- job: Build
pool:
vmImage: ${{ parameters.vmImage }}
steps:
- script: npm install
- script: npm test
Now you can reuse this template in multiple pipelines.
Use the resources
specification to provide the location of the core repo.
When you refer to the core repo, use @
and the name you gave it in resources
.
# Repo: Contoso/LinuxProduct
# File: azure-pipelines.yml
resources:
repositories:
- repository: templates
type: github
name: Contoso/BuildTemplates
jobs:
- template: common.yml@templates # Template reference
# Repo: Contoso/WindowsProduct
# File: azure-pipelines.yml
resources:
repositories:
- repository: templates
type: github
name: Contoso/BuildTemplates
ref: refs/tags/v1.0 # optional ref to pin to
jobs:
- template: common.yml@templates # Template reference
parameters:
vmImage: 'windows-latest'
For type: github
, name
is <identity>/<repo>
as in the preceding example.
For type: git
(Azure Repos), name
is <project>/<repo>
.
If that project is in a separate Azure DevOps organization, you need to configure a service connection of type Azure Repos/Team Foundation Server
with access to the project and include that in YAML:
resources:
repositories:
- repository: templates
name: Contoso/BuildTemplates
endpoint: myServiceConnection # Azure DevOps service connection
jobs:
- template: common.yml@templates
Repositories are resolved only once, when the pipeline starts up. After that, the same resource is used during the pipeline run. Only the template files are used. Once the templates are fully expanded, the final pipeline runs as if it were defined entirely in the source repo. This means that you can't use scripts from the template repo in your pipeline.
If you want to use a particular, fixed version of the template, be sure to pin to a ref
.
The refs
are either branches (refs/heads/<name>
) or tags (refs/tags/<name>
).
If you want to pin a specific commit, first create a tag pointing to that commit, then pin to that tag.
Note
If no ref
is specified, the pipeline defaults to using refs/heads/main
.
You can also pin to a specific commit in Git with the SHA value for a repository resource. The SHA value is a 40-character checksum hash that uniquely identifies the commit.
resources:
repositories:
- repository: templates
type: git
name: Contoso/BuildTemplates
ref: 1234567890abcdef1234567890abcdef12345678
You can also use @self
to refer to the repository where the original pipeline was found.
This is convenient for use in extends
templates if you want to refer back to contents in the extending pipeline's repository.
For example:
# Repo: Contoso/Central
# File: template.yml
jobs:
- job: PreBuild
steps: []
# Template reference to the repo where this template was
# included from - consumers of the template are expected
# to provide a "BuildJobs.yml"
- template: BuildJobs.yml@self
- job: PostBuild
steps: []
# Repo: Contoso/MyProduct
# File: azure-pipelines.yml
resources:
repositories:
- repository: templates
type: git
name: Contoso/Central
extends:
template: template.yml@templates
# Repo: Contoso/MyProduct
# File: BuildJobs.yml
jobs:
- job: Build
steps: []
FAQ
How can I use variables inside of templates?
There are times when it's useful to set parameters to values based on variables. Parameters are expanded early in processing a pipeline run so not all variables are available. To see what predefined variables are available in templates, see Use predefined variables.
In this example, the predefined variables Build.SourceBranch
and Build.Reason
are used in conditions in template.yml.
# File: azure-pipelines.yml
trigger:
- main
extends:
template: template.yml
# File: template.yml
steps:
- script: echo Build.SourceBranch = $(Build.SourceBranch) # outputs refs/heads/main
- script: echo Build.Reason = $(Build.Reason) # outputs IndividualCI
- ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}:
- script: echo I run only if Build.SourceBranch = refs/heads/main
- ${{ if eq(variables['Build.Reason'], 'IndividualCI') }}:
- script: echo I run only if Build.Reason = IndividualCI
- script: echo I run after the conditions