SOUTHWORKS Dev Team
January 8, 2021
This post is intended to give a brief introduction of how to create a Jenkins Pipeline for deploying a .NET Core (or .NET) application contained in an MSIX package, including unit tests and code coverage. Since this isn’t the most common workflow (because .NET has better integrations with other tools like Azure DevOps Pipelines), the documentation is a little scattered, so we are creating this post to facilitate this process.
First of all, we present a very brief description of what Jenkins is and what it does. Also, let me mention the team that worked on this, contributing as well as giving feedback: Ignacio Boada, Matías Nicolás Gesualdi, Gabriela Gutierrez, Nicolas Bello Camilletti, Mauro Krikorian and Juan Pablo Tomasi.
Taken directly from its official documentation, Jenkins is a self-contained, open-source automation server that you can use to automate all sorts of tasks related to building, testing, and delivering or deploying software.
Jenkins works by automatically executing certain scripts to generate files that are required for deployment. These scripts are called JenkinsFiles, and they are just text files that can contain declarative or scripted code. In this post we will be focusing on declarative pipelines.
There are several ways to automate Jenkins execution, for example, triggering it periodically, or when a developer commits to a branch or creates a Pull Request.
Jenkins pipelines are a suite of plugins that supports implementing and integrating continuous delivery pipelines into Jenkins. Once triggered, a Jenkins pipeline will execute any code in its JenkinsFile, and generate the artifacts that are needed for deployment. To define a Jenkins Pipeline, you write a JenkinsFile, which in turn can be committed to the source control repository. This is the foundation of “Pipeline-as-code”; treating the CD pipeline as part of the application to be versioned, and reviewed like any other code.
First, Jenkins requires Java 8 or 11 JDK. You can download it by clicking here (SDK version 8). Also, you have to set the Java environment variables, if you haven’t done so already. You can do this by going into the Environment Variables settings (you can find it by typing the Windows key and directly typing “environment”). Once there, create two new variables, JRE_HOME and JAVA_HOME, and set them to your jdk and jre executables.
The easiest way to get all the tools we need is to install Visual Studio Community 2019. You can download it from here.
Jenkins will need Git to be able to pull the code from repositories. You can download it from here.
In order to be more concise and not extend ourselves too much with this post, we won’t include here installation instructions for Jenkins, but you can find them in this tutorial, or in the official Jenkins page if you need something more elaborate like installing it on a docker container. When installing it, you will be asked to define administrator credentials. Write these down, as you will need them to access Jenkins later.
Once we have everything installed, we can start using Jenkins. After the installation, Jenkins will automatically start running on its own process. The way to access it is through a web browser in the http://localhost:8080 address. By default, Jenkins listens on port 8080, and is set to be accessible only from localhost. You can change it later by modifying “Jenkins Location” in the settings menu.
There are two pipeline types: Pipeline and Multi-branch pipeline.
A pipeline is intended to track a single branch (usually the master branch) and has a single JenkinsFile. By convention, this file is usually placed in the root directory, but you can move it somewhere else, and specify its location when creating the pipeline.
A Multi-branch pipeline is intended to support multiple environments, so you can track several branches at the same time. Each of these branches must include a JenkinsFile, and in this case we can’t change the location, all of them must be in their respective root directory.
The multi-branch pipeline will then look for JenkinsFiles in all branches, and trigger a deployment for each one that has changes.
If creating a Multi-branch pipeline, we suggest using the new BlueOcean plugin.
BlueOcean is a plugin that changes most of Jenkins GUI. It also comes with many other plugins integrated, that make some workflows, like integration with GitHub, a lot easier. Creating a Multi-branch pipeline with BlueOcean is much easier than using the normal Jenkins interface.
To automatically integrate with GitHub or other version control repository, you need to provide credentials to Jenkins. The best way to do this (and the only one if you are using Two-Factor Authentication) is to create a Personal Access token.
Once the pipeline has been created, we have to define at least one JenkinsFile. To help in the creation of declarative pipelines, Jenkins offers its Declarative Directive Generator. You can access it from the Pipeline configuration page. This tool has preloaded many common actions that are used in pipelines. These actions can receive parameters, so if what you want to do is in the list, you just fill the parameters and click “Generate Pipeline Script”, and the tool will show the code that must be added to the JenkinsFile.
Pipelines are normally separated in “stages”. Each of these stages executes some actions that are important for the deployment. Up to this point, we have shown how to use Jenkins in a more or less generic way. Now we will show what specific steps we have to add in order to create a pipeline for deploying a .NET Core application.
One problem we had is that Jenkins workspace is defined by default inside the Windows/System32 folder. In 64-bit Windows versions, the System32 folder is not accessible by 32-bit applications. Since Visual Studio and MSBuild.exe are 32-bit applications, we had problems with them recognizing files in the Jenkins default workspace. We recommend changing the default workspace to another location to avoid this issue.
1. Convert the .coverage file: The “.coverage” is a proprietary format from Microsoft. To be able to see the results in Jenkins, we have to convert the “.coverage” file into a “.coveragexml” file by using the CodeCoverage.exe app:
2. Generate the report: by using the ReportGenerator.exe app.
3. Publish HTML report: To make the results from the tests and the code coverage available in the Jenkins pipeline, we use the HTML Publisher plugin. After installing it, you can use it as follows. Parameters are self-explanatory.
If your HTML report shows as if not having any styles, follow the steps in this post.
Once we have the JenkinsFile ready, we can try running the pipeline directly from the Jenkin’s Pipeline homepage. Jenkins will show which stages ran successfully and how long it took to complete. It will also provide a link to the artifacts if they could be generated.
As we said before, one option for running Jenkins is polling for changes every certain amount of time. This approach is inefficient because it does unnecessary polls where there are no changes, and may take too long to make a poll when there are changes. To solve this, we can use webhooks. In this case, we used GitHub, so we will explain how to do this for a GitHub repository.
GitHub Webhooks are a mechanism for sending requests to an URL when certain conditions are met. This POST request is then used by Jenkins to know if it must start executing a pipeline.
To create a webhook we must go to the Settings->Webhooks section of a GitHub repository.
The Payload URL must have the form http://<jenkins-url>/github-webhook/. (Don’t forget the last “/”, otherwise it won’t work). The <Jenkins-url> can be configured in Jenkins by changing its “Jenkins URL” attribute.
Keep in mind:
Once the webhook is created, GitHub will send a POST request to Jenkins every time that the selected events are raised, and this will trigger the Jenkins pipeline.
Jenkins is actually much more powerful than what we have shown this post, but it requires a lot of expertise for complicated workflows. We have only shown how to solve a simple scenario that is not-so-common, and that can serve you as an introduction. Thank you for reading.
Thanks to Nicolás Bello Camilletti
Originally published by Sebastian Rial for SOUTHWORKS on Medium 08 January 2021