In this article, based on chapter 7 of Agile ALM, contributor Hadi Hariri shows you how easy it is to use a build framework such as MSBuild or TeamCity to build .NET software. He also demonstrates how to add Continuous Integration (CI) with .NET applications to an Agile ALM CI ecosystem that can also integrate other artifact types, such as Java.
This article is based on “Agile ALM – Lightweight Tools and Agile Strategies“, published in August, 2011. It is being reproduced here by permission from Manning Publications. Manning Publications Co. publishes computer books for professionals–programmers, system administrators, designers, architects, managers and others. All print Book purchases include free eBook formats. eBooks are sold exclusively through Manning. Visit the book’s page for more information.
This article will show you how easy it is to use a build framework such as MSBuild to build .NET software. Additionally, it will demonstrate how to add CI with .NET applications to an Agile ALM CI ecosystem that can also integrate other artifact types, such as Java. To demonstrate using CI with .NET, we’ll use TeamCity as the build server, but build frameworks like MSBuild are agnostic regarding build servers, so you can add your build scripts to other build servers as well. TeamCity is a powerful build server that can be used to integrate different platforms and languages, including Java and Microsoft-related ones, in parallel. The strategy presented in this article is to orchestrate best-of-breed tools and integrate them into a configured, personalized toolchain. You don’t need to stick to proprietary Microsoft tooling, such as Visual Studio, to build your .NET software; rather, you can use lightweight tools instead.
Additionally, it’s not necessary to use Microsoft Team Foundation Server to manage your .NET sources; you can manage the sources in parallel with other project artifacts in the same tool, such as Subversion, in order to foster an Agile ALM approach. You’ll also see how easy it is to temporarily add additional build machines to your CI system by running builds in the cloud.
Like many other tools and practices in .NET, CI originated from the world of Java. But despite its relative newcomer status, .NET has certainly gained maturity in terms of adoption of best practices that evolved in the Java world. Much of this is impacted by the number of tools in .NET that support the key elements required for successful CI.
Ted Neward on integrating .NET and Java systems
I once asked Ted Neward, .NET and Java expert, “What’s your opinion about adding .NET artifacts to continuous integration processes and systems that are based on open source or lightweight tools, in the case that projects don’t want to use TFS, Visual Studio, or other Microsoft products?” This was his answer:
“In general, as much as I spend time handling integration between .NET and Java systems, I’m not a huge fan of mixing the developer tools across those two platforms—trying to get Maven to build .NET artifacts, for example, can be a royal pain to get right. In general, the best success I’ve had with this is to fall back to MSBuild, and kick it off as you would any other command-line tool. The build results can be captured to a text file and examined later, or if a more fine-grained control is needed, a shell around MSBuild can be built (probably with PowerShell, depending on the complexity of the problem) to capture events during the build. This doesn’t mean I’m going to tell .NET developers to stick with plain-vanilla Visual Studio or TFS, mind you. Better tools definitely exist for handling continuous integration builds than what comes out of the box. Pick one of those CI tools, figure out how to invoke a command-line tool from the CI infrastructure, use that to kick off MSBuild, and call it a day.”
When talking about build tools in the .NET space, there are two main contenders. On one side there’s NAnt, which is a port of Java’s Ant, and on the other there’s MSBuild, which is the .NET framework’s native build system from Microsoft. The core principles behind MSBuild are the same as those for NAnt.
Using MSBuild to build .NET projects
MSBuild provides a series of targets, each of which defines one or more tasks to be carried out. Targets are a sequence of grouped steps; this is similar to Ant, where targets are a sequence of Ant tasks. The following listing shows a sample build script.
Listing 1 A simple build script for .NET with MSBuild
<?xml version="1.0" encoding="utf-8" ?>
<PropertyGroup Condition="'$(BuildType)'=='Release'"> #B
<Target Name="Clean"> #C
<Csc Optimize="$(Optimize)" DebugType="$(DebugType)"
<Target Name="Rebuild" DependsOnTargets="Clean;Build"/>
#A Custom item group
#B Property groups using conditions
As you can see, there’s support for concepts such as multiple targets (that is, one script being able to run different tasks and operations), property definitions, and conditions. Like NAnt, MSBuild is also extensible. You can create new tasks by implementing an interface and referencing it as an external assembly.
TeamCity, from JetBrains, supports CI for both Java and .NET projects and has become one of the most popular CI servers.
Using TeamCity to trigger .NET builds
TeamCity is available in two flavors: Professional, which is free, and Enterprise. It has quickly gained popularity over other tools, such as CruiseControl, due to its ease of use and rich feature set. In this part of the article, we’re going to look at some of the features that TeamCity provides, starting with visual configuration of the environment.
Visual configuration environment
One of the more painful issues with CruiseControl is the requirement to set up the configuration through XML files and having to make these changes on the production CI server. With TeamCity, rather than requiring users to have permission to access folders on the server, all access control is handled via a web interface, allowing different levels of permissions. All project configurations are carried out using this interface, making setup easier and less error prone. Figure 1 shows how you can configure a build runner to choose from among Ant, Maven2, MSBuild, NAnt, and many others.
Figure 1 Configuration in TeamCity: selecting a build runner (such as MSBuild or NAnt)
Ease of configuration is a main feature of TeamCity, although its ability to facilitate integration with other tools is also essential.
Integration is core
TeamCity was built with the goal of being integrated with other tools and frameworks. Each developer or company has its own policies and ways of working. Some prefer to use tools such as MSTest for testing and MSBuild for build automation, whereas others prefer to use open source tools such as NUnit and NAnt. TeamCity tries to accommodate as many frameworks as possible by providing support for a variety of them. This is a key feature when it comes to having a productive CI environment.
One of the core benefits of CI is immediate feedback. When you break the build, you need to know why, to see test results, and so on. All this needs to be easily accessible and viewable without requiring a lot of effort. By supporting different testing and code coverage frameworks, TeamCity allows this seamless integration. Figure 2 shows a sample output screen of build results with relevant information that allows you to investigate further if required.
Figure 2 Example TeamCity output screen showing test results
Apart from the more traditional build tools, TeamCity also supports some newer tools that are starting to gain interest among developers, such as Ruby’s Rake for build automation or Cucumber for testing. In addition to integrating with unit testing, code coverage, and automation tools, TeamCity also works with various types of source control management, including Team Foundation Server, Subversion, and some more popular distributed VCSs such as Git and Mercurial, as shown in figure 3.
Figure 3 Selecting a VCS for the .NET project build (with Subversion)
Another important aspect when it comes to integration is issue tracking systems. Again, TeamCity allows integration with common tools such as JIRA as well as Jet-Brains’ own issue tracker called YouTrack. The flexibility of building and storing sources makes Agile ALM effective. Using remote build agents and cloud computing are also popular practices.
Build agents and cloud computing
Many CI tools, including Jenkins, support the concept of build agents. The idea is to have one machine that handles the process and delegates the computing to other machines. As such, the main CI server would handle the configuring, reporting, and other non–CPU intensive processes, and one or more machines (called agents) would handle the compiling, building, and testing of the code. Figure 4 shows a build matrix that indicates the status of all agents and their utilization.
Figure 4 TeamCity showing agents
TeamCity has supported the concept of build agents from the beginning, but what’s new in the recent releases is its integration with cloud computing. Amazon’s EC2 cloud computing infrastructure is a pay-per-use concept where you pay for machines based on the number of hours they’re on—if your machine is running for, say, five hours, you would be charged for five hours of use. TeamCity uses EC2 via virtual build agents, which are similar to standard ones except that they run on virtual instances on the Amazon EC2. This means that TeamCity can dynamically start as many instances of agents as needed in order to keep the build queue under control during high loads. Additionally, TeamCity can shut down virtual build agents when they aren’t needed anymore; this minimizes EC2 consumption of uptime. Figure 5 shows how to create an EC2 cloud profile in TeamCity.
Figure 5 Server configuration, defining a cloud profile for EC2
CI is the same, whether it’s in Java, Ruby, or .NET. What’s important when it comes to implementing CI is having the correct tools to make the whole process efficient and fast. Spending time to integrate multiple products for every project is cumbersome and a waste of resources, and that’s why it’s important to have tools that can seamlessly work with multiple frameworks, platforms, and tools, such as Jenkins and TeamCity.
This leads to an effective toolchain that consists of one central CI server that integrates and works with different platforms and tools, such as Java and .NET.
We discussed using .NET without all of the associated Microsoft tools. Although it’s a proprietary platform, .NET can be handled with common tools. You don’t have to use a complete proprietary toolchain; you can use lightweight tools (such as Subversion) to store your artifacts and to manage your builds. In one case, we dropped an Ant script into a CI server. In a second case, we dropped the MSBuild script into TeamCity.