AZ-400: Designing and Implementing Microsoft DevOps Solutions

Implementing an Orchestration Automation Solution

YAML Templates

In this lesson, we'll explore YAML basics and how to leverage YAML templates in Azure DevOps. Whether you're an experienced DevOps engineer, a developer transitioning into operations, or coming from a systems administration background, this guide will help you master essential CI/CD skills. By the end of this lesson, you'll be comfortable writing efficient YAML pipelines and using templates to streamline your build, test, and deployment processes.

Example YAML Pipeline for an ASP.NET Project

Below is a comprehensive YAML pipeline example configured for an ASP.NET project. This pipeline installs necessary tools, restores packages, builds the solution, and runs tests:

# ASP.NET
# Build and test ASP.NET projects.
# Add steps that publish symbols, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4
trigger:
- master

pool:
  vmImage: 'windows-latest'
  name: 'Default'

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- task: NuGetToolInstaller@1
- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'
- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)\\"'
    configuration: '$(buildConfiguration)'
- task: VSTest@2
  inputs:
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'

YAML is both machine-readable and human-friendly. Azure DevOps uses YAML files to define pipelines, which are structured using key-value pairs, lists, and nested elements. In the ASP.NET example above, you can see the following components:

  • Trigger: Executes the pipeline when changes are pushed to the master branch.
  • Pool: Specifies the build agent, here using a Windows environment.
  • Variables: Holds common values such as the solution file pattern, build platform, and configuration.
  • Steps: Executes a series of tasks like installing NuGet, building the solution, and running tests.

Note

Think of YAML as a structured way to describe your process. It improves clarity, reusability, and maintainability of your pipelines.

Starter Pipeline Example

For new pipelines in Azure Repos Git, the Starter Pipeline is an excellent minimal template that you can customize. The simple template below makes it easy to set up a build process without relying on pre-packaged templates:

The image shows an Azure DevOps Pipelines interface with a list of recently run pipelines. One pipeline named "KodeKloudData" is highlighted, indicating a successful run.

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master

pool:
  vmImage: ubuntu-latest
  name: 'Default'

steps:
- script: echo Hello, world!
  displayName: 'Run a one-line script'

- script: |
    echo Add other tasks to build, test, and deploy your project.
    echo See https://aka.ms/yaml
  displayName: 'Run a multi-line script'

When you run this pipeline, the logs might display output similar to:

"C:\Windows\system32\cmd.exe" /D /E:ON /V:OFF /S /C "CALL \"C:\Users\jeremy\Downloads\agent_work_temp\66f121fab-641c-447d-80b9-3fce56d64c57.cmd\""
Hello, world!

Understanding the YAML Structure

YAML is constructed using three fundamental constructs:

  1. Key-Value Pairs:
    These are used for settings such as trigger, pool, and variables.

  2. Lists:
    Lists are denoted by a dash (-). They allow multiple items such as defining multiple branches to trigger the pipeline or multiple steps within the pipeline. For example:

    trigger:
    - master
    - develop
    
  3. Nested Structures:
    Indentation defines hierarchy. For example, additional properties can be nested within the pool configuration:

    pool:
      vmImage: 'ubuntu-latest'
      name: 'Default'
      fruits:
        - Apple
        - Banana
        - Cherry
    

Additionally, YAML supports nested dictionaries. For example, defining a person object can look like:

person:
  name: Jeremy Morgan
  age: 47
  occupation: trainer

You can also reference variables in your pipelines. For instance:

person:
  name: $(PipelineRunnerName)
  age: $(PipelineRunnerAge)
  occupation: trainer

This way, you can override variable values during runtime without changing the YAML file.

Variables and Best Practices

Variables enhance reusability and help you follow the DRY (Don't Repeat Yourself) principle. Instead of hardcoding values like "Jeremy Morgan" in multiple locations, you can define a variable once and reference it throughout your YAML file:

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

A best practice is to document your YAML files with comments. This aids future maintainers while keeping the file readable and concise.

Using Templates to Avoid Duplication

Azure DevOps supports breaking your pipeline into reusable templates. This modular approach prevents duplication of common tasks, such as installing NuGet and restoring solutions. Templates in Azure DevOps come in three types:

  • Include templates
  • Extend templates
  • Parameter templates

For example, you can extract common tasks into a separate file named nuget.yml:

# nuget.yml
steps:
  - task: NuGetToolInstaller@1
  - task: NuGetCommand@2
    inputs:
      command: 'restore'
      restoreSolution: '$(solution)'

Then, in your main pipeline file, you can reference multiple templates for build and testing tasks:

trigger:
- master

pool:
  vmImage: ubuntu-latest
  name: 'Default'
  person:
    name: $(PipelineRunnerName)
    age: $(PipelineRunnerAge)
    occupation: trainer

variables:
  solution: '**/*.sln'
  buildPlatform: 'Any CPU'
  buildConfiguration: 'Release'

steps:
- script: echo $(PipelineRunnerName)
  displayName: 'Run a one-line script'

- script: |
    echo Add other tasks to build, test, and deploy your project.
    echo See https://aka.ms/yaml
  displayName: 'Run a multi-line script'
  
- template: nuget.yml
- template: build.yml
- template: test.yml

This method of dividing your pipeline into smaller templates offers the following benefits:

TemplateUse CaseDescription
nuget.ymlNuGet installation and package restoreContains tasks for installing and restoring NuGet dependencies
build.ymlBuilding the solutionCompiles the solution using designated parameters
test.ymlRunning testsExecutes unit or integration tests for the solution

After committing your changes, you'll see a clear breakdown of steps in your pipeline. For instance, the Azure DevOps final view displays a summary of tasks, such as running scripts, NuGet installation, compilation, and tests.

The image shows an Azure DevOps interface for creating a new pipeline, with options to select the source of the code, such as Azure Repos Git, Bitbucket Cloud, GitHub, and GitHub Enterprise Server.

Later, when reviewing the pipeline execution details, you'll observe each task executed in the defined order:

The image shows an Azure DevOps pipeline interface with a build summary for a YAML file update. It includes details like the repository, branch, and job status.

And upon inspecting the job details, each step's execution is clearly laid out:

The image shows an Azure DevOps pipeline interface with a list of completed job tasks on the left and job details on the right, indicating successful test results.

Warning

Always maintain consistency in indentation and structure in YAML files. A small indentation error can lead to unpredictable pipeline behavior.

In Summary

This lesson has provided you with a detailed understanding of YAML pipelines in Azure DevOps, including key-value pairs, lists, and nested structures. We explored best practices for using variables and demonstrated how to create reusable templates to avoid code duplication. With these strategies, you can develop maintainable and scalable CI/CD pipelines that simplify automation and enhance development workflow.

Happy coding and best of luck building your CI/CD pipelines!

Watch Video

Watch video content

Previous
Implementing Release Gates