Hello All,
In this post I would like to explain how I used Azure DevOps to publish a simple .Net 7 class library to Azure DevOps Artifacts using YAML in a Build Pipeline.
The Process
To begin with I used Azure DevOps and within my selected project I created a new git repo called “kodeazure-shared“. I then cloned this repo to my local machine. I used the following folder structure as shown in the below image.
The “build” folder contains my yaml pipeline. The “src” folder contains my class library.
I then used Visual Studio 22 to create a simple Class Library project and stored the solution files within the src folder.
The Class Library
The class library project for the purpose of this blog post is used by the KodeAzure developers as a shared library, its purpose contains helper classes and methods to aid in development and to be shared amongst other projects that should need such a shared library.
to keep it simple I have a static class called “Strings” with a couple of static helper methods. This class library can be more complex if needed but the point in this post is to show you how to publish an Artifact using Azure DevOps.
The below code shows the strings class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System.Text.RegularExpressions; namespace KodeAzure.Shared { public static class Strings { public static string HtmlEncode(string input) { return System.Net.WebUtility.HtmlEncode(input); } public static string InputClean(string input) { Func<string, string> wrapperFunction; wrapperFunction = (string str) => str; return wrapperFunction( Regex.Replace( Regex.Replace(input ?? "", "<.*?>", // Remove HTML Tags "" ), @"\p{C}+", // Remove control characters "" ) ).Trim(); } } } |
The YAML File
In the “build” directory I created a YAML build file, the code for this is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
trigger: - main variables: # Working Directory workingDirectory: "$(System.DefaultWorkingDirectory)/src/KodeAzure.Shared" vmImage: windows-latest Major: '1' Minor: '0' Patch: '0' stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build Shared Library pool: vmImage: $(vmImage) steps: - task: DotNetCoreCLI@2 displayName: 'Dotnet build Release' inputs: command: 'build' projects: '$(workingDirectory)/*.csproj' arguments: '--configuration Release' - task: DotNetCoreCLI@2 inputs: command: pack versioningScheme: byPrereleaseNumber majorVersion: '$(Major)' minorVersion: '$(Minor)' patchVersion: '$(Patch)' packagesToPack: '$(workingDirectory)/*.csproj' packDestination: '$(Build.ArtifactStagingDirectory)' - task: PowerShell@2 inputs: targetType: 'inline' script: | Write-Host "Contents of $(Build.ArtifactStagingDirectory):" Get-ChildItem $(Build.ArtifactStagingDirectory) displayName: 'Echo Artifact Staging Directory Contents' - task: NuGetAuthenticate@1 displayName: 'NuGet Authenticate' - task: NuGetCommand@2 displayName: 'NuGet push' inputs: command: push packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg' publishVstsFeed: 'Joe Moore IAC/kodeazure' allowPackageConflicts: true |
Explaining the Build File
Let me explain what’s going on with this file:
1 2 3 4 5 6 7 8 9 10 |
trigger: - main variables: # Working Directory workingDirectory: "$(System.DefaultWorkingDirectory)/src/KodeAzure.Shared" vmImage: windows-latest Major: '1' Minor: '0' Patch: '0' |
I am keeping things simple at this stage. But this build pipeline will be triggered on when new code is added to the “main” branch. Next I have declared a variables section. I have a handful of variables one for the workingDirectory, vmImage and final some version variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build Shared Library pool: vmImage: $(vmImage) steps: - task: DotNetCoreCLI@2 displayName: 'Dotnet build Release' inputs: command: 'build' projects: '$(workingDirectory)/*.csproj' arguments: '--configuration Release' - task: DotNetCoreCLI@2 inputs: command: pack versioningScheme: byPrereleaseNumber majorVersion: '$(Major)' minorVersion: '$(Minor)' patchVersion: '$(Patch)' packagesToPack: '$(workingDirectory)/*.csproj' packDestination: '$(Build.ArtifactStagingDirectory)' |
The above shows that I am using stages and jobs. I have task to build my class library project, next I have task to pack my class library project as a nuget package, this is then published to ‘$(Build.ArtifactStagingDirectory)’
Stages: Stages are a way to break down your pipeline into smaller sections, each representing a logical division of work. For example, you might have stages like Build, Test, and Deploy. Each stage can contain one or more jobs. Stages run sequentially, meaning that each stage will wait for the previous stage to complete before starting.
Jobs: Jobs are individual units of work within a stage. Each job runs on an agent and can contain multiple steps. Jobs within the same stage can run in parallel or sequentially, depending on how you configure them. For example, you might have a job for building your application, another job for running tests, and a third job for deploying the application.
1 2 3 4 5 6 7 8 9 10 |
- task: NuGetAuthenticate@1 displayName: 'NuGet Authenticate' - task: NuGetCommand@2 displayName: 'NuGet push' inputs: command: push packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg' publishVstsFeed: 'Joe Moore IAC/kodeazure' allowPackageConflicts: true |
Finally as shown above, I am using the NuGetAuthenticate task, this is so that my Build Service can be authenticated to talk to my artifacts feed. the last task then publishes this Nuget package to my feed publishVstsFeed: ‘Joe Moore IAC/kodeazure’ this is in the format of Project Name/ Artifact feed name
Project Properties
I then opened the project properties up by right clicking on the project in visual studio and selecting properties. I selected “Package -> General” then checked the option “Generate NuGet package on build” I then filled out some of the settings such as Nuget description etc..
Next I checked in all this code into my repo.
Creating the Feed
Before we can create the build pipeline, we first need to create a new feed. If you already have a feed that you wish to use you can skip this section.
To do this located your DevOps project, and then select on the left hand side “Artifacts” followed by “Create Feed“.
Next provide a feed name and who can access this feed. to keep things simple I left the defaults. Click the “Create” button.
Next we need to set the permissions, so that our Build pipeline can access this feed in order to publish Artifacts. Click the gear icon.
Then click on the “Permissions” tab.
Then click on “Add users/groups”
I then selected my Project build service, the format for this is “Project Name Build Service [Organization Name]“.
I selected the “Feed Publisher “then clicked on “Save“.
The below image shows that this was created with sucess.
The Build Pipeline
With our code checked in and the permissions sorted we can now create a Build Pipeline.
To do this I selected “Pipelines” on the left hand side menu, and I then clicked on “New pipeline“.
I then selected on “Azure Repos Git”
On the “Select” screen, I selected the repo in question, and then on the “Configure” screen, I selected “Existing Azure Pipelines YAML File“.
I then drilled down to select the build file, and then clicked on “Continue“.
This opened the “Review your pipeline YAML” screen, from here I clicked on the “Run” button, or I could have clicked on the “Save” button which is located as a dropdown where it says “Run“.
Conclusion
That’s it. If all being well you should now see your Nuget package having been upload the Azure DevOps Artifacts. At a later date I will create a post that explains how to consume this NuGet package.
If you need any help with this please let me know: