Governance around CI/CD pipelines can be challenging. As the number of your applications and pipelines grow, it’s tough to make sure everybody is playing by the rules. Pipeline decorators can help us with this by injecting mandatory steps to the beginning and/or end of each pipeline.

Decorators will allow us to define required steps in one YAML file, that will be applied across all pipelines in an organization. Say our company wants to require running SonarQube analysis on all builds for the master branch. Rather than having developers add the SonarQube steps to all of their definitions, we can create a decorator that automatically runs the steps. I’ll walk through what is takes to setup decorators for this scenario. TLDR; create/install an extension with a YAML file that defines the steps to inject.

Enable the decorators feature at the organization level

Currently Pipeline Decorators are in preview. To enable this preview feature, we’ll need to enable it at the organization level.

  1. Click on your profile in the upper right -> Preview Features
  2. Toggle Pipeline decorators

Create an Azure DevOps Extension

  1. Create an extension using NodeJS, typescript and tfx-cli. The Microsoft docs walk through this step by step here: https://docs.microsoft.com/en-us/azure/devops/extend/develop/add-build-task
  2. Edit vss-extension.json and add contributions for our new pipeline decorators. I want the step that prepares for SonarQube analysis to run at the beginning of the build, and the step that runs the analysis to run at the end of the build. I specify this by using targets ms.azure-pipelines-agent-job.pre-job-tasks and ms.azure-pipelines-agent-job.post-job-tasks

Create Decorator YAML

Next, we create the YAML files that define the SonarQube steps to inject. For this example, I use SonarQubeDecoratorPrepare.yml and SonarQubeDecoratorAnalysis.yml. The syntax is no different than a typical YAML pipeline. I use conditional injection to control when the decorator runs, in this case I only want the tasks to run for the master branch (which is the default branch).

Build and install the private extension

There is detailed documentation on this here. When building the extension I like to rev the version number using: tfx extension create --manifest-globs vss-extension.json <strong>--rev-version

That way I don’t need to manually update the version in vss-extension.json every time.

After uploading the extension to the marketplace, it’s time to queue a build to test!

Troubleshooting

To log additional output produced during the build, set system.debugContext to True when queuing a build.

This will result in an additional section in the logs containing all of the information about the decorator.

The complete source for the examples above can be found in my GitHub repo here: https://github.com/MarcusFelling/PipelineDecorator