How to use template with references to script in another repository within Azure DevOps Pipelines?

Viewed 7017

I'm trying to use a template that's stored in another Git repository in Azure DevOps where that template has a reference to a script also contained within that repository. While I can successfully use the template from the main pipeline it doesn't reference the script the template requires.

Is there some way I can do this please?

The HelloWorld template/script are stored in Azure DevOps Repo 'HelloWorld' in a sub-folder called 'Templates'.

HelloWorld.ps1 script in the same directory as the below template.

param($Name)

Write-Host "Hello, $Name!"

Template #1 with reference to local script

  parameters:
  - name: azureSubscription
    type: string
  - name: name
    type: string
  
  jobs:
  - job: HelloWorld
    displayName: Hello World
    variables:
      name: ${{ parameters.name }}
    steps:
    - task: AzurePowerShell@4
      name: HelloWorld
      displayName: Hello World
      inputs:
        azureSubscription: ${{ parameters.azureSubscription }}
        scriptType: filePath
        scriptPath: ./HelloWorld.ps1
        azurePowerShellVersion: latestVersion
        failOnStandardError: true
        scriptArguments:
          -Name "$(name)"

Template #2


resources:
  repositories:
    - repository: helloworld
      type: git
      name: HelloWorld

stages:
- stage: Variables
  jobs:
  - template: Scripts/hello-world.yml@helloworld
    parameters:
      azureSubscription: 'My Subscription'
      name: 'Billy'
3 Answers

If your pipeline has templates in another repository, or if you want to use multi-repo checkout with a repository that requires a service connection, you must let the system know about that repository. The repository keyword lets you specify an external repository.

You could refer to Repository resource and templates in another repository for more details.

Such as in templates repository, we'd expect to find test.yml at the root.

resources:
  repositories:
  - repository: templates
    type: git
    name: templates
steps:
- template: test.yml@templates

Update1

I update your code and it works, please check it.

The repo HelloWord structure and the repo contain template file and PS1 file

enter image description here

Template #1 with reference to local script. Note: I add checkout step to checkout the HelloWord and pipeline self repo

  parameters:
  - name: azureSubscription
    type: string
  - name: name
    type: string
  
  jobs:
  - job: HelloWorld
    displayName: Hello World
    variables:
      name: ${{ parameters.name }}
    steps:
    - checkout: self
    - checkout: helloworld
    - task: AzurePowerShell@4
      name: HelloWorld
      displayName: Hello World
      inputs:
        azureSubscription: ${{ parameters.azureSubscription }}
        scriptType: filePath
        scriptPath: $(build.sourcesdirectory)/Helloworld/Subfolder/HelloWorld.ps1
        azurePowerShellVersion: latestVersion
        failOnStandardError: true
        scriptArguments:
          -Name "$(name)"

In the another repo create yaml build definition.

resources:
  repositories:
    - repository: helloworld
      type: git
      name: HelloWorld
pool:
  vmImage: 'windows-latest'
 
stages:
 
- stage: Variables
  jobs:
  - template: hello-world.yml@helloworld
    parameters:
      azureSubscription: 'My Subscription'
      name: 'Billy'

Result:

enter image description here

When you have multiple repositories in your pipeline and you have them when you use template from another repo, they are fetched to their own folders instead of root one. It seems to be obvious but we need to have this in mind.

If you have multiple checkout steps in your job, your source code is checked out into directories named after the repositories as a subfolder of s in (Agent.BuildDirectory). If (Agent.BuildDirectory) is C:\agent_work\1 and your repositories are named tools and code, your code is checked out to C:\agent_work\1\s\tools and C:\agent_work\1\s\code.

Thus when you call a script inside a template which is in another repo you may be forced to provide alias name for the repo to properly locate your script.

For instance:

trigger: none
pr: none

resources:
  repositories:
    - repository: devops
      type: github
      name: kmadof/devops-templates
      endpoint: kmadof

stages:
- template: templates/start.yaml@devops
  parameters:
    repo: devops-templates
    buildSteps:
      - checkout: self
      - checkout: devops
      - bash: echo Test #Passes
        displayName: succeed
      - bash: echo "Test"
        displayName: succeed

I'm passing there repo parameter to use it in my template:

parameters:
- name: repo  # defaults for any parameters that aren't specified
  default: ''

steps:
  - task: PowerShell@2
    inputs:
      filePath: ${{ parameters.repo }}/scripts/myscript.ps1

You can check code here

I will share a more detailed answer to this question for my case.

Our case:

tow repo case

My goal was to build a generic pipeline that will do CI/CD and infra as a code for multiple repositories with the same structured app but with different business logic. In this example I will call one of those repositories as Repository A We have Repostiroy B which is a template repo with CI/CD steps and it also has multiple bicep files (azure function basic, azure function, and Azure SQL).

Solutin

Repository A

    resources:
      repositories:
        - repository: DevOps
          type: git
          name: Repository/RepositoryB
    
    stages:
      - template: Templates/generic-template.yml@DevOps
        parameters: 
          resourceGroupName: resource-group-name
          azureServiceConnection: service-connection
          bicepFileTemplateName: basic-azure-function
          devOpsResource: DevOps # Pass RepositoryB to template

Repository B

parameters:
  - name: resourceGroupName
  - name: azureServiceConnection
  - name: bicepFileTemplateName
  - name: devOpsResource

stages:
  - stage: CreateEnvironment
    displayName: Provision Bicep ${{ parameters.bicepFileTemplateName }}
    jobs:
      - job: ProvisionBicep
        steps:
          - checkout: ${{ parameters.devOpsResource }}
          - task: AzureCLI@2
            inputs:
              azureSubscription: ${{ parameters.azureServiceConnection }}
              scriptType: bash
              scriptLocation: inlineScript
              inlineScript: |
BICEP_TEMPLATE=$(Build.SourcesDirectory)/Infrastructure/${{ parameters.bicepFileTemplateName }}.bicep
                echo Bicep template path: $BICEP_TEMPLATE
                az deployment group create --resource-group ${{ parameters.resourceGroupName }} --mode Incremental --template-file $BICEP_TEMPLATE


Related