Handling template inheritance within a monorepo.

Posted on Wed 17 May 2023 in devops

For my current client, they have all of their API's contained within a single repository as this allows for simpler code navigation from shared components such as DTO's or client classes which act as wrapper classes around an httpclient instance. This provides a lot of benefits especially when there is tighter coupling between some of the API's than say a nuget package would give.

It gives an interesting problem over reuse of yaml though, when defining a build pipeline or an integration pipeline, it would be silly to have the same pipeline copy/pasted into several different files and would give a bit of a maintenance headache when the shared powershell scripts that do 'the under the hood' work of the yaml pipelines change.

The solution we settled on was to create an application specific yaml file called say 'auth.yml' where the contents of it would simply be to extend and provide an application name parameter to a a beefier integration.yml pipeline.

# File: auth.yml
trigger:
- main
  paths:
    include:
    - Auth

extends:
  template: integration.yml
  parameters:
      applicationName: auth #

Then the integration.yml pipeline would look something like...

# File: integration.yml
parameters:
- name: applicationName

jobs:
  - job: Integration
    pool:
      vmImage: windows-2022
    steps:
    - checkout: self
      submodules: true
      persistCredentials: true

    - task: PowerShell@2
      inputs:
        targetType: 'filePath'
        filePath: $(System.DefaultWorkingDirectory)/Scripts/shared/build-app.ps1
        arguments: > # Use this to avoid newline characters in multiline string
          -n ${{ parameters.applicationName }}
      displayName: 'Build app'

    - task: PowerShell@2
      inputs:
        targetType: 'filePath'
        filePath: $(System.DefaultWorkingDirectory)/Scripts/prepare-artifacts.ps1
        arguments: > # Use this to avoid newline characters in multiline string
          -n ${{ parameters.applicationName }}
      displayName: 'Prepare artifacts'

    - task: PowerShell@2
    ########################### Other tasks...

The end result is one integration pipeline yaml to maintain which can have optionality built into it with application specific driver yaml files which act as parameter feeders.