This post shows how to structure a monorepo for NuGet packages and then automate their build using Azure YAML pipelines.
Project Structure
Use a package’s solution file to define the location of the packages source code and test code. This single solution file can then be passed to the DotNetCoreCLI@2 task to only build and pack that particular package.
Solution files are Common.A.sln and Common.B.sln.
Project file structure for two packages common.A and common.B
/common-nuget-library /common /common.A azure-pipelines.yml common.A.sln common.A.csproj /src /common.B azure-pipelines.yml common.B.sln common.B.csproj /src /tests common.A.tests common.A.tests.csproj common.B.tests common.B.tests.csproj
Configuring the pipeline for each NuGet package
Next we want to configure a pipeline for each package. The contents of each azure-pipelines.yml are show below.
common.A/azure-pipelines.yml
trigger:
paths:
include:
- common/common.A/*
...
- task: DotNetCoreCLI@2
displayName: 'DotNet Build'
inputs:
command: 'build'
projects: 'common/common.A/common.A.sln'
- task: DotNetCoreCLI@2
displayName: 'Dotnet Pack'
inputs:
command: 'pack'
packagesToPack: 'common/common.A/common.A.sln'
includesymbols: true
packDirectory: '$(Pipeline.Workspace)/dist'
configuration: 'Release'
nobuild: true
versionEnvVar: 'BUILD_BUILDNUMBER'
versioningScheme: 'byEnvVar'
buildProperties: 'SymbolPackageFormat=snupkg'
- The pipeline is only triggered when changes occur in common/common.A/*
- The DotNet Build task only builds the packages listed in the solution file ‘common/common.A/common.A.sln’
- The DotNet pack task only packages ‘common/common.A/common.A.sln’
common.B/azure-pipelines.yml
trigger:
paths:
include:
- common/common.B/*
...
- task: DotNetCoreCLI@2
displayName: 'DotNet Build'
inputs:
command: 'build'
projects: 'common/common.B/common.B.sln'
- task: DotNetCoreCLI@2
displayName: 'Dotnet Pack'
inputs:
command: 'pack'
packagesToPack: 'common/common.B/common.B.sln'
includesymbols: true
packDirectory: '$(Pipeline.Workspace)/dist'
configuration: 'Release'
nobuild: true
versionEnvVar: 'BUILD_BUILDNUMBER'
versioningScheme: 'byEnvVar'
buildProperties: 'SymbolPackageFormat=snupkg'
- The pipeline is only triggered when changes occur in common/common.B/*
- The DotNet Build task only builds the packages listed in the solution file ‘common/common.B/common.B.sln’
- The DotNet pack task only packages ‘common/common.B/common.B.sln’
Create a pipeline for each package
Finally you can create a pipeline to build each package by simply selecting ‘New pipeline’ from the Pipelines tab and providing the the azure-pipelines.yml file for that package.