Extending a .NET Development Tree – Basic Distributions

If you read my thoughts on setting up a .NET development tree you might be interested to know how we can extend these ideas to gain even more value from automation and configuration on our .NET projects. This series of entries should help you with these investigations.

In this first entry I’m going to talk about Distributions. Distributions are one kind of artifact produced by running the automated build of your project tree. They are typically a bundling of compiled code, dependencies, configuration and documentation that enables someone to get started using your application, or update an existing copy of your application. Distributions tend to take the form of file archives (such as Zip files) or installers (such as MSI files.)

Console applications tend to allow the simplest kind of distribution. Our Sycamore example project that we created in the original article has a console application so we’re going to use this to generate an example distribution.

First of all, we’re going to add a full target to our build script. A ‘full’ build is a concept that means ‘run an end-to-end development build, and produce all artifacts’. For Sycamore’s build it looks like this:

<target name="full" depends="clean, test, dist"	description="Compiles, tests, and produces distributions" />

So far, so good. Now we need to actually create our dist target. Here it is, and I’ll explain it afterwards:

<target name="dist">

<copy todir="${build.dir}dist">

<fileset basedir="${build.dir}DebugSycamoreConsole">

<include name="***"/>

<exclude name="***.pdb" />

</fileset>

</copy>

<zip zipfile="${build.dir}Sycamore.zip">

<fileset basedir="${build.dir}dist">

<include name="***" />

</fileset>

</zip>

</target>

There are 2 clear sections to this target. The first is to setup the file tree of our distribution. In our case, we just want the Sycamore application. We specifically don’t want the .pdb debugging file. (Note to those thinking Why didn’t you just use a release build? – I’m just using the .pdb as an example of a file produced by the compile step that we don’t want in our distribution.)

One of the nice side-effects of using the Visual Studio solution/project files for defining our automated build is that all required dependencies will already be copied to the build output folder, ready for us to copy to the dist folder. In fact you can even use the pre- and post- build scripting enabled for projects in Visual Studio (but make sure that your exclude list filters out any build event batch files!) In this first section you could also add extra <copy /> sections to include documentation, license files, etc.

Once the file tree is complete, we can create the actual distribution file. In our case, we use a simple Zip file, which is appropriate for XCopy Deployment. Since all the hard work has been done in the first part of the target, the <zip /> call is very simple.

Distributions typically get much more complicated than this. Deciding exactly what files to include is something you’ll need to think carefully about. Also, you need to decide to what extent your distribution should be environment specific. For example, you may want to produce a distribution of a web application, the configuration of which has already been setup to for your production database. The benefit of this is less work for your deployment team. The drawback is that you won’t be able to deploy this distribution somewhere else. Typically, your development distributions will be environment generic, and you may introduce post-development builds to deploy and configure your application for specific environments, but that really is subject for a much bigger discussion!

Distributions are also tied in to a versioning strategy, and stored on a server somewhere, but that is also out of scope for this particular entry.

To summarise this part:

  • Produce distributions to enable your project to be used elsewhere.
  • Your distributions should be generated by a full development build.
  • Distributions should include a combination of code, dependencies, configuration and documentation.
  • Separate out the work of deciding what should be in your distribution, and creating the distribution file itself.