Jenkins .NET job

This entry will document how to setup a basic localhost implementation of a simple Jenkins job dealing with technologies that many devs use at work and more importantly at home for their own projects. We’ll deal with:

– detecting a commit on Github
– building a .NET solution
– running MSUnit tests
– deploying
– sending an email

The incentive to write this entry comes from a week spent on setting up Jenkins. That in itself is not such a big deal, but having to spend several days on deploying and then further several hours simply to get Jenkins to send a simple email was enough to get me to write this as a reminder to myself.

Before we start, a quick word about the whole setup:

  • Windows 10
  • IIS 10
  • VS 2017
  • MVC application named SportsStore.com (irrelevant, but just so you know)

Along with all that, you’ll need to download nuget.exe. We’ll explain more when we get to it.

Detecting a commit on Github

After you create a Freestyle project, go to the Configuration -> General tab and mark as below:

Untitled1

Note that you don’t have to provide GitHub credentials if you’re referring to a public repository.

Untitled1

Building a .NET solution

Before we can start building a Visual Studio solution, we must have all the dependencies sorted out and for that we’ll need Nuget. We don’t need a plugin, downloading Nuget.exe is enough. Google on how to do that. I’ve placed the file in the WORKSPACE directory. When done, add a “Build step” -> “Execute a Windows batch command” and paste the following command:

REM Restore missing packages with NuGet
"%WORKSPACE%\nuget.exe" restore "%WORKSPACE%\SportsStore.sln"

Next step would be to download the MSBuild plugin. Go to “Manage Jenkins” -> “Plugin Manager” and find “MSBuild Plugin”. Select and download.

You’ll now have to help Jenkins configure MSBuild. Go to  “Manage Jenkins” -> “Global Tool Configuration” and configure it so it points to a valid MSBuild installation (see figure below).

Untitled1

Now we have to build the actual solution itself:

Untitled1

Running MSUnit tests

We’re now ready to automate unit tests on our solution. Add a “Build step” -> “Execute a Windows batch command” and paste the below command. The command has two parts: first we delete the current unit test results file and then we run the tests.

REM Run unit tests.
del "%WORKSPACE%\SportsStore_UnitTests_Results.trx"
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\mstest.exe" /resultsfile:"%WORKSPACE%\SportsStore_UnitTests_Results.trx" /testcontainer:"%WORKSPACE%\SportsStore.UnitTests\bin\Release\SportsStore.UnitTests.dll"

This concludes the Build part of the pipeline.

Before we can move on to notifying your team members about any potential errors that might have occurred, we would first like to have access to a more finely formatted test results. For that matter you’ll need to download “MSTest Plugin”. By now you know where to do that. After you’ve downloaded it go back to your project and add: “Post-build actions” -> “Publish MSTest test result report”. Default configuration is ok – no need to change anything.

For some reason, mstest.exe creates extra folders each run, with .dll’s necessary to run the tests. Folders are named SYSTEM_%computername% (at least on my system). It’s time to clean these up after tests have been run.

REM Remove folders created by mstest.exe
for /f "delims=" %%i in ('dir /a:d /b *%%computername%%*') do rd /q /s "%%i"

Deploying

Solution is buildable, tests have all passed – now it’s time to deploy the solution. It’s a two step process. Before we start, always make sure that you deploy only the relevant project(s). If you have a project representing your domain model you don’t need to deploy that – build it and deploy a .dll with your front-end project (MVC in my case). Bundling necessary .dlls will be taken care of during the build step.

Please note that the following configuration will deploy your application from the development folders onto a local IIS server, into an application named “SportsStore.com”.

Create a Build Step “Execute Windows batch command” to build your project using the following command:

REM Create a deploy package.
"C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" "%WORKSPACE%\SportsStore.WebUI\SportsStore.WebUI.csproj" /T:Build;Package /p:Configuration=DEBUG /p:OutputPath="obj\Debug" /p:DeployIisAppPath="/Default Web Site/SportsStore" /p:VisualStudioVersion=14.0

Then create another Build Step “Execute Windows batch command” to deploy your project using the following command:

REM Deploy package to local IIS.
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:package="SportsStore.WebUI\obj\Debug\_PublishedWebsites\SportsStore.WebUI_Package\SportsStore.WebUI.zip" -dest:auto -setParam:name="IIS Web Application Name",value="SportsStore.com" -allowUntrusted=true

Sending an email

Funny, but this was the trickiest part. It turns out that for some reason, Jenkins would not save my “Extended E-mail Notification” SMTP settings. At one point, it did save the setting and the emails started working. Below is how your settings should look, take care that the details in red are stored (reload page after storing, to make sure):

Untitled1

Post-build actions

First of all, we’d like to format our tests a bit nicer and for that we’ll use “Publish MSTest test result report. We already downloaded that plugin earlier, so we’re ready to configure this step. Under “Add post-build action” select and define as below:Untitled1

Final step is to send an email, but just in case the build failed. Do as below:

Untitled1.png

Open Advanced Settings and continue configuring:

Untitled1.png

Conclusion

This should be enough to get you on your way with automating a simple .NET deployment process on your localhost, for learning purposes. You’ve now implemented a simple workflow, enabling Jenkins to:

  1. Detect a commit.
  2. Pull changes.
  3. Build the solution.
  4. Run tests.
  5. Perform cleanup.
  6. Deploy relevant projects.
  7. Send an email if any of the steps fail.

In my opinion, next iteration(s) should provide following elements:

  1. allow GitHub to notify your Jenkins instance when a push has occurred, so you can react instantly, instead of pinging the server every so often as we do now. But that’s a topic for another article.
  2. Building on point 1, to detect a push on master and merge back into feature branches automatically.
  3. Parameterize Jenkins project so we can reuse it.

But these are topics for another article.