Continuous integration and continuous deployment is the holy grail of the modern DevOps.
Jenkins is the most popular continuous integration tool out there, but it requires some other knowledge to set it up, because Jenkins does not provide full out-of-the-box features for .Net projects.
Installing Jenkins and set up to use source code control system such as Git is relatively easy.
Tip – Set up to use BitBucket
When using Github, it’s OK to use id/password as normal.
However, when it comes to Bitbucket, repository URL needs to be like https://bitbucket.org/rocker8942/marketwatchconsole.git without an username at the start of URL. I spent some time pulling out my hair for this.
Setting up build process could be a bit challenging and require lots of external tools. So, just skipping up to setting up source code set up, I’ll focus on build and release / deployment automation process in Jenkins.
It could be easier if you use TeamCity and Octopus Deploy, but if you have to go with Jenkins due to cost of whatever, the rest of the process will be helpful.
External tools as below will be used to set up Jenkins Build steps.
- Octopack – nuget package to make the project into nuget package so that it’s easy to handle.
- Nuget.exe
- MSBuild.exe
- MSTest.exe
- Powershell Script
- Octo.exe – Octopus Deploy console app (if you use Octopus Deploy)
It looks a lot when naming it, but most of it should be familiar to .Net developer even though it may not being used often as a console application.
There are a few steps to set this up.
#1 Nuget restore
Nuget packages don’t need to be included in source control system, nuget packages can be restored just before build process.
Just use nuget command line command.
e.g.
"C:\Program Files (x86)\NuGet\nuget.exe" restore yourSolutionName.sln
#2 Build
#2-1 Just build in Jenkins
Build is done basically by MSBuild using the argument as below.
/t:Rebuild /p:Configuration=Release;RunOctoPack=true /p:OctoPackPackageVersion=1.0.${BUILD_NUMBER}
By running Octopack, the compiled files are packaged as a nuget pacakge, which is basically a zip file.
Even though we build an app with configuration pamareter ‘Release’, which create compiled library using ‘Release’ configuration. Web.config is not transformed to Release. So, we will transform it to release version later using Powershell.
#2-2 Build and publish to Octopus Deploy
or, we can publish the complied package into Octopus Deploy server if you used Octopus deploy by using the argument as below. After this, Octopus Deploy will release the package to servers using this package.
/t:Rebuild /p:Configuration=Release;RunOctoPack=true;OctoPackPublishApiKey=UseYourOwnAPIKey;OctoPackPublishPackageToHttp=http://localhost:8201/nuget/packages /p:OctoPackPackageVersion=1.0.${BUILD_NUMBER} /p:VisualStudioVersion=14.0
It’s similar with the previous argument. Just added OctoPackPublishApiKey and OctoPackPublishPackageToHttp
#3 Run Octopus to create release
By using Octopus console tool, we can even run Octopus Deploy from Jenkins (or custom build automation script) to create release
"C:\Octopus\Tools\Octo.exe" create-release --project MarketWatchConsole --version 1.1.%BUILD_NUMBER% --packageversion 1.1.%BUILD_NUMBER% --server http://localhost:8110/ --apiKey %OctopusApiKey% --releaseNotes "Jenkins build [%BUILD_NUMBER%](http://localhost:8054/job/MarketWatchConsole/%BUILD_NUMBER%)/"
#4 Run Test
Unit test can be done by calling MSTest.exe within Jenkins.
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe" /resultsfile:"%WORKSPACE%\AutomationTestAssistantResults.%BUILD_NUMBER%.trx" /testcontainer:"%WORKSPACE%\TestProject\TestProjectTests\bin\Release\TestProjectTests.dll" /nologo
#5 Release
To get the benefit of powerful Powershell, release script can be written by Powershell and loaded into Jeknins as a build step.
# # Demo.ps1 # $destination = "D:\DemoProject" function XmlDocTransform($xml, $xdt) { if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) { throw "File not found. $xml"; } if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) { throw "File not found. $xdt"; } $scriptPath = "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web" Add-Type -LiteralPath "$scriptPath\Microsoft.Web.XmlTransform.dll" $xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument; $xmldoc.PreserveWhitespace = $true $xmldoc.Load($xml); $transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt); if ($transf.Apply($xmldoc) -eq $false) { throw "Transformation failed." } $xmldoc.Save($xml); } # Clean up - Pre remove-item $destination\bin\* remove-item $destination\Content\* remove-item $destination\fonts\* remove-item $destination\Scripts\* remove-item $destination\"Service References"\* remove-item $destination\Views\* # unzip package & 'C:\Program Files (x86)\NuGet\nuget.exe' install DemoProject -Source $ENV:WORKSPACE\DemoProject\bin -OutputDirectory "D:\" -ExcludeVersion # transform configs XmlDocTransform $destination\Web.config $destination\Web.Release.config # Clean up - Post remove-item $destination\*.$ENV:BUILD_NUMBER.zip remove-item $destination\Web.Debug.config remove-item $destination\Web.Release.config remove-item $destination\*.xml remove-item $destination\*.nuspec remove-item $destination\bin\*.pdb remove-item $destination\DemoProject.nupkg
As most of automation is done by calling console application, Jenkins itself doesn’t do much here, but hosting and managing all these steps in a central place will be its role.
A good thing about setting up automation in Jenkins using various external console application tools is that we can set this automation up without Jenkins, because build / test / release process can be achieve by creating custom script.