3 min read
Azure DevOps in 2022: New Features and Best Practices
Azure DevOps continues to evolve with powerful new features for 2022. Let’s explore the latest capabilities and best practices for modern DevOps workflows.
YAML Pipelines Evolution
Multi-stage pipelines with environment approvals:
trigger:
branches:
include:
- main
paths:
exclude:
- docs/**
- README.md
pool:
vmImage: 'ubuntu-latest'
variables:
- group: 'Production-Secrets'
- name: buildConfiguration
value: 'Release'
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- task: UseDotNet@2
inputs:
version: '6.0.x'
- task: DotNetCoreCLI@2
displayName: 'Restore'
inputs:
command: 'restore'
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
arguments: '--configuration $(buildConfiguration)'
- task: DotNetCoreCLI@2
displayName: 'Test'
inputs:
command: 'test'
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage"'
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Agent.TempDirectory)/**/coverage.cobertura.xml'
- task: DotNetCoreCLI@2
displayName: 'Publish'
inputs:
command: 'publish'
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
- publish: $(Build.ArtifactStagingDirectory)
artifact: 'drop'
- stage: DeployDev
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployDev
environment: 'Development'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: 'drop'
- task: AzureWebApp@1
inputs:
azureSubscription: 'Azure-Dev'
appName: 'myapp-dev'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
- stage: DeployProd
dependsOn: DeployDev
condition: succeeded()
jobs:
- deployment: DeployProd
environment: 'Production'
strategy:
runOnce:
deploy:
steps:
- download: current
artifact: 'drop'
- task: AzureWebApp@1
inputs:
azureSubscription: 'Azure-Prod'
appName: 'myapp-prod'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
Reusable Templates
Create reusable pipeline templates:
# templates/dotnet-build.yml
parameters:
- name: buildConfiguration
default: 'Release'
- name: dotnetVersion
default: '6.0.x'
- name: projects
default: '**/*.csproj'
steps:
- task: UseDotNet@2
inputs:
version: ${{ parameters.dotnetVersion }}
- task: DotNetCoreCLI@2
displayName: 'Restore packages'
inputs:
command: 'restore'
projects: ${{ parameters.projects }}
- task: DotNetCoreCLI@2
displayName: 'Build solution'
inputs:
command: 'build'
projects: ${{ parameters.projects }}
arguments: '--configuration ${{ parameters.buildConfiguration }} --no-restore'
Use the template:
# azure-pipelines.yml
stages:
- stage: Build
jobs:
- job: Build
steps:
- template: templates/dotnet-build.yml
parameters:
buildConfiguration: 'Release'
dotnetVersion: '6.0.x'
Service Connections with Workload Identity
# Using workload identity federation (no secrets!)
- task: AzureCLI@2
inputs:
azureSubscription: 'WorkloadIdentityConnection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az account show
az webapp list --query "[].name"
Pull Request Validation
# pr-validation.yml
trigger: none
pr:
branches:
include:
- main
- release/*
jobs:
- job: Validate
steps:
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
- task: DotNetCoreCLI@2
displayName: 'Test'
inputs:
command: 'test'
arguments: '--logger trx --results-directory $(Agent.TempDirectory)'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'VSTest'
testResultsFiles: '**/*.trx'
searchFolder: '$(Agent.TempDirectory)'
- task: BuildQualityChecks@8
inputs:
checkCoverage: true
coverageFailOption: 'fixed'
coverageType: 'lines'
coverageThreshold: '80'
Artifacts and Feeds
- task: NuGetCommand@2
displayName: 'Push to feed'
inputs:
command: 'push'
packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg'
nuGetFeedType: 'internal'
publishVstsFeed: 'MyOrg/MyFeed'
Azure DevOps in 2022 offers a mature, flexible platform for any DevOps workflow.