Injecting SVN revision number via Maven

I am as Prometheus to you mere mavening mortals (except for how he was chained to a rock for all eternity while birds repeatedly ate his internal organs)! I have stolen fire from mighty Zeus and I now share it with you. Wear your flame retardant pants, ye knave–for we enter the wild world of groovy.

(I should note, I stole this technique from a coworker, but he’s too lazy to blog about how awesome it is.)

One of the most irritating things in the world for a browser based game developer is the browser cache. Sure, you know how to reload a page, but no one on the QA team does. Sometimes, even you can’t seem to get Chrome to just stop caching crap (stupid jerk). How does the QA team know when they’re playing the latest build? Turns out that with Maven, you can actually compile the SVN revision number into your build, then you can display that number for all to see. This technique works for Flash games, JavaScript games– whatever you’re using.

First, you need to use a plugin to generate a build number. In your pom, add:

<profile>
	<id>has-cmdline-svn</id>
	<activation>
		<file>
			<exists>.svn</exists>
		</file>
	</activation>
	<build>
		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>buildnumber-maven-plugin</artifactId>
				<version>1.0</version>
				<executions>
					<execution>
						<phase>validate</phase>
						<goals>
							<goal>create</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</profile>

This is most easily done in a profile so that you can detect whether or not a .svn folder exists to grab the information from. Now you need to add two more plugins.

<plugin>
	<groupId>org.codehaus.gmaven</groupId>
	<artifactId>gmaven-plugin</artifactId>
	<version>${groovy.version}</version>
	<executions>
		<execution>
			<id>create-version</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>execute</goal>
			</goals>
			<configuration>
				<source>${basedir}/src/main/groovy/com/mycompany/version/Version.groovy</source>
			</configuration>
		</execution>
	</executions>
</plugin>
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>build-helper-maven-plugin</artifactId>
	<executions>
		<execution>
			<id>add-source</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>add-source</goal>
			</goals>
			<configuration>
				<sources>
					<source>${project.basedir}/target/generated-sources/version</source>
				</sources>
			</configuration>
		</execution>
	</executions>
</plugin>

These two plugins have two responsibilities. The first uses a .groovy file (which we’ll write in a sec) to generate a source file. The second plugin is a programmatic way to unclude more source directories in your POM. Now we need to write our .groovy file that will generate our source. Here’s an example that generates an .as file for Flash apps:

def ant = new AntBuilder();
def build = project.build.directory;
def root = new File( build, "generated-sources/version/");
def output = new File( root, "com/mycompany/version/");

ant.mkdir(dir: output);

ant.echo(file: "${output}/Version.as", message:
"""package com.mycompany.version{

	/**
	 * <strong>DO NOT EDIT</strong>
	 *
	 * <p>This class is auto-generated by the build.</p>
	 */
	public class Version {

		/**
		 * Build Revision Number
		 */
		public static const SCM_REVISION:String = '${project.properties.buildNumber}';

		/**
		 * Build Date
		 */
		public static const BUILT_AT:Date = new Date(${project.properties.timestamp});

	}
}
""");

The final step is to add the generated source directory to whatever build plugin you are using (like flex-mojos). What’s brilliant about this technique, is that now you can build with Maven, and display the revision number so that everyone who loads the game will know exactly what version they are using. This doesn’t solve browser caching problems, but it lets you know in a single number if the browser is caching something it shouldn’t be.