My blog has moved!

Visit http://www.codeprogression.com or http://www.elegantcode.com/about/richard-cirerol and update your bookmarks.

Monday, November 30, 2009

Wrapping up the StructureMap Automocking Container

I have been using StructureMap.AutoMocking with MSpec (Machine.Specifications) and Rhino.Mocks for a few months now.  Although I am very comfortable with the patterns that emerge from using the frameworks together, introducing StructureMap.Automocking to other developers is sometimes challenging.

When viewing a specification or test set up with the Rhino.Mocks or Moq automocking container, what is being tested is not readily apparent.  Once the concept is explained and demonstrated, these same developers seem to have no issue with maintaining the specifications/tests. 

I decided to wrap the details of the container to make the intention clearer and explanation easier.  I have started using this wrapper in my projects, and have found it makes building up specifications more efficient in my daily coding.

See the full post at ElegantCode.com

Sunday, November 1, 2009

State Pattern, Enumeration Class and Fluent NHibernate (Oh my!)

Recently, I needed to change a basic enumeration into a full-fledged state pattern. After getting all my domain classes updated, I began reviewing the persistence layer. And I hit a wall.  I wasn’t sure how I wanted to update my Fluent NHibernate convention to persist the current state.

See the complete post on ElegantCode.com.

Tuesday, October 6, 2009

AutoMapper Introduction and Samples from NETDUG

In September, Cory Isakson and I presented AutoMapper to the Boise .NET Developer User Group (NETDUG).  As promised, I have included the sample code here.  AutoMapper 1.0 RC1 is available on the CodePlex site.

The complete post is available on Elegant Code.

Sunday, August 9, 2009

Implementing Team City for .NET Projects, Part 5: Deployments

My apologies to all those who have been waiting for the deployment scenario – I appreciate your patience.  My approach to deployments has been a moving target – as it is starting to firm up a bit, I thought  I would write down some thoughts.

For more information on this series, please see the introductory post. In the previous post, I discussed build scripts as a way of extending the functionality of TeamCity.  If you downloaded the sample solution, you could see the tasks and structure of the NAnt and Rake scripts.  Since then, I have fully embraced Rake as my default build script engine; therefore, my script examples in this post are Rake scripts.

Don’t forget to listen to Elegant Code Cast #28 , where Chris Brandsma and I had the privilege of speaking with Jim Wierich, the father of Rake.

I have modeled the Rake scripts after the Fluent NHibernate and FubuMVC scripts.  I am also very interested in rake-dotnet from Pete Mounce.  Once rake-dotnet has support for NUnit and MSpec, I will be migrating my scripts to use it as a base library.  (Pete, I am actually planning on a patch for both – you know…in my spare time.)  Rake-dotnet is definitely worth checking out, especially if you use xUnit as your test library.

The Deployment Process

Here is a representation of my preferred folder structure for a solution:

before build

The following tasks are completed on each check-in:

  • MSBuild is called to clean and build both debug and release versions of the projects in the solution
  • Tests are run
  • An archive is created of each site and/or binaries (both debug and release versions), build scripts, and possibly SQL scripts

A post-build event is run on each web application project to pre-compile the site into a specific directory for each compilation type. My post build event looks like this:

%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_compiler.exe 
–nologo -errorstack -f -u -c -p $(ProjectDir) -v temp
$(SolutionDir)\Build\results\PrecompiledWeb\$(ConfigurationName)\$(TargetName)

The post-build event is also a good place to add any plug-in type binaries not directly depended on by your site, but included in your solution. Each site also has a set of configuration sources for each environment up the chain (nightly, test, staging, production)

After the build, I have added several folders and archive files to the build directory:

after build 

The archive files are stored in subsequent builds.  I never have to rebuild my solution for each platform.  Here is an example artifact path definition:

image

For the nightly build artifacts, I have the following definitions:

build/*=>Build
build/results/Debug.zip=>Sites
build/results/Release.zip=>Sites
build/results/DebugBinaries.zip=>Binaries
build/results/ReleaseBinaries.zip=>Binaries

For subsequent builds, the definitions change slightly:

build/**/*=>build
sites/**/*=>sites
binaries/**/*=>binaries

