How I run a personal CI build every time I build my code in Visual Studio.
In this series I show you how to take continuous integration to the extreme by building a personal CI server that runs all your tests and adds a commit to source control every time you build in Visual Studio.
This week, we look at the overview of the problem and the proposed solution.
- Extreme CI Part 1 – Overview (you are here)
- Extreme CI Part 2 – Setting Up Git
- Extreme CI Part 3 – The Visual Studio Macro
As more and more tests are written for a project, they take longer and longer to run. Even after optimizing tests I find that I spend far too much time waiting for them to run. So what do I do? I stop running all the tests, and only run part of them. But then how do I know when I have broken a test if I am not running it? And there lies the rub. It’s a catch-22. I try to save time by running fewer tests, only to lose time fixing errors those tests were written to protect me from. What to do?
I thought, “If only I could keep working while the tests were running…But that would mean they would need to run on another machine…How would I kick that off…” Then it hit me, “I do this all the time, I just need a CI server.” Then the ideas just started flowing…
Continuous Integration is an Agile/XP practice where developers check their code into a source code repository very often (at least once a day) and an automated process builds the code and runs all the tests against it to ensure quality.
To run this automated process, we a Continuous Integration Server application. This software can be configured to check the source control repository for changes, and kick off your build scripts (that you write) to compile your code, and run your tests. You can run unit, integration, and ever UI-tests. Its common to build installers and gather code metrics, etc., all automatically.
If I could get a CI Server just for me, a “Personal CI”, and have it kick off every time I run my tests (even if I don’t run them all), then I could get out of that catch-22 and save time running tests because they will run automatically on another server while I continue working.
As an added bonus, I could have the CI Server tag the versions of the code that passed all the tests so I could roll back to the most recent good state if I ever needed to.
How It Works
So I schemed an planned, and tried, failed, and tried again, and here is what I came up with.
- I build my code in Visual Studio.
- A custom Visual Studio macro commits all my changes to a local Git repository.
- The macro then pushes the changes to the Git repository that the CI Server is watching.
- The CI Server sees the changes, pulls them down, builds the code, and runs all the tests.
- When all the tests pass, the CI server can tag that version of the code so we can roll back to it if necessary.
- On failure, the CI notifies me.
Lets walk through the major parts of this process.
The Visual Studio Macro
I chose to trigger the process when building rather than running the tests. I did this for two reasons: (1) I wanted to run the tests as often as possible, (I build my code more often than I run the tests.) and (2) it was much easier than triggering off the test runner.
When code is built in Visual Studio, it fires of several events that can be captured by custom macros. When the macro fires off, it will execute a batch file that calls git on the command line to commit our code to the git repository and push it to the CI’s repository. The batch file is executed as an “External Tool” since we cant just shell out to the command prompt from the macro.
The Git Repositories
This process involves two repositories. The first is on the developer’s machine. It’s the developer’s local working repository. The second is the CI Server’s repository. This is set up as a remote on the developer’s repository so the changes can be pushed to the CI server.
I chose to use Git because it can work side by side with other source control packages.. If you are using SubVersion, you can just tell subversion to ignore the .Git folder and use them both.. If you are using Git, you can push to the CI Server’s repository without pushing to other developer repositories or your main repository. Its just another remote.
The CI Server
The CI server will detect that the new code has been committed to the repository, check it out, and run your build script against it to build the code and run the tests. What CI you choose to use is up to you. Hopefully, if you are setting up a personal CI Server, you already have a team CI Server that you are using. If not, you need to set up one of those first. So you would likely use the same CI Server software. I have done this with Hudson and TeamCity, though CCNet would work as well.
I set my CI Server up on my personal laptop and had it running next to my dev box. That way I could watch it run the tests and know immediately if it fails (using email or a CI monitor for notification works just as well). Alternatively, you could also set up another box or VM somewhere on the network. I wouldn’t recommend running it on your dev machine (either in a VM, or directly on the machine) because that would really slow your machine down and defeat the purpose. Whatever machine you use, it doesn’t have to be a really fast one. After all, its running on its own so you don’t have to wait for it, so speed isn’t that big of a deal.
The Build Script
This is the script that builds your code and runs your tests. Use MSBuild, NAnt, PowerShell, Rake, or whatever floats our boat. If you have a team CI Server running, you can usually just use its script.
You can set this script up to tag the code when the tests pass if you like. Then you can roll back to the last known state where the tests passed.
Next week we’ll look at how to set up the Git repositories and automate pushing files from the developer’s working repository up to the CI Server.
- Extreme CI Part 3: The Visual Studio Macro.
- Extreme CI Part 2: Setting up Git for a Personal CI
- Video: Padawan to Jedi – A Developer Jump-Start (my presentation at Austin Code Camp 2011)
- Importance of Treating Unit Tests as First Class Code
- Screencast of my Integration Testing and Fluent Builder presentation at Austin Code Camp 2009