Monday, March 30, 2009

Exposing SVN version and build time with Ant

As a developer, I find that an application's most useful version number is its SVN version; once I have that number, I can head over to the repository and figure out exactly what code is running. This is extremely useful both during development (Did I upload the correct .war to my staging server?) and for ongoing maintenance (What version is running on this server that needs to be updated?)

Fortunately, it's pretty easy to configure Ant to automatically inject the SVN version into your application every time you build it. Let's say that you have a particular file (/WEB-INF/jsp/admin.jsp) that should contain the SVN version number.

We take advantage of svntask, a nice simple library that lets Ant use SVN. Download/unzip the project files, place them somewhere convenient in your project, and add the following to your Ant build file: (modifying the fileset directory to where you put the svntask libraries)
<target name="version">
<typedef resource="com/googlecode/svntask/svntask.xml">
<classpath>
<fileset dir="${lib.dir}/buildtime">
<include name="svnkit.jar" />
<include name="svntask.jar"/>
</fileset>
</classpath>
</typedef>

<svn>
<info path="." revisionProperty="revisionVersion" />
</svn>

<property name="svn.version" value="${revisionVersion}" />
</target>

This stores the SVN version number of your project root in the "svn.version" Ant property. Now, it's just a matter of copying the correct file from the source web directory to the target web directory before you package your .war file: (The following will require some modification depending on how you normally package your wars.) We use Ant's copy/filter tasks to replace all occurances of the token "@version@" in admin.jsp with the SVN version number.
<target name="war.pre" depends="version">
<copy file="${src.web.dir}/WEB-INF/jsp/admin.jsp"
tofile="${target.war.expanded.dir}/WEB-INF/jsp/admin.jsp"
overwrite="true">
<filterset>
<filter token="version" value="${svn.version}" />
</filterset>
</copy>
</target>

Now, the following snippit in admin.jsp
<div id="footer">
<p>Build Number @version@</p>
</div>

becomes
<div id="footer">
<p>Build Number 1692</p>
</div>

This is good enough for production releases, where the package application will (or should) be compiled straight from the repository. However, during development, I often won't be checking in changes between builds. So, to tell those builds apart, I find it useful to include the build timestamp as well, which I can get using Ant's tstamp task. This isn't a perfect solution, but it's enough to give me some reassurance that I didn't accidentally deploy an old build to my local server.
<target name="war.pre" depends="version">
<tstamp>
<format property="war.tstamp" pattern="yyyy-MM-dd HH:mm:ss z" />
</tstamp>
<copy file="${src.web.dir}/WEB-INF/jsp/admin.jsp"
tofile="${target.war.expanded.dir}/WEB-INF/jsp/admin.jsp"
overwrite="true">
<filterset>
<filter token="version" value="${svn.version}" />
<filter token="time" value="${war.tstamp}" />
</filterset>
</copy>
</target>

Now, inside of admin.jsp, I can include the following snippit
<div id="footer">
<p>Build Number @version@ (@time@)</p>
</div>

and Ant will transform this into
<div id="footer">
<p>Build Number 1692 (2009-03-30 11:20:15 PDT)</p>
</div>

which is exactly what I want.

Wednesday, March 25, 2009

Dude. Sweet.

Larry tipped me off to the new AWS Toolkit for Eclipse. This looks like it could be pretty awesome for integrating/viewing our EC2 instances.

Friday, March 20, 2009

super lightweight cms

We wanted to roll something out that would allow us to update some areas of our site more easily, and make the content a little more dynamic. Specifically, the News and Announcements page and the Behind the Scenes page.

We've all had experiences with big crazy cms solutions, that do a million things, none of them all that well, and never exactly what you want.

Also, we're a really small team, so we didn't want to set something up that would require a lot of maintenance, or even require a new service or machine.

For "Behind the Scenes", we're already using twitter for company updates. I think this is a great solution for posting short news items, or links, for any site.

The next step was to integrate with Flickr for our Around the office photos. We set up a public, invite only Bizo group. Anyone at Bizo can post photos to this group, and they'll show up on our site. Flickr handles the authentication/authorization, content storage and hosting, and a decent API for getting content on the site.

For "News and Announcements", we wanted a way to be able to easily update any news or press releases, quickly, and without requiring a site release.

We ended up creating a simple blogspot blog to host the content. Blogs/RSS seemed like a pretty close fit. You already have the concept of multiple published items, with dates, titles, and content. Using the excellent rome java library, we pull the content in on the backend, do a little content parsing, then render the results.

The "content parsing" is a little hacky. We wanted slightly more structure around our entries than you get from an RSS feed. So, we expect all of the posts to be formatted like "image (optional), text, read more link". Blogger lets you set up Post Templates, so, it's actually not that bad. When you go "super lightweight", you have to expect to make some tradeoffs, and this seemed like one worth making.

The other nice thing about externalizing your content like this is that you can start pulling it into other places. Last night we launched a new version of our homepage with a flash ticker, that pulls in these news items from the same place.

So there you go: a free, lightweight, zero infrastructure CMS recipe.