When the nightly build is run:

  • The check-in build is run, if it has pending changes
  • The desired (debug or release) site is unzipped and pushed to the nightly build site
  • The configuration files for the site are overwritten with the nightly build environment files (See script below) You may update the configuration files before or after pushing your site, depending on your preference)
  • Artifacts of the sites, binaries, and build scripts are stored with the build on TeamCity
  • Smoke test the sites (see script below)
    When a subsequent environment is run:
  • Clean all files before build (checkmark on the VCS configuration page for the build)
  • The artifacts from the dependent build are retrieved (configured from the dependencies page of the build configuration).
    image
  • The build tools are retrieved from source control using an edit checkout rule (+:lib)
    Whereas the compile-check and nightly build configurations get the entire folder structure from version control, the subsequent builds only retrieve the lib directory.
    image
  • The existing site is archived
  • The new site is unzipped and pushed
  • The configuration files for the site are overwritten with the specific environment files
  • Artifacts of the sites, binaries, and build scripts are stored with the build on TeamCity
  • Smoke test the sites
    The idea is to feed up the chain of deployments the artifacts needed to complete the next deployment.  It takes a little trial and error to get it right, but the benefits are worth it.  Our current builds at Unity Media Group take 2 to 3 minutes for the compile check (including test runs and zipping files), then approximately 45 seconds to deploy the site on the internal network.

What I have not automated yet (but would like to):

  • Reconfiguring the sites to point to a maintenance page while deploying
  • Running the SQL schema compare and integration or run update scripts
    -- I have run compare/integration scripts previously, but they tended to be more hassle than running them manually.  Still looking for better ways to do this, though.
  • If building binaries for use by other projects, update those projects with the new binaries
  • Run data scrubbing scripts (for creating known default environments for test or demonstration sites)

      Rake File Snippets

    To update the configuration files, I define the following method in my helper file:
 # UPDATING CONFIGURATION FILES 
def copyToDirectory(zip_file, website_dir, config_type)
throw("ZipFile does not exist!", zip_file) unless File.exist?(zip_file)
seven_zip = SevenZip.new :ziparchive => zip_file, :directory=>website_dir
seven_zip.unzip

# WEB_PROJECTS: list of web application projects with a Config directory
# => WEB_PROJECTS =
# ['ElegantCode.Example.Administration',
# 'ElegantCode.Example.Client',
# 'ElegantCode.Example.Services']
WEB_PROJECTS.each do |site|
puts "##teamcity[progressMessage 'Updating application settings for #{site}']"
list=FileList.new("#{website_dir}/#{site}/Config/*-#{config_type}.config")
list.each do |file|
target = file.gsub("-#{config_type}",'')
puts "##teamcity[progressMessage 'Copying #{file.to_s} to #{target.to_s}']"
cp file,target
end
end
end
















And this is how I use it in the rakefile:



# USAGE:
zip_file = File.expand_path(File.join("..","Sites", 'Debug.zip'))
website_dir = File.join('Z:', 'AdventureMVC')
copyToDirectory zip_file, website_dir, 'sandbox'


Similarly, to smoke test the site, I have the following class in my helper file:



# SMOKE TEST 
class PreJIT
attr_reader :sites

def self.compile(sites)
sites.each do |site|
puts "##teamcity[progressMessage 'Pre-jitting #{site}']"
open (site)
end
end
end


And this is how I use it:



# USAGE:
sites = ['http://test.example.com/admin', 'http://test.example.com']
PreJIT.compile(sites)


If the site  has a 40x/50x error, the build will fail.



There is much more to the rake scripts; however, you should peruse the rake files from Fluent NHibernate or FubuMVC for more ideas on writing your own Rake scripts.  You can incorporate rake-dotnet into your rake environment, as well.  Finally, you can accomplish the same tasks using MSBuild or NAnt, if you feel more confident in those environments.



Until next time..



Fluent NHibernate


FubuMVC


rake-dotnet


TeamCity


Rake

Sunday, May 24, 2009

Implementing TeamCity for .NET Projects, Part 4: Using Build Scripts

For more information on this series, please see the introductory post. This post also assumes that you have completed parts 1-3. The sample solution has been updated with new build scripts as of May 24, 2009. If you have downloaded the solution previously, please download the updated solution. You can explore the source or create a working copy. A zip file has been provided for you to download to import into your own writeable repository.

For more advanced or complex build scenarios, the build it solution runners prove somewhat inflexible. Once you have arrived at this conclusion, you will most likely start investigating some of the other build runner options.

