CI / CD
Note
Please read about CI / CD in general first.
What is YAML
YAML is a human-friendly data serialization language for all programming languages. It is designed to be easy to read and understand and commonly used for configuration files, creating automation processes and in applications where data is being stored or transmitted.
Configure CI pipeline with YAML file
To set up a build pipeline create a YAML (.yml or .yaml extension) file in the ".pipelines" folder of the project with a descriptive name.
.NET projects can be built either with Visual Studio or with dotnet
command line tool.
Check the capabilities os the build agent to decide which tool to use for building the project.
In general, a CI pipeline must consist of at least a build and a test step to validate that the code base can be built and no tests are broken by code changes.
Build with dotnet
command line tool
Customize below snippet to meet your project needs. It is triggered on all branches when changes committed into src or tests folders. See repository management for detailed information on folder structure. It installs the required .NET version, restores the NuGet packages for the project, build the solution and executes the tests before publishes the packaged application.
trigger:
branches:
include:
- '*'
paths:
include:
- src
- tests
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
solution: '**/<solution_name>.sln'
project: '**/<project_name>.csproj'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core 7'
inputs:
version: 7.0.x
- task: DotNetCoreCLI@2
displayName: Restore
inputs:
command: restore
projects: '$(solution)'
arguments: '--configuration $(BuildConfiguration)'
- task: DotNetCoreCLI@2
displayName: Build
inputs:
projects: '$(solution)'
arguments: '--configuration $(BuildConfiguration)'
- task: DotNetCoreCLI@2
name: 'Tests'
displayName: 'Run tests'
inputs:
command: 'test'
projects: '$(solution)'
arguments: '--configuration $(BuildConfiguration) --collect "Code coverage"'
- task: DotNetCoreCLI@2
displayName: Publish
inputs:
command: publish
publishWebProjects: false
projects: '$(project)'
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: true
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: $(solution)-$(Build.BuildNumber)
Build with Visual Studio
To achieve the same behavior with Visual Studio as with dotnet
command line, use below snippet.
trigger:
branches:
include:
- '*'
paths:
include:
- src
- tests
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
solution: '**/<solution_name>.sln'
project: '**/<project_name>.csproj'
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)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: VSTest@2
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: $(solution)-$(Build.BuildNumber)
Configure CD pipeline with YAML file
In this section you will find an example how to deploy a .NET web application into Azure App Service. Depending on the complexity of the project you might need to customize it to meet your needs.
Prerequisites
Service Connection
To deploy a web application into Azure App Service a Service Connection needs to be created in Azure DevOps. Follow this Microsoft learn article to create a Service Connection to connect to Azure.
It is recommended to create one Service Connection per Azure environment.
Environments
To manage approvals and checks during deployment, create an Azure DevOps environment for each Azure environment.
For higher environments, like pre-production and production, it is a must to set up approvals. It is also recommended to set up Branch control and Business Hours checks, to restrict which branch can be deployed to target environments and what time to minimize business impact. For more detailed information, please consult with this Microsoft learn article.
Example pipeline
For the sake of simplicity, the example pipeline contains only to deployment stages for two environments. It is recommended to extract the common steps into a reusable template and use that template instead of copy-pasting the same steps.
Consult this Microsoft learn article to know more about reusable YAML templates.
trigger: none
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
solution: '**/<solution_name>.sln'
project: '**/<project_name>.csproj'
stages:
- stage: deploy_<name of env 1>
displayName: Deploy to <name of env 1>
jobs:
- deployment: deploy
displayName: Deploy
environment: <name of env 1>
variables:
- group: <name of environment specific variable group if any>
strategy:
runOnce:
deploy:
steps:
- download: none
- checkout: none
- task: DownloadBuildArtifacts@1
displayName: Download artifacts
inputs:
buildType: current
downloadType: single
artifactName: <name of artifact to be deployed>
downloadPath: $(System.ArtifactsDirectory)
- task: AzureWebApp@1
inputs:
azureSubscription: '<Azure service connection env 1>'
appType: webAppLinux
appName: '<name of web app>'
deployToSlotOrASE: true
resourceGroupName: '<name of resource group>'
package: '$(System.ArtifactsDirectory)/**/*.zip'
- stage: deploy_<name of env 2>
displayName: Deploy to <name of env 2>
jobs:
- deployment: deploy
displayName: Deploy
environment: <name of env 2>
variables:
- group: <name of environment specific variable group if any>
strategy:
runOnce:
deploy:
steps:
- download: none
- checkout: none
- task: DownloadBuildArtifacts@1
displayName: Download artifacts
inputs:
buildType: current
downloadType: single
artifactName: <name of artifact to be deployed>
downloadPath: $(System.ArtifactsDirectory)
- task: AzureWebApp@1
inputs:
azureSubscription: '<Azure service connection env 2>'
appType: webAppLinux
appName: '<name of web app>'
deployToSlotOrASE: true
resourceGroupName: '<name of resource group>'
package: '$(System.ArtifactsDirectory)/**/*.zip'