CI/CD build pipeline for .NET solutions using Cake2 – Azure Devops

In a previous article Build .NET solutions/projects using cake 2 I described how you can build a .NET solution using cake 2. In this tutorial I will explain how you can create your continuous integration pipeline to build your projects automatically with cake 2 and a build agent.

You should first store your project on a git repository. For the purposes of this demo I will choose Azure Devops. I first clone the repository and add the appropriate code. Then I push back to the remote.

Git commands:

git add
git commit -m "added code"
git push

Then under main branch the src folder will be located. In this folder the code is placed.

The second step is to create the pipeline and store it in the repository. Press new pipeline and then select your Azure Repos Git.

Then choose the starter pipeline on which we will add some tasks.

The code for the pipeline is just a simple powershell script that will execute the cake build command as we examined on the previous article.

trigger:
- main

pool:
  vmImage: ubuntu-latest
steps:

- task: PowerShell@2
  displayName: Build step using cake
  inputs:
    targetType: 'inline'
    script: 'dotnet cake'
    workingDirectory: '$(Build.SourcesDirectory	)/src/'

When I tried to build my application although the procedure started, I got an error about the targeting SDK.

You can resolve this by specifying your requested DotNet version.

- task: UseDotNet@2
  displayName: Use .NET 6
  inputs:
    version: '6.0.x'
    includePreviewVersions: true

Finally the build will be successful.

The final pipeline will be the below:

trigger:
- none

pr: none

pool:
  vmImage: ubuntu-latest
steps:

- task: PowerShell@2
  displayName: install cake tool
  inputs:
    targetType: 'inline'
    script: 'dotnet tool install Cake.Tool --version 2.0.0 --global'

- task: UseDotNet@2
  displayName: Use .NET 6
  inputs:
    version: '6.0.x'
    includePreviewVersions: true

- task: PowerShell@2
  displayName: Build step using cake
  inputs:
    targetType: 'inline'
    script: 'dotnet cake'
    workingDirectory: '$(Build.SourcesDirectory)/src/'

Build and run .NET applications on Azure DevOps

In this article I will explain how one can automate their .NET applications development using Azure DevOps. For the sake of this example I created a simple Console Application targeting .NET Framework 6.

The code only includes the below line.

Console.WriteLine("Hello from Azure Devops!");

First things first, a Git repository will be needed for the CI procedure. I chose to use Azure DevOps repositories as it is integrated with Visual studio and can be used very quickly. By pressing Add to Source Control a dialog will appear to choose the organization and project on which the repository will be created. This will create a new repository and you should then commit and push your code to the repository using the UI of Visual Studio.

After the push, the repository will be created on Azure DevOps

I disabled the automatic triggers on the repository with pr and trigger to none and I used the latest ubuntu machine as the build agent.

If a specific version of .NET is required it should be included in the task UseDotNet@2.

The building of the project is done from the DotNetCoreCLI@2 task. It will search everything with the .csproj extension and build it using the Azure CLI.

The last task that I included will run the application from the debug output folder.

trigger:
- none

pr: none 

pool:
  vmImage: ubuntu-latest

steps:

- task: UseDotNet@2
  inputs:
    version: '6.0.x'
    includePreviewVersions: true
    

- task: DotNetCoreCLI@2
  displayName: Building .NET project
  inputs:
    command: 'build'
    projects: '**/*.csproj'
    arguments: '--configuration debug'

- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      cd "bin/debug/net6.0"
      ./ConsoleApp1

As my application only Included a print message, this will be shown on the output.

More details on how to build .NET projects with Azure DevOps

https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops&tabs=dotnetfive

The specified module ‘MSAL.PS’ was not loaded because no valid module file was found in any module directory.

Recently when I used Dynamics 365 Finance and Operation tools plugin for Azure Devops I faced an issue with a missing Powershell module.

Error message:

##[error]The specified module 'MSAL.PS' was not loaded because no valid module file was found in any module directory.

In order to bypass this issue, add a PowerShell step with the below commands:

Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module MSAL.PS
Import-Module MSAL.PS

Your final pipeline should look like the one below.

An additional issue you may face, could relate with the service connection authentication endpoint. The error indicates that the common endpoint cannot be used and the specific tenant-endpoint should be used instead.

##[error]AADSTS9001023: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.

Go and edit your service connection details

Endpoint URL:

https://login.microsoftonline.com/organizations

Be sure that your user has sufficient privileges and that prerequisites are met as documented from Microsoft.

LCS doesn’t support service-to-service authentication. Therefore, only regular user credentials (that is, a user name and password) can be used. Because the pipelines don’t run interactively, multifactor authentication must not be set up for the account that you use. We recommend that you set up a separate user account that has limited access and strong credentials that can regularly be rotated for security purposes.

Create an LCS connection in Azure Pipelines

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/pipeline-lcs-connection

Trigger Azure Devops build pipelines using REST API

In some cases you may need to schedule pipelines execution on nights but the schedules yaml feature cannot accomplish your needs. This could could happen if you have to provide parameters as inputs on the pipelines for a specific project export/import. In this case you could trigger your pipelines with REST APIs using ansible or another scripting tool.

In this article I will explain how you could trigger pipelines execution using the REST API of Azure Devops.

First things first you should create a personal access Token (PAT) in order to get the access required to run the pipelines on your organization. You can accomplish that by pressing your profile icon and selecting the sub-menu shown below.

You can specify the expiration of the token along with the access permissions. For the simplicity of deployment I gave it full access. You will need to copy the token somewhere as it will not be accessible after the creation.

In order to trigger a new build we would have to use the POST HTTP verb. Along with that we will need the repository name, the project name and the build pipeline ID. The below URL uses build API of version 6.1-preview.6 with the parameters

Organization: GeralexGR
Project: test-project

https://dev.azure.com/GeralexGR/test-project/_apis/build/builds?api-version=6.1-preview.6

Using CURL we can get information of runs for a specific pipeline. For example in order to get the latest runs for pipeline with ID:11. In the below example you should replace PAT with your provisioned personal access token.

curl  --user '':'PAT' --header "Content-Type: application/json" --header "Accept:application/json" https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?api-version=6.1-preview.1

In order to implement a run of a build pipeline using REST APIs I will use Postman.

The selected verb is POST and the URL is the one mentioned above. By giving the URL on the input field, POSTMAN will automatically enumerate Query parameters.

In Authorization tab you should select Basic Auth. The username can be empty and the password will be your PAT.

On Headers tab, add Content-Type as application/json

In the body, you should specify the build pipeline ID in the JSON format that is shown in the picture. If you press Send, you will successful trigger your build pipeline with ID 11.

The next step is to edit the pipeline to include also input parameters.

In order to do that, I will use the latest version of the REST API that uses the runs URL instead of builds.

As shown in the picture the request URL will be pipelines/buildID/runs

https://dev.azure.com/GeralexGR/test-project/_apis/pipelines/11/runs?&api-version=6.1-preview.1

The logic of the pipeline will only print the parameters that has been provided as input on the REST API.

trigger:
- none

pr: none 

pool:
  vmImage: ubuntu-latest

parameters:
  - name: name
    displayName: Tell me your name.
    type: string
    
steps:
- script: echo ${{parameters.name}} "succesfully triggered this build from a REST API call"
  displayName: 'print message from automatically created pipeline'

You can see in the result that my name is printed.

Azure Devops Rest API documentation:

https://docs.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/run-pipeline?view=azure-devops-rest-6.0

Youtube video: