azure-devopsazure-pipelinesazure-yaml-pipelines

Azure DevOps Pipelines - calling yaml template from stages


I've been trying to implement as per this blog post

I have created a template yaml that received the environment name as a single parameter.

I'd like to call this from a yaml pipeline using stages. Hoping to reduce code duplication, with the idea being the outer calling pipeline yaml is quite simple. This is what I have for the caller:

trigger: none

stages:
- stage: dev
  jobs:
  - job: dev
    extends:
      template: templates\365-response.bicep.template.yml
      parameters:
      env: dev
- stage: test
  jobs:
  - job: test
    extends:
      template: templates\365-response.bicep.template.yml
      parameters:
      env: test

My template to be called is:

name: Deploy Bicep files $(Build.BuildId)

parameters:
  - name: env
    type: string

variables:
  location: "uksouth"
  templateFile: "bicep/365Response.main.json"

pool:
  vmImage: "windows-latest"

stages:
  - stage: preDeploy
    jobs:
      - job: listFiles
        displayName: List Files
        pool:
          vmImage: windows-2022

        steps:
          - powershell: echo $(Build.SourcesDirectory)
          - powershell: Get-ChildItem -Path '$(System.DefaultWorkingDirectory)' -recurse

      - job: scanWhatif
        displayName: scan and run whatif
        pool:
          vmImage: windows-2022

        steps:
          - task: AzureCLI@2
            displayName: Preview Bicep Changes
            inputs:
              azureSubscription: "subname-${{parameters.env}}"
              scriptType: "bash"
              scriptLocation: "inlineScript"
              inlineScript: |
                az --version
                az deployment group what-if --resource-group rg-365Response-${{parameters.kbName}}-001 \
                  --template-file '$(System.DefaultWorkingDirectory)\bicep\365Response.main.bicep' \
                  --parameters '$(System.DefaultWorkingDirectory)\bicep\365Response.parameters.${{parameters.kbName}}.json' \

  - stage: Deploy
    displayName: Deploy stage
    dependsOn: Build
    condition: succeeded()
    jobs:
      - deployment: Deploy
        environment: ${{ parameters.env }}
        strategy:
          runOnce:
            deploy:
              steps:
              - task: AzureCLI@2
                displayName: Deploy  Bicep Changes
                inputs:
                  azureSubscription: "subname-${{parameters.env}}"
                  scriptType: "bash"
                  scriptLocation: "inlineScript"
                  inlineScript: |
                    az deployment group create --resource-group rg-365Response-${{parameters.env}}-001 \
                      --template-file '$(System.DefaultWorkingDirectory)\bicep\365Response.main.bicep' \
                      --parameters '$(System.DefaultWorkingDirectory)\bicep\365Response.parameters.${{parameters.env}}.json'

I seem to have the syntax for calling the template wrong?


Solution

  • As per the YAML schema, the extends keyword applies to pipelines, not jobs. The extends keyword is intended as:

    # pipeline.yml
    
    trigger: 
    - main
    
    # these are parameters you show to the user
    parameters:
    - name: parameter1
      type: string
    
    extends:
      template: pipeline-template.yml
      parameters:
        parameter1: ${{ parameters.parameter1 }}
    

    What you trying to do is to create a stage template, but the template you're describing appears to be an entire pipeline.

    You'd want your template to look something like this:

    # template.yml
    
    parameters:
    - name: requiredParameter1
      type: string
      
    - name: optionalParameter1
      type: string
      default: 'default-value'
    
    stages:
    - stage: Deploy
      jobs:
      - job: preDeploy
        pool:
          vmImage: windows-2022
        variables:
          myVariable: '${{ parameters.optionalParameter }}'
          otherVariable: '${{ parameters.requiredParameter }}'
        steps:
        ...
      - job: deploy
        steps:
        ...
    

    And then you'd be able to use it like:

    # pipeline.yml
    
    trigger:
    - main
    
    stages:
    - template: template.yml
      parameters:
        requiredParameter1: value
    
    

    A good way to think of templates is like an include file, but it has to adhere to the schema. At compile time it expands the templates into a single file for execution.

    A few notes about your current "template":

    If you were to remove these elements from your current template, you could use it as a stage template.