Azure Bicep validation in a pull request with Azure DevOps

In this blog I am going to write about how you can automatically validate Bicep template changes inside a pull request in Azure DevOps. This validation step can help identify errors written in a template or parameter file. These errors can be syntactical or input-based errors. The techniques used in this blog are: Azure CLI, Azure DevOps, Azure Bicep and YAML.

Validation placement

Before I go in-depth let’s see where the Bicep validation will take place. Let’s take a look at the development flow:

Development Flow
  1. There is an engineer who writes code in their favourite IDE.
  2. The engineer works on a development branch (feature branch).
  3. When the engineer is done a pull request has to be created:
    • In this pull request there is an automated pipeline that is triggered on pull request creation. This pipeline validates the Bicep template and parameter file found in the pull request. This pipeline triggers after every change in the PR.
    • Two other engineers check the code in the pull request and provide feedback when necessary.
  4. After approval the PR will be merged with the main branch.
  5. The reviewed Bicep template and parameter file are being deployed.

In this blog I am going to focus on the “Automated Bicep Validation” step.


To work with an example I am going to create a virtual network (VNet). To create a VNet you need a Bicep template where the VNet is defined and a parameter file to populate the Bicep input parameters:

Bicep template example (virtualNetwork.bicep)

param parVnetName string
param parAddressSpace string
param parSubnet string
resource resVirtualNetwork 'Microsoft.Network/virtualnetworks@2015-05-01-preview' = {
name: parVnetName
location: 'westeurope'
properties: {
addressSpace: {
addressPrefixes: [
subnets: [
name: 'my-subnet'
properties: {
addressPrefix: parSubnet

Parameters input (virtualNetwork.parameters.json)

"$schema": "",
"contentVersion": "",
"parameters": {
"parVnetName": {
"value": "validation"
"parAddressSpace": {
"value": ""
"parSubnet": {
"value": ""

Add a new parameter

If you want to deploy the virtual network in multiple regions you need to parameterize the location input. To add the location parameter input you need to create a feature branch called something like add-location. In this branch you add the code in the Bicep template and parameter file:

param parLocation string
resource resVirtualNetwork 'Microsoft.Network/virtualnetworks@2015-05-01-preview' = {
location: parLocation
"parLocation": {
"value": ""

Now you have a change ready for a pull request. 


You want the pipeline to run every pull request creation or every pull request change. It will run the validation using an Azure CLI command. The pipeline is written in YAML and will contain two jobs:

  • Checkout
  • Validation_Step_PR
- job: Checkout
- checkout: git://bicep-validation/bicep-validation@$(Build.SourceBranch)
- task: PublishBuildArtifacts@1
pathToPublish: $(Build.SourcesDirectory)
artifactName: drop
- job: Validation_Step_PR
displayName: "Validating Bicep in PR"
dependsOn: Checkout
- task: DownloadPipelineArtifact@2
artifact: drop
- task: AzureCLI@2
displayName: Validate
azureSubscription: publish-my-iac
scriptType: pscore
scriptLocation: inlineScript
inlineScript: >
az deployment group validate
--resource-group rg-we-prod-validation
--template-file Infrastructure/Templates/virtualNetwork.bicep
--parameters Infrastructure/Parameters/virtualNetwork.parameters.json

Job: Checkout

In this job the pipeline does a checkout at bicep-validation repository. The crucial step of the checkout process is to refer to the pull request source branch. Azure DevOps has a built-in variable called Build.SourceBranch which targets the source branch of the pull request. In this case the feature branch add-location is going to be checked-out. If you don’t specify this variable the default branch is going to be checked-out. When the checkout is done the artifacts are being published with the name drop.

Checkout URL segments explained: git://<Azure DevOps Project Name>/<Git repo name>@<Branch>

Job: Validation_Step_PR

In this job the pipeline downloads the published artifacts. After that the validation step comes into play. I use the built-in Azure CLI validation tool to validate the Bicep template. Add the AzureCLI@2 task and set the scriptLocation property to inlineScript. You can also use a value scriptPath to refer to a file instead of inline. 

The inlineScript runs an Azure CLI command az deployment group validate with the following properties:

  • resource-group → rg-we-prod-validation
  • template-file → path to virtualNetwork.bicep
  • parameters → path to virtualNetwork.parameters.bicep

This is everything you need to create to validate our Bicep using a pipeline. Commit and push the YAML file and create the pipeline. I named mine BicepTemplateValidation.

Added the pipeline to Azure DevOps

Next you need to set up a build validation policy so the pipeline triggers on every pull request.

Branch policy

A branch policy protects important branches. You want to protect the main branch and enforce a validation pipeline run before merging any feature branches. To set a branch policy you must be a member of the Project Administrator group or you need edit policy permissions.

Under Repos go to Branches. On this screen you see all active branches. Hover over the main branch (or over another default branch) to see the ellipsis (“three dots”) on the right, click on these and go to Branch policies.

Azure DevOps screen where branch policies can be found

On the Branch policies screen add the following setting by pressing the “+” button:

  • Build validation
The branch policies page, here you can add a build validation

Refer to the validation pipeline you created. Set the build expiration to “immediately” so the pipeline always triggers on new pushes to the pull request, also after the pull request has been created. Also the trigger is set to automatic so the pipeline always runs a pull request is created.

Build policy setting screen

Pull request

Let’s merge the location parameter changes from the feature branch to the main branch using a pull request and see what happens with the pipeline.

Pull request with the change and a running validation pipeline

You can see the build validation policy is being enforced. The validator pipeline runs when the pull request is created or when new changes are pushed in the pull request.  

Pipeline result

If you look at the pipeline output you see the added parameter parLocation in our validation. This is the change we made in the feature branch, which is being validated in the pull request.

Successful validation run and the change is visible

In the overview of the pull request it shows that the automated validation pipeline has run successfully and the PR is now able to be completed and merged to main.

Successful validation run on the pull request screen

Let’s take a look at what happens if you make a typo in a parameter. For example, you make a typo in the CIDR notations of the subnet address. Instead of assigning a CIDR-block of /24 I assigned a CIDR-block of /245.  

Make a new commit and push it to the pull request. It reruns the validator pipeline and validates the newly made changes. In the overview it shows that the validation has failed, which means that the mistake has been automatically detected. 

Failed validation run
Error message


This is one way to validate your Bicep template and parameter files. I like this way of validation because when you work with large and complex Bicep files small errors like typos will be picked up automatically. This allows the reviewers to focus on other things in the pull request.

You can extend the YAML file to support multiple Bicep validations using a loop or do checkouts based on your Git repository structure.

The Azure Pipeline YAML is uploaded as a GitHub gist:

One thought on “Azure Bicep validation in a pull request with Azure DevOps

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s