Why should my build and deployment scripts be separate?

You may ask this question when you notice that every time you build, you also deploy. What’s the point in keeping the scripts separate if they will always be run together? Before listing all of the reasons I can think of, let me tell you about a bug we recently had in our (currently combined) build and deployment script.

The installer for our licensed FogBugz product is created by a single script that builds both the FogBugz binaries, as well as the installer program that includes all of the binaries in a zipped up cab file. The script first copies all of the files that will be needed in the cab to a specific directory, then builds them, then adds everything in the directory to the cab file, and proceeds to build the installer. A developer recently noticed that certain files were not being included in the cab file that should have been. Closer investigation revealed that the step to create those files failed because the tool necessary to build them wasn’t one of the files copied into the directory to be zipped into the cab.

Now obviously, a lot had to go wrong for this to happen. The build didn’t correctly report the failure to build those files. The build tool required was part of the code repository instead of being placed in a common build tools repository. The build tool required was called via a path relative to the code, rather than relative to the build script. But the issue I’m looking at today is that we mixed up steps that were meant for the deployment with steps meant for the build.

In this case, the deployment script was the script that took built FogBugz files and created an installer with them (deploying to a setup program, as opposed to deploying to the web). Because the steps were mixed together instead of strictly separated, the necessary build tool was not at the expected location, and the build failed (silently, unfortunately).

There are obviously less architectural changes we could make that would have helped us identify and fix this issue more quickly - things like reporting all build errors, or calling the build tool with a path relative to the build script, not the code. But separating the build and deployment scripts would have prevented the bug from occurring in the first place.

Keeping the scripts separate has the following advantages:

  1. Bugs caused by mixing deployment steps into the build script go away.
  2. A single build can be used for multiple deployments (to an installer, to a web site, on a dev machine)
  3. Developers can use the build script on their dev machine, instead of doing the build manually or having a separate script that must be kept in sync.
  4. The development team can take ownership of the build scripts, without having to worry about the details of deploying, which can be left to system administrators and release managers.