You'll want to create a few build scripts for your project. Most builds will simply grab the latest code, build it, and copy the results somewhere on the network. The milestone build is a little more complicated and involves branching and merging the source code repository.
The normal build script builds a clean version of the game and copies the results somewhere useful. It is run as a part of the milestone build process, but it can also run automatically at regular intervals. I suggest you run a normal build at least once per day, preferably in the wee hours of the morning to check the code on the network for any errors. The normal build script is also useful for building ad-hoc versions of the game for the test team.
The normal build script performs the following steps:
Clean the build machine. If you use the directory structure I suggest at the beginning of this chapter, you can run a command to delete everything.
Get the latest source code. Since the whole project will be cleaned in the previous step, everything in the repository will come down.
Grab the latest version number and label the build. Optionally, change the version number each night. When the version number changes, the destination directory of the build changes too. This is a really handy technique to keep old versions of a game around without copying them by hand. Visual Build Pro has a utility to grab or even change the version number of Visual Studio resource files, but it's pretty easy to write one yourself.
Compile and link the debug and release versions of the project. The project settings will make sure everything goes into the right place.
Run automatic test scripts. If you have automated testing, have the build machine run the test scripts to see if the build is a good one. This is more reliable than a bleary eyed programmer attempting to test the game at 4 a.m.
Process and copy the build results. This should be encapsulated in the updaterelease.bat file. The destination directory should use the code name of the project and the version number to distinguish it from other projects or other versions of the same project. For example, version 22.214.171.124 of the Rainman project would go into E:\Builds\Rainman\126.96.36.199. The nightly build of the same project would always go into E:\Builds \Rainman\Nightly.
If you're paying attention you'll realize that the build scripts themselves should be checked to make sure they haven't changed. If the build script is running, how can it clean itself off the build machine and get itself from the source code repository? It can't, at least not easily. If you standardize your projects with a single directory structure it's better to create a master build script that works for any project. Project specific build commands are put into a special build script that lives in the same directory as the project files. The master build script should only change when the build process for every project is changed—something that should be extremely rare.
Milestone builds are entirely different creatures since they involve branching the code. They also involve an approval process that takes days or weeks instead of minutes. A milestone build takes this extra work because it keeps the team from hitting a moving target.
|A Tale from the Pixel Mines|| |
At Origin Systems we didn't do anything special for milestone builds on the Ultima projects. Some unlucky programmer, usually me, launched the build on their desktop machine and after plenty of cussing and a few hours the new version was ready to test. The other programmers kept adding features and bugs as fast as the test team could sign off old features. New code and features would break existing code—stuff the test team approved. The bugs would pile up and it was difficult to figure out if the project was making any progress.
The Microsoft projects I worked on were entirely different, mostly due to ditching SourceSafe. Our source code repository, Perforce, had excellent branching and merging capabilities. The programming team resisted at first, but quickly saw that milestone builds were linked directly to their paychecks. A few milestones later everyone wondered how we ever developed projects without branching.
Every project should have a Main branch and a Publish branch. Every source code repository does this a little differently. When a milestone build is launched, the first thing that happens is the Publish branch gets a fresh copy of the Main branch. The branches are synchronized without merging. When a build begins the two branches should be identical. The build machine runs the build scripts from the Publish branch to make the milestone build. This implies that the Main and Publish branch can exist on the same machine at the same time. This is true. Generally different branches are stored in different directory trees.
Most source code repositories allow a great degree of freedom for each client to configure how they view the contents of the repository. It's pretty easy to configure the client to put all the Main branches of every project into a D:\Projects\Main directory and all the Publish branches into D:\Projects\Publish. The build scripts can use a branch macro to figure out which branch needs building.
Once the milestone build is assembled it should be packaged and sent to testing. In our case, this meant Zip'ing up the entire build and putting it on our FTP site so Microsoft test could grab it.
|Best Practice|| |
If you have to FTP builds to another group, it's a good idea to zip or tar the files into one monolithic file. The FTP protocol can spend a lot of time opening and closing files and if your game has hundreds of components you'll find that one big file FTP is much faster. One more thing: big companies like Microsoft have internal and secure FTP sites for developers that are usually accessed via FTP internally. FTPing the file twice takes much longer, usually. Set up your own FTP site, secure it, and have the test team pull the build from your FTP site. That's much faster.
I almost never submit milestone builds that were approved on the first shot. Most of the time I make a few minor fixes. Every now and then I have to do something major. Either way, the fixes get made to the Publish branch and the milestone build is resubmitted.
This process continues, sometimes for almost a week, until the test team is satisfied. The Publish branch is then merged to the Main branch. This is usually an automatic process, but sometimes merge conflicts force a programmer to stare at the code and fix them.
Here are the build scripts that were used on the Microsoft projects to open and close milestone builds. These scripts are designed to be used with Perforce, but most source code repositories have similar commands or features:
Open Publish Phase:
rem Get the Latest Main p4 sync %PROJECTSDIR%\Main\... rem Unlock the target branch and revert any unlocked files p4 unlock %PROJECTSDIR%\%BRANCHNAME%\... p4 revert %PROJECTSDIR%\%BRANCHNAME%\... rem Force Integrate from Main to target branch, resolve, and submit p4 integrate -b %BRANCHNAME% p4 resolve -at %PROJECTSDIR%\%BRANCHNAME%\... p4 submit %PROJECTSDIR%\%BRANCHNAME%\...
Close Publish Phase:
rem Get the Latest from the target branch p4 sync %PROJECTSDIR%\%BRANCHNAME%\... rem Integrate from target branch to Main - resolve changes and sumbit p4 integrate -r -b %BRANCHNAME% p4 resolve -am %PROJECTSDIR%\Main\... p4 submit %PROJECTSDIR%\Main\ ... rem Lock the target branch so noone changes anything p4 edit %PROJECTSDIR%\%BRANCHNAME%\ ... p4 lock %PROJECTSDIR%\%BRANCHNAME%\...
The integration commands are expected, but if you look at the last two lines of the close publish phase you'll see that the target branch, usually Publish, is checked out to the build machine and locked so that no one can change it. The open publish phase unlocks the files and reverts any changes. Why bother? This makes absolutely sure that the Publish branch, or any other branch that is keeping pace with the Main branch, is only open for changes during milestone approval. If no milestone build is in test, there should be no reason to change the Publish branch.
This has an added side effect: Anyone who wants the latest approved milestone build can simply grab the code in the Publish branch and build the game. This is especially useful if the odd executive or representative of the press wants to see a demo of some kind. Even if the last build is missing from the network, you can always recreate it by building the Publish branch.