Azure 37: YAML Pipeline Templates — the `extends` + `parameters` pattern
easy⏱ 5 mincourseazure
Service repo just extends a template
A service like cart-service has pipelines/prod.yml that does one job: pick the environment and pass parameters. It points at pipelines/backend/delivery.yml@pipelineTemplates — a wrapper template in a shared repo registered as a resource. The wrapper orchestrates GitVersion, Docker build/push, Helm deploy, Argo rollout — service repos never see those stages directly.
# cart-service/pipelines/prod.yml
resources:
repositories:
- repository: pipelineTemplates
type: git
name: Driveway/pipeline-templates
ref: refs/heads/main
trigger:
tags:
include: ['v*']
extends:
template: pipelines/backend/delivery.yml@pipelineTemplates
parameters:
environmentName: prod
createProdCR: true
services:
- name: cart-api
projectName: routes
universalChartType: api
Templates declare a typed parameter contract
pipelines/backend/delivery.yml declares every parameter with a type and often a default. Types include string, boolean, object, and typed arrays like services: type: object with documented shape. The pipeline fails at compile time if a consumer passes a parameter that doesn't match — your CI is statically typed.
# pipeline-templates/pipelines/backend/delivery.yml
parameters:
- name: environmentName
type: string
values: [dev, test, uat, prod]
- name: createProdCR
type: boolean
default: false
- name: services
type: object
- name: vaultNames
type: object
default: []
- name: variableGroups
type: object
default: []
Why this is a force multiplier
One change in pipeline-templates/main updates every service's pipeline simultaneously — add Datadog tagging once, get it on 35 services on the next run. The flip side: a breaking change in main breaks 35 services at once. Lythia mitigates with branch-pinning during rollout (ref: refs/heads/feature/new-rollout-step) and only flips to main after a canary service validates it.
Build a template resolver
Write a resolveTemplate(template, consumer) function. template has a name, a parameters schema (array of {name, type, required?, allowed?, default?}), and a stages list. consumer has a parameters object. Validate the inputs (required, allowed values, type), apply defaults for missing optional params, and return { effective: { ...params }, stages }. Throw a useful error message if validation fails. Log the resolved consumer's effective parameters for one prod and one dev pipeline.
Always pin ref for templates that consumers depend on
If your template repo uses ref: refs/heads/main and someone force-pushes main, every consumer breaks at the next run. Prefer release tags (ref: refs/tags/templates-v3.1.0) for prod-grade services. Reserve main for fast-moving infra-team services where breakage is recoverable.
Quiz: where do stages live?
A new engineer asks: 'Where is the actual docker build stage defined for cart-service?' Answer: not in the service repo — in pipeline-templates/ci/jobs/docker-build-push-v4.yaml, which delivery.yml composes into the buildImages stage. The service repo only chose environmentName: prod and a list of services to build.