About the presenter

Presenter Name

☁️ Presenter Title

For questions or help with this series: msusdev@microsoft.com

All demos and source code available on GitHub:

github.com/msusdev/end-to-end-ci-cd

Series road map

  • Session 1:
    • Introduction to Azure Pipelines
  • Session 2:
    • ↪️ Automatically build and test your code with Azure Pipelines
  • Session 3:
    • Deploy your code to Azure with Azure Pipelines

Today’s agenda

  • Review Azure Pipelines
  • Automate build for a console app
  • Automate release to NuGet

::: notes

We’ll show you how to implement continuous integration (CI) for code maintained in GitHub repositories. You’ll learn to:

  • Build a project in a workflow
  • Create build assets for deployment
  • Distribute builds as packages

:::

Review Azure Pipelines

::: notes

  1. Start with an empty Azure DevOps project

  2. Create a GitHub repository with a single README file

  3. Use Visual Studio Code to create a simple .NET project:

     dotnet new console
     dotnet add package Colorful.Console
     dotnet new gitignore
    
     using static System.Drawing.Color;
     using Console = Colorful.Console;
    
     Console.WriteAscii("Hello, Audience!", Red);
    

    Note: You can use GitHub Codespaces to perform this task quickly.

  4. Create a new pipeline YAML file in your project.

    Note: The filename of the pipeline is arbitrary. For the remainder of the demos, we will assume you named the pipeline build.yml.

  5. Add the following content to the pipeline YAML file:

     pool:
       vmImage: ubuntu-20.04    
     stages:
     - stage: continuous_integration
       displayName: Continuous Integration
       jobs:
       - job: build
         displayName: Build
         container: mcr.microsoft.com/dotnet/sdk:6.0
         steps:
         - script: dotnet --version
           displayName: Check .NET SDK version
         - script: dotnet restore
           displayName: Restore NuGet packages
         - script: dotnet build
           displayName: Build .NET project
         - script: dotnet run
           displayName: Run .NET application
    
  6. Commit your changes to the local repository and push the changes to GitHub.

  7. Return to the new Azure DevOps project.

  8. Create, save, and then run a new pipeline with the following settings:

    • Source: GitHub
    • Repository: Select GitHub repository you created earlier
    • Template: Existing Azure Pipelines YAML file
    • Branch: main
    • Path: /build.yml
  9. Observe the job output logs.

:::

Today’s demo: .NET single-file applications

  • Attractive option for deploying console apps
  • Easy to distribute on GitHub “releases”
  • Can included debug files
  • Can be compressed to reduce size
  • Can have ahead-of-time (AOT) compilation enabled

Configuring single-file publishing

Command: dotnet publish

  • Release vs Debug configuration
  • Self-contained vs framework-dependent deployment
  • OS and architecture for executable

Project file

  • Single/multiple files (PublishSingleFile)
  • AOT compilation (PublishReadyToRun)
  • Compression (EnableCompressionInSingleFile)

::: notes

  • Single-file apps must be OS and architecture-specific and target a specific runtime
  • Compression comes with a performance cost
  • AOT compilation can have significant performance benefits with a 2-3x size increase to the executable

:::

Single-file command example

dotnet publish \
    --configuration Release --output pkg \
    --self-contained --runtime win-x64 \
    -p:EnableCompressionInSingleFile=true \
    -p:PublishSingleFile=true \
    -p:PublishReadyToRun=true \
    -p:DebugType=embedded

Demo: Automate Build

::: notes

  1. Create a GitHub repository using the msusdev-examples/contoso-spaces-dotnet-console-app template.

  2. Test the console app using the following command:

     dotnet run --
    

    Note: You can use GitHub Codespaces to perform this task quickly.

  3. Test the console app again using this variation on the previously ran command:

     dotnet run -- --seats 4
    
  4. Test publishing the console app using a simplified version of the dotnet publish command:

     dotnet publish --configuration Release --output out -p:PublishSingleFile=true --self-contained --runtime win-x64
    
  5. Observe the contents of the newly created out folder in your project.

  6. Create a new pipeline YAML file in your project.

    Note: The filename of the pipeline is arbitrary. For the remainder of the demos, we will assume you named the pipeline integration.yml.

  7. Publish the console application as an EXE and validate:

     pool:
       vmImage: ubuntu-latest    
     stages:
     - stage: ci
       displayName: Continuous Integration
       jobs:
       - job: build
         displayName: Build Project Assets
         container: mcr.microsoft.com/dotnet/sdk:6.0
         steps:
         - script: |
             dotnet publish \
             --configuration Release \
             --output out \
             --self-contained \
             --runtime win-x64 \
             -p:EnableCompressionInSingleFile=true \
             -p:PublishSingleFile=true \
             -p:PublishReadyToRun=true \
             -p:DebugType=embedded
           displayName: Publish .NET console project
    
  8. Create a build artifact for the console application and validate:

     ...
     - publish: out/Contoso.Spaces.Console.exe
       displayName: Upload console app artifact
       artifact: console-app
    

:::

Pack command example

dotnet pack \
    --output pkg \
    -p:Version=1.0.0

Another demo: NuGet publishing

  • .NET console application can be distributed at dotnet tools
  • Project is only required to be rebuilt using dotnet pack
  • Once packaged, the NuGet package (.nupkg) is published to
  • Versions are controlled using the Version project property

Demo: Automate Package & Release

::: notes

  1. Test publishing the console app using the dotnet pack command:

     dotnet pack --output pkg -p:Version=1.0.0
    
  2. Observe the contents of the newly created pkg folder in your project.

  3. Package the dotnet tool for NuGet and validate:

     ...
     - script: |
         dotnet pack \
         --output pkg \
         -p:Version=1.0.0
       displayName: Package dotnet tool
    
  4. Create a build artifact for the NuGet package and validate:

     ...
     - publish: pkg/Contoso.Spaces.Console.1.0.0.nupkg
       displayName: Upload package artifact
       artifact: nuget-package
    
  5. Create a release job and validate:

     ...
     - job: release
       displayName: Release on NuGet
       dependsOn: build
       container: mcr.microsoft.com/dotnet/sdk:6.0
    
  6. Download the NuGet package artifact and validate:

     ...
     steps:
     - download: current
       displayName: Download package artifact
       artifact: nuget-package
    
  7. Navigate to the NuGet website and get a new API key for your account.

  8. In your Azure Pipeline, create a new variable with the following settings:

    • Name: nuget-api-key
    • Is Secret: yes
    • Value: API key from NuGet website
  9. Push to NuGet and validate:

     ...
     - script: |
         dotnet nuget push \
         Contoso.Spaces.Console.1.0.0.nupkg \
         --skip-duplicate \
         --api-key $(nuget-api-key) \
         --source https://api.nuget.org/v3/index.json
       displayName: Push to NuGet.org
       workingDirectory: $(Pipeline.Workspace)/nuget-package
    
  10. Navigate to and view the newly created NuGet package.

  11. Test the new NuGet dotnet tool’s installation:

     dotnet tool install --global Contoso.Spaces.Console --version 1.0.0
     contosospaces
     contosospaces --seats 4
     dotnet tool uninstall --global Contoso.Spaces.Console
    

:::

Reviewing today’s session

  • Review Azure Pipelines
  • Automate build for a console app
  • Automate release to NuGet

Microsoft Learn

Thank You! Questions?