Loading...
Loading...
Marco Franssen

Recently, I've been setting up continuous integration (CI) for my C# project using MSBuild. In this series, I'll show you how I build up a CI workflow with Jenkins, MSBuild, NuGet, and Git.
We'll start by creating an MSBuild script to compile our code, along with a small batch file to make it easy to run.
Once that's in place, we'll add targets for tasks such as unit tests, integration tests, code coverage, and packaging.
We'll take an agile approach, improving our build process based on validated learning.
First, we need some basic MSBuild knowledge. There are plenty of introductions on the web; the MSDN documentation is a good starting point.
Let's assume we have the following project structure in our Git repository and local file system.
src (contains our source code)
|- lib (contains build output, and third party libs not available on nuget)
|- reports (contains code coverage reports, test scenarios and test results)
|- ci.msbuild (your msbuildfile)
`- ci.msbuild.cmd (your batch file to execute the build on your local machine)In this first version of our build file, we have only one target (Compile), which builds our projects. We don't use the solution file because someone could disable projects in the solution's build configuration. By specifying the projects explicitly, we make sure all the necessary projects are built. We also use a PropertyGroup to define some variables.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Compile">
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
<DefineSolutionProperties>false</DefineSolutionProperties>
<!-- General Paths -->
<RootPath>$(MSBuildProjectDirectory)</RootPath>
<SrcPath>$(RootPath)\src</SrcPath>
<ReportsPath>$(RootPath)\reports</ReportsPath>
<ToolsPath>$(RootPath)\tools</ToolsPath>
<Packages>$(SrcPath)\packages</Packages>
</PropertyGroup>
<Target Name="Compile">
<Message Importance="high" Text="Compiling projects"/>
<MSBuild Projects="$(SrcPath)\MyProject.Core\MyProject.Core.csproj"
Properties="Configuration=$(Configuration);Platform=$(Platform)" />
<MSBuild Projects="$(SrcPath)\MyProject.Web\MyProject.Web.csproj;$(SrcPath)\MyProject.Win\MyProject.Win.csproj"
Properties="Configuration=$(Configuration);Platform=$(Platform)"
BuildInParallel="true" />
</Target>
</Project>With the following batch file, we can easily run the build script and choose a build configuration.
@echo off
setlocal
set msbuild="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe"
set /p configChoice=Choose your build configuration (Debug = d, Release = r? (d, r)
if /i "%configChoice:~,1%" EQU "D" set config=Debug
if /i "%configChoice:~,1%" EQU "R" set config=Release
%msbuild% _ci.msbuild /nologo /m /v:m /t:Compile /p:Configuration=%config%
pause
endlocalAs you can see, we use msbuild.exe and pass our ci.msbuild file as an argument. The /nologo parameter removes the msbuild header text from the console output. The /m parameter enables parallel builds based on the processors available on your machine. The /v:m parameter sets verbosity to minimal, so the console shows less output. The /t:Compile parameter tells msbuild.exe to run the Compile target, and /p:Configuration=%config% passes our build configuration (Debug or Release) into the build.
If we omit the /p parameter, the configuration defaults to Debug, as defined in the build script's PropertyGroup. If we omit /t, the default target, Compile, runs as defined in our msbuild file.
You can now build your projects using a simple batch file. In the next part, I'll add a LoadNuGetPackages target to download NuGet packages based on your package configurations. We'll also add a Clean target to clean our directories before compiling again, so old assemblies from previous builds don't get in the way. Please share this article with your friends, and stay curious about the next part of the series :D.
Marco Franssen
Extend a .NET MSBuild CI script with MSpec tests, OpenCover code coverage, and ReportGenerator reports that you can later publish through Jenkins.
Marco Franssen
Add Clean and LoadNuGetPackages targets to a .NET MSBuild script so your CI build clears previous output and restores missing NuGet packages before compiling.
Marco Franssen
A personal look back at my 2012 blog posts, favorite technical articles and starred GitHub projects, covering JavaScript, .NET, CQRS and Windows.
Marco Franssen
Explore the Knockout.js mapping plugin to turn JSON into observable view models, customize property mappings, and build nested employee models.