There are some things in a project that you should do as early as possible as they will save you a lot of time in the long run. The most important time saver might be setting up an automatic build server.
Even in small and smallest teams you’ll have the need of creating a build of your game every now and then. Here are some occurrences:
- Your non-programming colleagues can test the current version of your game
- You need a version to give to the press
- Your publisher wants a milestone version
- You just want to make sure the game still works on the devices
- You need a final release build
- The final release build wasn’t that final and you need a version with several bug fixes
The more you get into a project, the higher the request for current and special builds of your game. In the final phase of your game you definitively want a version at least every day, so your QA can find the last bugs and can make sure no new bugs are introduced.
But you definitively don’t want to sit down every day building this version, do you? Eventually programmers are lazy and this is where our good friend Jenkins steps in.
At your command, Sir!
The Jenkins project was originally developed as a project called Hudson. It provides a so called continuous integration service which takes over the work of automatically building your software once it is properly configured. Here are some use cases when a new version of your game might be build:
- Each day at a specific time (Daily Build)
- Each time something changed, i.e. somebody committed changes to the project repositories (Continuous Build)
- Manually triggered for a specific branch (Release Build, Press Build,…)
Configuring the build server
After you installed your build server, it’s time to configure it correctly. There are several plugins which makes it easy to let Jenkins get the source code of your project from a repository (Git, SVN, Mercurial,…). After this step you have to decide what Jenkins should do with the sources to give you a proper build.
Jenkins is structured by jobs. Each job consists of an arbitrary number of build steps. These build steps are among others:
- Executing a shell/command line/Nant/Ant/… script
- Triggering a Unity3D build
- Sending files to a FTP server
- …
When setting up the build server for our current project, I found great use of the Parameterized Trigger Plugin. As the name suggests, it allows to trigger other jobs with a bunch of parameters as a build step for another job.
As you saw there are a lot of different configured versions that you have to build during the development of your game. The configuration of what to build usually contains:
- Branch of repository to use
- Platform
- Release or debug configuration
Additionally there may be project-specific settings that change between different builds. You don’t want to set up a completely new job for every configuration you need, as you would have to change multiple jobs if something changes in your build pipeline.
Instead you should add a parameterized job that contains all the configuration values that are available. After that we will use that job for all the specific jobs. The job structure will look like this:

Sharing the workspace
By default, each job uses its own workspace (i.e. an own folder) to work in. This is the place the sources are checked out and the scripts are executed in.
As the parameterized job is used for several other jobs, we don’t want it to work in a separate folder. Instead we tell the parameterized job which workspace to use by sending the workspace of the calling job as a parameter and setting the workspace with the “Custom Workspace” option in the parameterized job.
This way the main job works in the workspace of the specific jobs rather than in its own. It gives you the opportunity to do the workspace handling in the specific jobs, e.g. to clean it up before each build (for daily, release builds) or to copy the results of a successful build somewhere they can be accessed (FTP server, website,…).
Creating specific jobs
Now that you’ve got your main build pipeline with the parameterized job, it’s time to set up the specific jobs we use to build the different versions of our game with.
Here are the jobs I set up for our current project and the things which are specific to them:
Daily build
- Runs automatically each night between 0 – 7 a.m.
- Configuration
- Project branch: develop
- Framework branch: develop
- Platform: Android
- Build Target: debug
- Configuration: Debug Android
- Cleans the workspace before running
- Copies the built Android APK to the FTP server
Master build
- Has to be triggered manually
- Configuration
- Project branch: master
- Framework branch: master
- Platform: Android
- Build Target: release
- Configuration: Release Android
- Cleans the workspace before running
- Copies the built Android APK to the FTP server
Manual build
- Has to be triggered manually
- Configuration
- Project branch: develop
- Framework branch: develop
- Platform: Android
- Build Target: debug
- Configuration: Debug Android
- Does not clean the workspace before running
- Copies the built Android APK to the FTP server
Continuous job
- Used to make sure that the project still compiles correctly.
- Triggers after each repository change (framework and project)
- Configuration
- Project branch: develop
- Framework branch: develop
- Platform: Android
- Build Target: debug
- Configuration: Debug Android
- Does not clean the workspace before running
- Sends out mails to the contributors of the last commit(s) if the job is unstable or fails
The additional build steps for each job depend on your needs. The important thing here is that the main build pipeline is shared between all jobs, so changing it is easy and adding a job for a new version is quickly done, too.
Conclusion
Setting up a build server takes some time and may seem to be a big overhead for the few versions you build at the start of your project. But it’s worth taking the time and the earlier you do it, the earlier the time will be made up. With a properly set up build server you only need a single click to create a new version of your game. Or no click at all if you use a time trigger.
Furthermore a build server is a great tool to guarantee that your project compiles which is especially useful on a team. The continuous job even sends out mails to remind the people who committed bad stuff to fix it. And of course you can run the unit tests of your project before each build to make sure the project not only compiles, but also still succeeds the tests.
Once set up there are many, many ways to further automatize things using your build server. If you can think of something that may be automatized in your project, chances are good that there is already a Jenkins plugin out there for the job. Here are some more plugins that I found useful:
- MSBuild: Use MSBuild to build .NET projects
- NUnit: Run NUnit tests as a build step
- Publish over FTP: Send files (e.g. the built game) to an FTP server
- Version Number: Automatically generate a version number and use it during the job
- Unity3D: A bit nicer way to start a Unity3D build than using the command line directly
If you made your own experiences with Jenkins, please share your knowledge and leave a comment!
Pingback: Unit Testing - Coding with Style in Unity3D()