skip to Main Content

I have an Azure DevOps pipeline setup with YAML templates shared across multiple repositories. Specifically, I have:

  1. A YAML template file named kv_template.yaml in Repo1 (Project1). This template runs an Azure CLI task that requires a service connection to authenticate with Azure.
  2. Service Connection 1 is configured for Project1 and is used by kv_template.yaml when run directly in Repo1.
  3. Service Connection 2 is configured for Project2 and should be used when kv_template.yaml is called by a pipeline in Repo2 (Project2).

I’ve considered Sharing multiple Service Connections in the Repository where kv_template.yaml is saved, but I’m not sure of the best way to detect or pass which repository/project is calling kv_template.yaml. My ideal solution would dynamically use Service Connection 1 when kv_template.yaml is called within Repo1 and Service Connection 2 when called within Repo2.

My objective is to have kv_template.yaml dynamically select the appropriate service connection based on which repository/pipeline is calling it, without needing to hardcode or duplicate the template file.

Is there a way in Azure DevOps YAML to detect the calling repository or project and use the appropriate Service Connection?

kv_template.yaml script:

- name: parameter1
  type: string
- name: parameter2
  type: string

jobs:
  - job: Job1
    steps:
      - checkout: self
      - task: AzureCLI@2
        inputs:
          azureSubscription: '$(SERVICE_CONNECTION_1)'
          scriptType: 'pscore'
          scriptLocation: 'scriptPath'
          scriptPath: 'helper_scripts/script.ps1'
          arguments: '-WebhookURL "${{ parameters.parameter1 }}" -KeyVaultsToCheck "${{ parameters.parameter2 }}"'
        env:
          GLOBAL_SUBSCRIPTION: $(GLOBAL_SUBSCRIPTION) 
    

2

Answers


  1. My objective is to have kv_template.yaml dynamically select the appropriate service connection based on which repository/pipeline is calling it, without needing to hardcode or duplicate the template file.

    I don’t have enough context to understand how the template is being used, but if you’re referencing the template in different pipelines have you considered replacing the pipeline variable with a parameter for the service connection?

    - name: azureSubscription
      type: string
    
      # other parameters here
    
    jobs:
      - job: Job1
        steps:
          - checkout: self
          - task: AzureCLI@2
            inputs:
              azureSubscription: ${{ parameters.azureSubscription }}
              # ...
    

    Removing the dependency on the pipeline variable improves the reusability of the template IMO.

    I’m not sure of the best way to detect or pass which repository/project is calling kv_template.yaml

    Take a look into the predefined variables.

    Some of these can be used to dynamically load a variables template using template expressions:

    jobs:
      - job: Job1
        variables:
          # reference variables template for the specified project
          - template: /pipelines/variables/${{ variables['System.TeamProject'] }}-variables.yaml
        steps:
          - checkout: self
          - task: AzureCLI@2
            inputs:
              azureSubscription: $(SERVICE_CONNECTION)
              # ...
    

    This means each project would have its own variable templates:

    # /pipelines/variables/foo-variables.yaml
    # variables for project foo
    
    variables:
      - name: SERVICE_CONNECTION
        value: fooServiceConnection
    
      # other variables here
    

    A simpler approach would be to use a condition instead:

    variables:
      ${{ if eq(variables['System.TeamProject'], 'foo') }}:
        SERVICE_CONNECTION: fooServiceConnection
      ${{ elseif eq(variables['System.TeamProject'], 'bar') }}:
        SERVICE_CONNECTION: barServiceConnection
    

    Or, as an alternative:

    variables:
      SERVICE_CONNECTION: ${{ variables['System.TeamProject'] }}ServiceConnection
    
      # result:
      # SERVICE_CONNECTION: fooServiceConnection
    

    Please note that not all predefined variables are available in template expressions (${{ ... }}). For example, the above workarounds work when using variables such as System.TeamProject or Build.SourceBranch but won’t work for Build.Repository.Name (not available at compile time).

    Please see the Available in templates? column in predefined variables to check which variables can be used in template expressions (i.e. at compile time).

    Login or Signup to reply.
  2. The simplest way is using a global pipeline variable to pass the name of ARM service connection to the AzureCLI@2 task in the template kv_template.yaml, and it does not need to detect which repository/project is calling the template.

    See below example as reference:

    1. The template kv_template.yaml in Repo1 in Project1.

      enter image description here

      # kv_template.yaml
      
      parameters:
      - name: parameter1
        type: string
      - name: parameter2
        type: string
      
      jobs:
      - job: job1
        steps:
        - task: AzureCLI@2
          inputs:
            azureSubscription: '$(ARM_Connection)'  # Call the global pipeline variable.
            scriptType: 'pscore'
            scriptLocation: 'scriptPath'
            scriptPath: 'helper_scripts/script.ps1'
            arguments: '-WebhookURL "${{ parameters.parameter1 }}" -KeyVaultsToCheck "${{ parameters.parameter2 }}"'
          env:
            GLOBAL_SUBSCRIPTION: $(GLOBAL_SUBSCRIPTION)
      
    2. The pipeline of Repo1 in Project1.

      enter image description here

      # azure-pipelines.yml
      
      parameters:
      - name: parameter1
        type: string
        default: 'xxxx'
      - name: parameter2
        type: string
        default: 'xxxx'
      
      variables:
        # Define the global pipeline variable.
        # The variable name should be same as that called by AzureCLI@2 task in the template.
        # The value should be the name of Service Connection 1 in Project1.
        ARM_Connection: 'Service_Connection_1'
      
      jobs:
      - template: /templates/kv_template.yaml
        parameters:
          parameter1: ${{ parameters.parameter1 }}
          parameter2: ${{ parameters.parameter2 }}
      
    3. The pipeline of Repo2 in Project2.

      enter image description here

      # azure-pipelines.yml
      
      resources:
        repositories:
        - repository: Repo1
          name: Project1/Repo1
          type: git
          ref: refs/heads/main
      
      parameters:
      - name: parameter1
        type: string
        default: 'xxxx'
      - name: parameter2
        type: string
        default: 'xxxx'
      
      variables:
        # Define the global pipeline variable.
        # The variable name should be same as that called by AzureCLI@2 task in the template.
        # The value should be the name of Service Connection 2 in Project2.
        ARM_Connection: 'Service_Connection_2'
      
      jobs:
      - template: /templates/kv_template.yaml@Repo1
        parameters:
          parameter1: ${{ parameters.parameter1 }}
          parameter2: ${{ parameters.parameter2 }}
      

    With above configuration:

    • When running the pipeline of Repo1 in Project1, it will directly pass the name of Service Connection 1 using the global pipeline variable ‘ARM_Connection‘ to the AzureCLI@2 task in the template kv_template.yaml.

    • Similarly, when running the pipeline of Repo2 in Project2, it will directly pass the name of Service Connection 2 using the global pipeline variable into the template.


    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search