There are two main ways to create re-usable components for Azure Pipelines. I’ll review the pros and cons of each and talk about when it makes sense to use one over the other. Keep in mind that the two are not mutually exclusive, so it may make sense to use a combination of both.
Note: I won’t be including task groups as they’re not supported in YAML pipelines. Why use YAML over Classic Editor? See my previous blog post here: Classic Editor VS. YAML
Custom pipeline task extension
Why would you use a custom pipeline task extension over a YAML template?
- Discoverability – Once installed, the pipeline consumers can search for custom tasks using the Task Assistant.
- Helpers – You can add helpers (helpMarkDown in task.json) that assist users with filling in the necessary param’s for the task, through the Task Assistant.
- SDK – Extensions make it easy to bundle and utilize the functions available in the Azure Pipelines Task SDK.
- Learning curve – There is definitely a learning curve that comes with figuring out how to author, test, package, version, publish, and install extensions.
- More than 1 file required – There is complexity that comes with the required config files, dependencies, and TFX CLI, compared to a single YAML template file.
Why would you use a YAML template over a custom pipeline task extension?
- Simplicity – Only a single file required.
- Security and governance features – There are bunch of security features that can be enforced through YAML. My favorite is the required template check. You can set up certain environments or service connections (e.g. production) to require that a template is referenced in the pipeline. This enables an inner sourcing workflow where SME’s (security, database, networking teams) define their standards in templates, then only allow contributions through a pull request to sign off on changes. Ideally the pipeline consumers have read-access to the template repo’s so they have visibility into what the templates do and can submit a pull request with changes to extend the functionality or fix a bug. This way the SME’s aren’t a bottleneck.
- Easy updates – Git branches can be used to isolate and test changes, then pull requests can be used to collaborate with others on changes.
- Parameters – Consumers would need to go to the template YAML file and/or documentation to understand parameters. Having README markdown files alongside templates helps.
- What templates can I use? – Discovering all of the templates available requires searching across repositories.
Use them together
Sometimes it makes sense to create a custom task extension, then reference it in templates. In that case, consumers can still use the task individually (outside of the template), but things like security can be enforced when it makes sense. I have some examples of this on GitHub; I have a template repo here, that get’s referenced in my YAML pipeline here.
3 thoughts on “Azure Pipelines: YAML Templates VS. Custom Tasks”
If I may add my observations:
Using Custom tasks has this benefit that if:
– you want to use your custom step in the “deployment” type of Stage (where your repository is not being checkout)
– you want to keep your custom step logic in the seprerate repository
you don’t need to worry about downloading those steps artifacts
With templates, you might need to add “push artifact” in one stage and “download artifact” in the second.
We’ve started using templates with the Azure Artifact repository to simplify that.
Great discussion and comparison. We additionally use Custom Tasks for functionality that we may want both in YAML pipelines as well as the visual “Release” workflow for deployments. Our teams are in transition between moving from “Releases” to YAML Pipelines and this is effective in allowing teams to transition over easily.
If you’re using a Repository resource and referencing a job template, you wouldn’t have to worry about a checkout of the yaml? You would just reference via path-to-yaml@templates, for example.
I also think one benefit a team might consider when creating their own custom task is the added ability in managing versions of the task. If you don’t want teams using old code, you just push a (minor or patch) update. With yaml, a team can pin to the specific commit, branch, or tag, which may be beneficial for backwards compatibility but if you are in a situation where an older version of the template has a crucial bug or security vulnerability, finding out whose using what version of the yaml is tricky.