0

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
  • Please share some YAML code. Commented Nov 7, 2024 at 10:19
  • "My objective is to have kv_template.yaml dynamically select the appropriate service connection based on which repository/pipeline is calling it" - are you using triggers? Or resources? Please share more details. Commented Nov 7, 2024 at 11:56

2 Answers 2

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?

parameters:
- 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).

Sign up to request clarification or add additional context in comments.

Comments

0

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.


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.