Setting Up SVN and CC.NET for .NET Development
Subversion and CruiseControl.NET can be invaluable tools in your .NET development process. There are many resources available to help you get started which I'll try to gather in this post along with some of my personal experiences.
Let me start with the list of recommended software:
- VisualSVN Server is the ultimate Windows version of Subversion including a simple setup and powerful management tools. If you are planning to install a Subversion server on Windows it should be your first choice.
- AnkhSVN is a Subversion Source Control Provider (SCC) for Visual Studio. As long as you're not using Express editions of Visual Studio, this is the suggested way of working with SVN directly from Visual Studio IDE.
- TortoiseSVN is a Windows shell extension for working with Subversion from within Windows Explorer. When you're not working with Visual Studio solutions this is the best choice for using SVN.
- CruiseControl.NET is a continuous integration server including a web dashboard and CCTray - a system tray client application for monitoring and controlling builds.
If you're not already familiar with the above mentioned products, you should consult their documentation or search for tutorials. I will rather focus on setting up your development and release process. If you haven't done so already I suggest you first read the following articles by Ariejan de Vroom:
I mostly based my configuration on the ideas in these articles. I have projects configured in CC.NET to build all copies of the project: trunk (
ProjectName-Trunk), all branches (
ProjectName-REL-#.#) and all tags (
ProjectName-v#.#.#). To identify individual builds I am using CC.NET's Assembly Version Labeller together with
AssemblyInfo MsBuild Community Task.
Assembly Version Labeller is really simple to configure. You only need to add a short snippet to each project:
<labeller type="assemblyVersionLabeller"> <major>1</major> <minor>0</minor> <build>0</build> </labeller>
I'm using the following versioning policy:
- I start each project with version 1.0.0.
- Once it's ready for release I make a copy of the trunk in the
REL-#.#containing the major and the minor version number. Immediately afterwards I bump the version of the trunk (only minor or major and minor, depending on the nature of the new features planned).
- In the release branch I make the necessary changes before release (e.g. I change the
AssemblyProductname to distinguish between development and release quality builds) and make another copy in the
v#.#.#containing the major, minor and build version numbers. Immediately afterwards I increase the build version number in the release branch.
- I make no changes to the copies in the
tagsdirectory. All bug fixes go to the release branch. Once I'm ready for a new release I repeat the previous step.
Since I don't specify the revision number directly, the SVN Revision number gets used automatically. This makes it possible to match each build to the revision of the code in SVN.
To put the generated assembly version in the build I am using the
AssemblyInfo MsBuild task. There are two steps involved in doing this.
First you need to move the
AssemblyFileVersion attributes from the auto generated
AssemblyInfo.cs file into a new file. In my case the
AssemblyVersion.cs has the following contents:
using System.Reflection; [assembly: AssemblyProduct("ProjectName DEV")] [assembly: AssemblyVersion("184.108.40.206")] [assembly: AssemblyFileVersion("220.127.116.11")]
Next you have to modify your project file (
*.csproj) by importing the community tasks and adding a call to the
AssemblyInfo MsBuild task:
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" /> <Target Name="BeforeBuild"> <AssemblyInfo Condition="'$(CCNetLabel)' != ''" CodeLanguage="CS" OutputFile="Properties\AssemblyVersion.cs" AssemblyProduct="ProjectName TRUNK" AssemblyVersion="$(CCNetLabel)" AssemblyFileVersion="$(CCNetLabel)" /> </Target>
If you have never edited a project file before, you might want to read these first:
One more thing to note which might not be all that obvious. The
Condition in the
AssemblyInfo task is met only when building from CC.NET. For builds in Visual Studio the task doesn't regenerate the
AssemblyVersion.cs file therefore the revision number is always
0 and the
AssemblyProduct has a
DEV suffix as defined in the original file. Also I remove the
TRUNK suffix from the
AssemblyProduct attribute of the
AssemblyInfo task when moving code from trunk to release branches to separate between the two.