Before the build server got going, we had several chronic problems that sapped time and morale from our team:
- People would forget to include a new file with a commit or break the build in various other ways. This wouldn’t be discovered until someone else updated from source control and couldn’t build any more. That’s never fun.
- Because there wasn’t any official build, the process of deploying builds to the live web sites was pretty much having someone build on his/her local machine then manually copy the resulting binaries to the web server. Every once in a while a bad build would go out with personal configuration options or uncommitted code changes that shouldn’t have been made public. That’s never fun either.
- As a result of the previous point, we could never tell exactly what build was running on the web servers at any given moment. The best we could do was inspect timestamps on the files but that didn’t tell us exactly what commits were included in a build.
Needless to say that wasn’t a great experience for our development team. The solution was to set up a continuous integration build server that would automatically sync, build, and report automatically after each commit.
Solving the problem
I downloaded and installed TeamCity from JetBrains. TeamCity is one of those rare tools that manages to combine both ridiculously awesome ease of use and ridiculously powerful configurability into one package. I highly recommend it if you’re looking for a CI build server. JetBrains offers very generous licensing terms for TeamCity which makes it free to use for most small teams. By the time your team is large enough to need more than what the free license provides, you won’t mind paying for it.
I set up a build configuration for our main branch in SVN, set it to build and run unit tests after every commit, and configured TeamCity to send email to all users on build failures. This way when someone breaks the build we know about it instantly and we know exactly what caused it. Sure, we still have occasional build breaks but they’re not a big deal any more.
I extended our Rake build script to copy all binaries to a designated output folder in the source tree then configured TeamCity to grab that output folder and store it as the build artifacts. Now when we want to deploy a build to our web servers, we can go to the TeamCity interface, download the build artifacts for a particular build, and deploy them without fear of random junk polluting them. No more deploying personal dev builds!
I also set up a build numbering scheme for the TeamCity builds so that every build is stamped with a <major>.<minor>.<TeamCity build counter>.<SVN revision number> scheme. This lets us unambiguously trace back any build binary to exactly where it came from and what it contains.
Finally, once the TeamCity build was working smoothly I created a template from the main branch build and use that template to quickly define new build configurations for our release branches as we create them. When we create a new release branch I copy the version number information from the main branch build definition to the new release branch build definition, then bump the minor version number and reset the TeamCity build counter on the main branch. This way all builds from all branches are unambiguous and we know when and where they came from.
A dedicated build server has been considered a best practice for decades now, and a CI build server doing builds on every single commit has been a best practice for a long time as well, but small startup teams can sometimes get so caught up in building the product that they forget to attend to the necessary engineering infrastructure. Setting up a build server isn’t a very sexy job but it pays huge dividends in reduced friction over time. These days it’s amazingly easy to do it, too. If your team doesn’t have a CI build server, you should get one right away. Once you do you’ll wonder how you ever got along without it.