For .NET projects, the two obvious choices are MSBuild and NAnt. The new hotness for building .NET projects is Rake. And, if you use a scripting language not built into TeamCity (such as FinalBuilder, Psake, or shell scripts), the command line runner is your friend. TeamCity also has two .NET build runners specifically targeting code inspection: Duplicates finder and FxCop.

I have been using NAnt for several years to build both web and desktop applications. NAnt has been fairly quiet for the last couple years. The latest official release (0.86 Beta 1) is dated December 2007, but there has been sporadic 0.86 Beta 2 activity in the nightly releases.

I have just started working with Rake for build scripts. (A big thanks to the Fluent NHibernate and FubuMVC contributors for their pioneering efforts on this front.) Rake, like Ruby itself, seems to be infinitely extensible.

What Should a Build Script Do?

My build scripts need to at least handle the following targets/tasks:

  1. Compile the application
  2. Run the tests
  3. Provide a code coverage report
  4. Zip up the compiled application for artifact retention
  5. Update the configuration files
  6. Publish the website to a folder or IIS virtual directory
    TeamCity natively handles 1 and 2, but we will be duplicating that functionality with the build scripts. TeamCity also allows you to download your artifacts as a zip file, but does not store it as one. TeamCity does not provide code coverage for .NET projects. However, it does for Java projects.)
    Our NAnt and Rake scripts will handle the all the tasks. I will cover the first four tasks in this post. I will cover the other three in another post.

Setting Up an NAnt Build Runner

We’ll start with an NAnt Build Runner. In your TeamCity website:

  • From the Projects page, click the drop arrow next to the existing project and click on Edit Settings
  • On the right hand side of the screen, click on the Copy button to copy the configuration
  • Name the new build configuration “Just Build It! (with NAnt)”
  • Select the Runner link from the navigation bar on the right

Based on the sample solution, enter the following values and save your changes. Leave all other values at their defaults. (If your solution is structured differently, adjust accordingly.)

Build Runner: NAnt
Path to a build file: nant.build
NAnt Home: lib/nant

Leaving the Targets text box blank will force the runner to use the default target.

The default targets in thee script files create a zipped file of the website and code coverage results from the free NCover Community edition. I am using a couple custom tasks from kiwidude for integrating NCover with the NAnt script.

In the General Settings page, add the following to the Artifacts text box to force both files to show up as artifacts:

results/Artifacts.zip
results/CoverageReport.html=>ncover

