Lint and validate your Bicep code
Now that you know what workflow jobs are for, let's consider the first set of validation steps that you can add to your Bicep deployment workflow. In this unit, you'll learn about validating Bicep templates. You'll also learn about the two validation activities that are commonly used: linting and preflight validation.
What is a valid Bicep file?
A valid Bicep file doesn't contain any syntax errors. Also, the definitions for the Azure resources that you plan to deploy are valid. And when the resources defined in the file are deployed, they stay within the quotas and limits that exist in your Azure subscription.
Some of the checks are performed on your Bicep file in isolation, like the checks for syntax errors, for valid Azure resource definitions, and for code quality. These steps are part of a process called linting. To check for other problems, you need to request that the Azure Resource Manager service validates your template and takes your Azure environment into consideration.
A valid Bicep template has a greater chance of deploying successfully. You get feedback without actually deploying your Bicep template. Validation is a good practice because if you deploy a Bicep file that isn't valid, Azure might deploy or change only a subset of the resources described in your template. A partial deployment could mean that the state of your environment is inconsistent and might not behave the way you expect.
Building and linting Bicep code
When you deploy a Bicep file, the Bicep tooling first runs some basic validation steps. These steps are the same ones that run when you modify your file by using Visual Studio Code. They check that you used Bicep's language keywords correctly and that you defined your Azure resources according to the requirements for each resource type.
In addition, Bicep runs a linter over your files. Linting is the process of checking your code against a set of recommendations. The Bicep linter looks at your file and verifies that you followed best practices for maintainability, correctness, flexibility, and extensibility.
A linter contains a predefined set of rules for each of these categories. Example linter rules include:
- Unused parameters. The linter scans for any parameters that aren't used anywhere in the Bicep file. By eliminating unused parameters, you make it easier to deploy your template because you don't have to provide unnecessary values. You also reduce confusion when someone tries to work with your Bicep file.
- String interpolation. The linter checks if your file uses the
concat()
function instead of Bicep string interpolation. String interpolation makes your Bicep files more readable. - Default values for secure parameters. The linter warns you if you set default values for parameters marked with the
@secure()
decorator. Setting defaults for secure parameters is a bad practice because it gives the secure parameter a human-readable value, and people might not change it before they deploy.
The Bicep linter runs automatically when you use the Bicep tooling. Every time you build a Bicep file, the linter checks it against its best practices. This check happens automatically when you deploy a Bicep file to Azure.
In a workflow, however, you typically want to run the validation and linting steps before you deploy the file. You can tell Bicep to verify your file by manually building the Bicep file through the Bicep CLI:
az bicep build --file main.bicep
bicep build main.bicep
Note
When you run the build
command, Bicep also transpiles your Bicep code to a JSON ARM template. You generally don't need the file that it outputs, so you can ignore it.
Because you want your Bicep templates to be linted each time anyone checks in code to your repository, you can add a lint job to your workflow:
You express this addition in your workflow YAML file like this:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- script: |
az bicep build --file deploy/main.bicep
Linter warnings and errors
By default, the linter emits a warning when it discovers that a Bicep file violates a rule. Warnings that the Bicep linter emits aren't treated as errors, so they don't stop the workflow run or stop subsequent jobs from running.
You can change this behavior by configuring Bicep to treat the linter rule violations as errors instead of warnings. You do this configuration by adding a bicepconfig.json file to the folder that contains your Bicep file. You can decide which linter issues should be treated as errors and which should remain as warnings. You'll configure the linter later in this module.
Tip
The bicepconfig.json file also controls how Visual Studio Code shows errors and warnings in the editor. It displays red and yellow squiggly lines under misconfigured parts in your Bicep template. These indicators give you even quicker feedback when you're writing your Bicep code, further reducing the chance of an error.
After you reconfigure the linter to emit errors, whenever the linter detects a problem, your workflow stops running and subsequent jobs don't run. This configuration helps ensure that problematic Bicep code isn't deployed.
Preflight validation
You also should check whether your Bicep template is likely to deploy to your Azure environment successfully. This process is called preflight validation, and it runs checks that need Azure to provide information. These kinds of checks include:
- Are the names that you specified for your Bicep resources valid?
- Are the names that you specified for your Bicep resources already taken?
- Are the regions that you're deploying your resources to valid?
Preflight validation requires communication with Azure, but it doesn't actually deploy any resources.
To submit a Bicep file for preflight validation, you use the arm-deploy
action, and set the deploymentMode
to Validate
:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: azure/arm-deploy@v1
name: Run preflight validation
with:
resourceGroupName: ${{ env.AZURE_RESOURCEGROUP_NAME }}
template: ./deploy/main.bicep
deploymentMode: Validate
You can also use the Azure CLI's az deployment group validate
command.
Preflight validation is similar to a normal deployment, but it doesn't actually deploy any resources. It performs extra checks against the resources that are being used in your template.
For example, suppose your Bicep file contains a storage account. Preflight validation checks whether another storage account already took the name you chose. It also checks whether the name you chose for the storage account complies with naming conventions.
The preflight validation command runs the Bicep linter too. However, it's usually a good idea to run the linter separately. That way, if there are any linter errors, you detect them quickly instead of waiting for the validation process to finish. Validation takes longer.
Important
When you run a preflight validation, each of the Azure resource providers performs its own checks. Some resource providers don't run many checks, whereas others do. So you can't rely on preflight validation to be certain that your file is valid. Nevertheless, it's a useful tool and is worth including in your workflow.
By adding validation jobs to your workflow to run the linter and perform a preflight validation, you'll have more confidence before you deploy your Bicep file.