Search Results for

    Show / Hide Table of Contents

    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'
    
    • Improve this Doc
    In This Article
    Back to top Copyright 2023 One Step Beyond