Loading...
Loading...
Marco Franssen

In part 1 of this series, we created a basic MSBuild script to compile our projects. I also provided a simple batch file to make the build script easier to run.
In this part, we'll clean the output folders before building again and retrieve missing NuGet packages with package restore. Let's look at package restore first.
NuGet package restore can be enabled in Visual Studio. In this workflow, I enable it so we don't have to keep all our NuGet packages in source control. Each team member can then download missing packages automatically when building the project in Visual Studio. Our build server won't do this by default, so we'll create a custom target to handle it.
<!-- The Clean Target -->
<ItemGroup>
<ProjectFiles Include="**\*.csproj" />
</ItemGroup>
<Target Name="Clean">
<Message Importance="high" Text="Cleaning folders" />
<RemoveDir Directories="$(ReportsPath)" Condition="Exists('$(ReportsPath)')" />
<MakeDir Directories = "$(ReportsPath);$(ReportsPath)\MSpec;$(ReportsPath)\Coverage" />
<!-- Clean the source code projects -->
<MSBuild Projects="@(ProjectFiles)"
ContinueOnError="false"
Targets="Clean"
Properties="Configuration=$(Configuration)" />
</Target>This target cleans our project output folders for the given configuration. For example, if you specify Debug, it cleans the /bin/Debug folder. We use an ItemGroup to find all the project files, then pass them to an MSBuild task to clean their outputs.
Notice that we also recreate the reports directory, where we'll store our unit test reports and other results. In the next part of this series, we'll create a target to generate those reports.
In the package restore task below, quotation marks are encoded as ".
For LoadNugetPackages, we also use an ItemGroup, this time to find files named packages.config. We pass these files to the Exec task, which runs nuget.exe.
<!-- The LoadNuGetPackages Target -->
<ItemGroup>
<NuGetPackageConfigs Include="$(MSBuildStartupDirectory)\**\packages.config" />
</ItemGroup>
<Target Name="LoadNuGetPackages">
<Message Importance="high" Text="Retrieving packages for %(NuGetPackageConfigs.Identity)" />
<Exec Command=""$(SrcPath)\.nuget\nuget" install "%(NuGetPackageConfigs.Identity)" -o "$(SrcPath)\packages"" />
</Target>Adding both targets gives us the following MSBuild script. Notice the DependsOnTargets attribute on the Compile target: it makes sure Clean and LoadNuGetPackages run first. With the Nuget package restore setup used here, your solution contains a .nuget folder with the NuGet executable. Commit that executable to source control too, so the build server can access it later.
<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>
<!-- The Clean Target -->
<ItemGroup>
<ProjectFiles Include="**\*.csproj" />
</ItemGroup>
<Target Name="Clean">
<Message Importance="high" Text="Cleaning folders"/>
<RemoveDir Directories="$(ReportsPath)" Condition="Exists('$(ReportsPath)')" />
<MakeDir Directories = "$(ReportsPath);$(ReportsPath)\MSpec;$(ReportsPath)\Coverage" />
<!-- Clean the source code projects -->
<MSBuild Projects="@(ProjectFiles)"
ContinueOnError="false"
Targets="Clean"
Properties="Configuration=$(Configuration)" />
</Target>
<!-- The LoadNuGetPackages Target -->
<ItemGroup>
<NuGetPackageConfigs Include="$(MSBuildStartupDirectory)\**\packages.config" />
</ItemGroup>
<Target Name="LoadNuGetPackages">
<Message Importance="high" Text="Retrieving packages for %(NuGetPackageConfigs.Identity)" />
<Exec Command=""$(SrcPath)\.nuget\nuget" install "%(NuGetPackageConfigs.Identity)" -o "$(SrcPath)\packages"" />
</Target>
<!-- The Compile Target -->
<Target Name="Compile" DependsOnTargets="Clean;LoadNuGetPackages">
<Message Importance="high" Text="Compiling core 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>Now we're getting somewhere! When we run our batch file, it first cleans the output folders, retrieves any missing NuGet packages, and then compiles our assemblies.
In the next part, we'll add a target to run our MSpec tests and generate a code coverage report from those test assemblies. Stay tuned, and share this article with your friends.
Marco Franssen
Connect a .NET MSBuild CI script to Jenkins, trigger builds from GitHub, configure repository access, and publish MSpec and code coverage reports.
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
Start a .NET continuous integration build with an MSBuild script and a Windows batch file, then choose Debug or Release builds from the command line.
Marco Franssen
A personal look back at my 2012 blog posts, favorite technical articles and starred GitHub projects, covering JavaScript, .NET, CQRS and Windows.