Creating custom tabs is fairly simple as well. Add the following entry to the <TeamCity data directory>/config/main-config.xml (the default data directory is named .BuildServer to create a tab that shows the NCover results for each build:

<report-tab title="NCover"
basePath="ncover"
startPage="CoverageReport.html" />

(Thanks to Laurent Kempé for the instructions on integrating NCover with TeamCity)

Setting Up a Rake Build Runner

Make another copy of a configuration and name the new build configuration “Just Build It! (with Rake)”. This time select Rake as the build runner on the Build Runner page. Leave all other values at their default. (The Rakefile in the root directory will be used. I modified the rake scripts from the FubuMVC project for this solution.)

You will need Ruby and a couple of Gems to get started. Check the information in the Ruby_Not_Installed.txt file in the root directory of the sample solution.

Setting Up an MSBuild Build Runner

I actually do not have an example of an MSBuild script (because I do not have enough experience with MSBuild). Setting up the build runner is similar to the NAnt and Rake runners. If you are interested in this build runner type, check out Ryan Anderson’s posts. He has done an excellent job detailing the process.



Upcoming posts:

  • Deployment: Using TeamCity and build scripts to update different deployment environments.

  • Setting up notifications: We will look at the different options for notifications, such as email and the tray notifier.


JetBrains TeamCity
Sample Project on GoogleCode
NAnt
NAntContrib
NCoverExplorer Downloads
NAnt
NAntContrib
NCoverExplorer Download Page (with NAnt/MSBuild documentation links)
Ruby Downloads

Sunday, April 19, 2009

Implementing TeamCity for .NET Projects, Part 3: Running Tests, Nightly Builds, and Creating Artifacts

For more information on this series, please see the introductory post.  This post also assumes that you have completed parts 1 and 2.

With our basic solution build, we want to start running our unit tests on every check-in, create a nightly build (that runs both unit and integration tests), and generate some artifacts.

Running Tests

First things first, lets get the tests running.  Open the current build configuration and select the build runner navigation link (it should say Runner: sln2008).  On the build runner page, select NUnit 2.4.8 from the NUnit runner combo box.  Add the path to the unit test assembly in the assembly text box.  For our solution, the path is: **/bin/debug/AdventureMVC.Tests.dll .  As you can see, this is using an MSBuild wildcard format to find the correct assembly.  It is unnecessary to point to the full path.

image

Save your changes.

Now, when your builds run, you should get a new status indicator showing how many tests passed. 

image

If you click on the status, you will also see a new tab on the build results page showing the test information.

image image

Nightly Builds (with integration tests)

Now that we have our imageunit tests running on every check-in, let’s create a nightly build.  Open the current build configuration.  Make a copy of the build by clicking on the Copy button on the right-hand side of the page. 

Rename the new configuration as you see fit.  I will use Nightly Build.

image

Select the build runner link.  Add the integration test assembly to the test assembly text box.

image

Save your changes.

Select the Build triggering link.  Deselect the check box.  On the imageSchedule tab, click on Add time trigger and configure your nightly build time. Save your changes.  (You can test the build at this point by clicking on the Run button.)

Creating Artifacts

We want to make the compiled website readily available, so we are going to create some artifacts.  Getting at the precompiled website through the file system is inconvenient.

If the example solution contained a website, compiling the solution would create a precompiled website.  Since the example solution contains a web application project (specifically an ASP.NET MVC application project), I had to add a post-build event to create the precompiled site.  Check the AdventureMVC project properties to see the syntax.

On the Nightly Build configuration page, select the General Settings link.  In the Artifacts text box, type: PrecompiledWeb\Web=>PrecompiledWeb.  Save your changes.

image 

Now when you run your build, you should see an Artifacts dropdown link in the status line of the build. 

image

When you click on the build status, the status page now has an artifacts tab.  

image

Not only do you have the ability to download the individual files, you can now use these artifacts in other build configurations…but that is for another post.


Upcoming posts:

  • Build scripts: We need some additional functionality that the basic solution runner doesn’t provide, such as zipping up artifacts.

  • Setting up notifications: We will look at the different options for notifications, such as email and the tray notifier.

  • Deployment: Using TeamCity and build scripts to update different deployment environments.


    JetBrains TeamCity
    Sample Project on GoogleCode

    Wednesday, April 15, 2009

    Implementing TeamCity for .NET Projects, Part 2: Triggering Builds

    For more information on this series, please see the introductory post.

    Why Continuous Integration?

    The benefit of continuous integration, according to Martin Fowler, is reduced risk.  Reduced risk is accomplished through a quick feedback cycle.  The longer you defer integration, the more difficult integration becomes.  If you integrate automated testing into your integration cycle, you can further reduce your risk.

    Continuous Integration with TeamCity (VCS Triggers)

    TeamCity has four build trigger options:

    1. VCS Triggers: Triggers a build when files are checked into source control.
    2. Schedule: Triggers a build on a predetermined schedule.
    3. Dependencies: Triggers a build when another build completes successfully.
    4. Other Triggers: Triggers a build if previous build fails.

    VCS triggers are analogous to continuous integration.  Check in files to source control and a build is started.  Enabling continuous integration in TeamCity takes only a few clicks to configure.

    imageLets get started. Click the arrow next to the build configuration we completed in the last post. Select Edit Settings.

     

    image

     

    On the right side of the build configuration screen, you will see a list of Build Configuration Steps.  Select the Build Triggering step. 

    Select the checkbox labeled Enable triggering when files are checked into VCS

    image

    At this point, you can save your changes and you will have enabled continuous integration.  The quiet period and trigger rules (explained below)  fine-tune the behavior of the build trigger.

    Once checked, an option to set a quiet period is enabled.  A quiet period is the length of time after a check-in which TeamCity will wait before starting the build.  If check-ins tend to come in waves, this can help keep the build queue short.  (If you tend to forget to check in all your files or need to check in files from your IDE and file system, you may want to give yourself a short quiet period before triggering a build to allow for multiple check-ins.)image

    However, if you configure too long of a quiet period with a project with a large team, the build may take too long to start, negating the benefits of continuous integration.  I prefer to select Do not use or Use default value (60 seconds) for my projects.

    Finally, you can exclude some check-ins from triggering the build by defining trigger patterns.  Exclusions can be based on file paths, users, or a combination.  For example, if your project team includes a technical writer who produces documentation, those check-ins probably do not affect build quality.  Or, when you update your build scripts, those changes may not need to trigger a build either (see example below).  For the purposes of the example solution, you may define the –:*.build pattern, even though we haven’t started using build scripts yet.

     image

    Defining a trigger pattern is fairly straightforward. The pattern is:
    +|-:[user][VCS root][path]
    Defining a +: rule removes the include all rule, allowing a very fine-grade include path. Defining a –: rule excludes the defined path from triggering a build.  For more information, see the documentation.

    Finish by saving your changes and returning to the main page.  Update and check in a project file and you can watch TeamCity start a new build process.

     Congratulations! You have just enabled continuous integration with TeamCity!


    Upcoming posts: Creating artifacts and nightly builds


    JetBrains TeamCity
    Sample Project on GoogleCode

    Sunday, April 5, 2009

    Implementing TeamCity for .NET projects, Part 1: Just Build It! (A Simple Build Configuration)

    For more information on this series, please see the introductory post.

    When working on an development team, one of the more challenging tasks can be building your integrated source code for deployment.    Building a production version of the application may be a long and difficult process, especially if production builds are infrequent.  Even a well-documented build procedure may take hours or days to complete and is probably prone to error.  One person may have all the requisite knowledge to perform the build, causing delays or rifts for other team members when builds are needed.

    Therefore, creating a repeatable build process that any team member can instantiate can provide great benefit for the team, reducing the risks in the build process.  That is our purpose for this exercise – to Just Build It! 

    For a production build system, your build server should be a mirror of your production environment.  This helps reveal possible issues and risks before deploying to your production environment.  For the purposes of this series, this is not necessary; however, you must have the following installed:

    • Microsoft Visual Studio 2008
    • A version control system(VCS), such as Subversion or Team Foundation Server. 
      • If you do not have a current VCS instance, consider VisualSVN Server
      • Ensure that the system on which you will install TeamCity has the ability to check out files from your VCS natively.  For Team Foundation Server, you must have Team Explorer installed.  For Subversion, you must have SVN or TortoiseSVN installed.
      • For a full list of supported systems, consult the TeamCity documentation
    • ASP.NET MVC
    • The sample AdventureMVC solution
      • Added to your installed VCS
      • Available from codeprogression.googlecode.com
        • A zip file is available to download for utilization in your VCS
        • You may also browse the source on the site
    • The AdventureWorks database installed on SQL Server 2005 or SQL Express 2005
      • Available from Microsoft downloads
      • Update the web.config file to your specific database connection information prior to running the solution or any builds
    • TeamCity 4.02 or later
      • If you are using VisualSVN Server 1.7, you must download TeamCity 4.1 EAP or later
      • For installation instructions, consult the TeamCity documentation.
      • Note your installation directory and build server directories.  These will be useful in the future.
      • I usually locate my buildServer directory in the TeamCity installation directory rather than in the user profile folders.
      • When choosing the port for the TeamCity website, be aware of other sites configured on the machine.  Unless the server is dedicated to TeamCity operations, I suggest using port 8111.

    Note: I am assuming that you will be installing all of these packages on one system for exploratory purposes.  If you are not, you will need to adjust the instructions accordingly, especially in later posts.  For example, you will need an instance of AdventureWorks on your development system and your build system.  In a future post, I plan to explore the challenges of integrating databases into a continuous integration solution, such as TeamCity.

    Your First Project

    With TeamCity, the time between finishing installation and running the first build can literally be minutes.  Lets get started.The minimum requirements for build configurations are:

    1. A project to house the configuration (TeamCity houses all build configurations within user-defined projects).
    2. A connection to a version control system
    3. A build runner

    Start up the TeamCity site.   Click on the imageCreate Project link, name your project, provide a description of the project (optional), and click the Create Project link.  

    Your First Build Configuration

    image Click on Create Build Configuration (you have 20 total in the professional version). 

    On the General Settings, provide a name for your build configuration and an optional description.  Leave the rest of the options on the General Settings page at their default.

    Click on VCS Settings.

    Name your VCS root and choose your VCS type.  Fill out your VCS-specific settings.  Ensure that the root of the source control directory is the trunk folder. 

    Here is my Subversion configuration for the example project:

    image

    And my working directory:

    image

    Here is a possible TFS configuration:

    image

    Test your connection and save.  Once again, leave the rest of the options at their defaults. 

    Click on Choose Build Runner.

    Select sln2008 from the Build Runner: option list.  In the Solution file path: text box, enter src\AdventureMVC.sln.  Change the text in the Confguration: text box to Debug.

    Click Save.

    Running Your Build

    Click on the Projects tab in the top navigation. In your newly defined build configuration, click on the Run button (do not click the ellipse) and watch your build run.image

    image 

    If everything compiles, you should see a success message for your build.  If not, check the error messages in the build log.  You may have errors in your VCS configuration.

    image 

     Congratulations! You have just completed and run your first build configuration!

    You can find your compiled website in the TeamCity installation directory under \buildAgent\work\guid\src\PrecompiledWeb\Web.


    Next: Continuous Integration (or Triggering Builds) and Creating Artifacts

    Even with a source code version control system (VCS), ensuring each developer has a working, buildable version of source code can be a slippery slope.  A developer may forget to check in a new file or dependent library.  With a VCS based on optimistic locks, a careless developer may break another developer’s code during a merge operation. So, how do we make sure that the latest code is compiling code? By using Continuous Integration.

    And, isn’t there an easier way to get at my compiled application? Yes, there is.  Its called Artifacts.

    Stay tuned.

    Tuesday, March 31, 2009

    Implementing TeamCity for .NET Projects: Evolving Your Build Automation Solution

    As the title suggests, I will be focusing on using TeamCity with .NET projects. However, make no mistake: TeamCity is well-positioned and well-tuned for use with many development environments, and many of the concepts I will discuss are applicable to those environments.

    Posts in this Series:

    1. Just Build It! (A Simple Build Configuration)
    2. Triggering Builds
    3. Nightly Builds and Creating Artifacts
    4. Using Build Scripts
    5. Deployments
    6. Setting Up Notifications (Coming Soon)

    During my talk at Boise Code Camp 2009, we discussed the evolution of build automation and continuous integration. If you are not familiar with build automation and continuous integration, Martin Fowler’s article is a nice primer on the subject.

    When I started on my current project, our team was not using a build server. We were encountering problems with incomplete check-ins, hostile merging, missing dependencies, and inconsistent and bloated production builds. The classic “it works on my machine” and “your code broke my code” syndromes were very prevalent. Prior to this gig, I had worked on a team that was using a continuous integration solution and I knew that we needed to implement something similar.

    While investigating options, I compared Team Foundation Build, CruiseControl.net, and TeamCity. TeamCity quickly became the forerunner strictly due to the ease of configuration and raving reviews from the community. Both Team Build and Cruise Control use XML configuration (yes, MSBuild is XML). Although I am very comfortable with scripting builds using nAnt, this was a barrier to implementation as a team. I wanted a low-friction entry point with the ability to implement more powerful functionality later.

    In the next several posts, I would like to expound on the evolution of our build process, starting with basic patterns, and then exploring more powerful patterns, all implemented using TeamCity. The patterns I will discuss are…

    • Simple Build Automation
    • Build and Test
    • Continuous Integration
    • Nightly Builds
    • Artifact Creation
    • Alternative Build Runners (Build scripting)
    • Build Dependencies
    • Deployments
    • Custom User Interface Elements

    You may want to download your own copy of TeamCity (the Professional version is free!). Installation is quick and painless . Make note of which directory you designate to be the .BuildServer directory – for convenience purposes, I suggest placing it in the root of the main TeamCity directory. I will make a sample project available for use in exercising the build server configurations shortly.

    Boise Code Camp
    Team Foundation Build
    CruiseControl.net
    TeamCity

    Sunday, March 29, 2009

    Boise Code Camp Session: Getting Started with Continuous Integration using Team City

    Giving a talk today at Boise Code Camp on JetBrains TeamCity build management server. 

    Topics:

    • Benefits of continuous integration
    • Why TeamCity?
    • Evolution of automated builds/continuous integration

    Will follow up with examples of evolving your build automation from just compiling code in a team environment to deploying websites.

    TeamCity Home Page
    Continuous Integration (Martin Fowler)