Pragmatic Automation http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi Pragmatic Automation. Hosted by Mike Clark. en-us Rake: Not Your Father's Build Language http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/RakeBuildLanguage.rdoc Martin Fowler has written an excellent <a href="http://martinfowler.com/articles/rake.html">article</a> describing the strengths of using <a href="http://rake.rubyforge.org/">Rake</a> as a build language, and how it compares to our old friends make and Ant. <p> Having used Rake extensively in recent months on a <a href="http://www.clarkware.com/cgi/blosxom/2005/08/18#VitalSourceStore">Rails project</a>, I can&#8217;t underscore enough how handy it is to have a full-blown language at your fingertips when crafting a build system. I got a taste of this power when I experimented with using Groovy to script Ant. I didn&#8217;t get a chance to push those boundaries before moving on to Rake, but it&#8217;s the same concept: build systems have much to gain from the use of an internal domain-specific language. </p> <p> A must read! </p> Is Your Build Agile? http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/AgileBuilds.rdoc SD Times just posted a <a href="http://www.sdtimes.com/article/special-20050815-01.html">new article</a> concerning lengthy builds siphoning energy off agile processes. <p> I think we&#8217;ll continue to see the tools and processes of old getting in the way of the rapid feedback required to move quickly and confidently. It&#8217;s an opportunity to revisit the value of those tools and processes, and adjust accordingly. </p> Firefox Plugin for CruiseControl http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/CCFirefoxPlugin.rdoc Inspired by the recent <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/CCWidget.rdoc">Dashboard widget</a>, Dmitri Maximovich wrote a <a href="http://www.md.pp.ru/mozilla/cc/">Firefox plugin</a> to monitor builds in CruiseControl. He&#8217;s looking for your feedback to help make it even better&#8230; CruiseControl Widget http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/CCWidget.rdoc The <a href="http://www.apple.com/macosx/features/dashboard/">Dashboard</a> in Tiger is an ideal way to monitor automation at work with just a glance. I&#8217;ve been anxiously awaiting word of attractive widgets that monitor builds and running programs. <p> Jason Sypher and Mark Husson came through with style today by unveiling the <a href="http://rubicore.com/code/cruisecontrol/">CruiseControl Widget</a>. Check out the <a href="http://rubicore.com/code/cruisecontrol/">screenshots</a>. Yum! </p> Project Dependencies Using Ant http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/AntDependencies.rdoc <a href="http://www.exubero.com/">Joe Schmetzer</a> has posted a short and sweet <a href="http://www.exubero.com/ant/dependencies.html">article</a> on how he uses Ant target dependencies and the &lt;import&gt; task to manage the build order of sub-projects. Examples scripts are there for the taking. Ant 1.6.3 Available http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant163.rdoc <a href="http://ant.apache.org/">Ant 1.6.3</a> is now available for your automation pleasure. This release includes a <a href="http://www.apache.org/dist/ant/RELEASE-NOTES-1.6.3.html">beefy list</a> of fixed bugs and enhancements, some of which are related to the new <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Subant.rdoc">subant</a>, <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Macrodef.rdoc">macrodef</a>, and <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Import.rdoc">import</a> tasks we recently toured. Ant 1.6 Goody: <subant> http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Subant.rdoc So far we&#8217;ve looked at <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Import.rdoc">&lt;import&gt;</a> and <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Macrodef.rdoc">&lt;macrodef&gt;</a>. As a result, hopefully your Ant build files have lost a few pounds of angle brackets so that they&#8217;re easier to maintain. It&#8217;s a good start, but if your project consists of several sub-projects, then there&#8217;s one more new feature in Ant 1.6 that you won&#8217;t want to miss. <p> The <tt>&lt;subant&gt;</tt> task lets you uniformly call an Ant target on multiple sub-projects, without having to maintain a list of those sub-projects. This is especially helpful when you want a master build file to build all your sub-projects. </p> <p> Say, for example, your project is structured as follows: </p> <pre> rodents | +- chipmunk | |- build.xml | +- groundhog |- build.xml </pre> <p> Each of the sub-projects, <tt>chipmunk</tt> and <tt>groundhog</tt>, can be built independently of the other. For example, to create a JAR file for the <tt>chipmunk</tt> project, you type </p> <pre> $ cd chipmunk $ ant dist </pre> <p> The resulting JAR file is created in the <tt>chipmunk/dist</tt> directory. </p> <pre> chipmunk | |- build.xml | +- dist |- chipmunk.jar </pre> <p> That&#8217;s all well and good when you&#8217;re working on <tt>chipmunk</tt>, but you&#8217;d also like to be able to build all the rodent sub-projects at once from a master build file. (All your rodents are belong to us.) And when those sub-projects are built, you want their resulting JAR files to be created in the top-level <tt>rodents/dist</tt> directory. That is, you want to call the <tt>jar</tt> target on each sub-project and override the <tt>dist</tt> directory so that you end up with </p> <pre> rodents | +- dist |- chipmunk.jar |- groundhog.jar </pre> <p> To do that, create a <tt>master.xml</tt> file in the top-level <tt>rodents</tt> directory and define a <tt>jar</tt> target that uses a <tt>&lt;subant&gt;</tt> task. </p> <pre> &lt;project name=&quot;master&quot;&gt; &lt;property name=&quot;dist.dir&quot; location=&quot;dist&quot; /&gt; &lt;target name=&quot;jar&quot;&gt; &lt;mkdir dir=&quot;${dist.dir}&quot; /&gt; &lt;subant target=&quot;jar&quot;&gt; &lt;property name=&quot;dist.dir&quot; location=&quot;${dist.dir}&quot;/&gt; &lt;fileset dir=&quot;.&quot; includes=&quot;*/build.xml&quot;/&gt; &lt;/subant&gt; &lt;/target&gt; &lt;/project&gt; </pre> <p> The <tt>jar</tt> target uses a <tt>&lt;mkdir&gt;</tt> task to create a root-level directory named <tt>dist</tt>&#8212;the directory we want to contain the resulting JAR files. Then the target uses a <tt>&lt;subant&gt;</tt> task to run the <tt>jar</tt> target of each <tt>build.xml</tt> file found in sub-directories of the root-level directory. (Note that a <tt>&lt;fileset&gt;</tt> is unordered, but <tt>&lt;subant&gt;</tt> supports other path structures.) </p> <p> When Ant is run in the sub-directories, the value of the <tt>dist.dir</tt> property will be set to <tt>rodents/dist</tt>. In other words, we override the <tt>dist.dir</tt> property so that sub-projects will create their JAR files in the root-level <tt>dist</tt> directory instead of in the project-level <tt>dist</tt> directories. </p> <p> You now have a transparent master build step: </p> <pre> $ ant -f master.xml jar Buildfile: master.xml jar: [mkdir] Created dir: /Users/mike/work/rodents/dist jar: [jar] Building jar: /Users/mike/work/rodents/dist/chipmunk.jar jar: [jar] Building jar: /Users/mike/work/rodents/dist/groundhog.jar BUILD SUCCESSFUL </pre> <p> Now imagine that tomorrow you add a new rodent sub-project. What do you have to change in order for the new project to fit into the master build system? Well, as long as the new project has a <tt>jar</tt> target that puts its output in a location defined by a <tt>dist.dir</tt> property, you don&#8217;t have to change anything. The more rodents, the merrier. </p> <p> The ability to transparently iterate over sub-projects, calling a target in each of their build files, is powerful. And if all of your sub-projects define a common set of Ant targets, then you can imagine a master build file that defines the same common targets. Each target in the master build file would simply delegate to the respective target in the sub-projects by using the <tt>&lt;subant&gt;</tt> task. And if you&#8217;re not careful, you might end up with a lot of duplication. </p> <p> Thankfully, you can avoid that mess by combining the new <tt>&lt;macrodef&gt;</tt> and <tt>&lt;subant&gt;</tt> tasks. After all, the only thing that changes from one master build file target to the next is the name of the target to be called on the sub-projects. Putting all the common Ant tasks in a macro makes your master build file more maintainable: </p> <pre> &lt;project name=&quot;master&quot;&gt; &lt;property name=&quot;dist.dir&quot; location=&quot;dist&quot; /&gt; &lt;target name=&quot;jar&quot;&gt; &lt;iterate target=&quot;jar&quot;/&gt; &lt;/target&gt; &lt;target name=&quot;clean&quot;&gt; &lt;iterate target=&quot;clean&quot;/&gt; &lt;/target&gt; &lt;macrodef name=&quot;iterate&quot;&gt; &lt;attribute name=&quot;target&quot; default=&quot;&quot;/&gt; &lt;sequential&gt; &lt;mkdir dir=&quot;${dist.dir}&quot; /&gt; &lt;subant target=&quot;@{target}&quot;&gt; &lt;property name=&quot;dist.dir&quot; location=&quot;${dist.dir}&quot;/&gt; &lt;fileset dir=&quot;.&quot; includes=&quot;*/build.xml&quot;/&gt; &lt;/subant&gt; &lt;/sequential&gt; &lt;/macrodef&gt; &lt;/project&gt; </pre> <p> When you call the <tt>iterate</tt> macro, specifying a <tt>target</tt> attribute, it executes that target on each sub-project. The <tt>&lt;subant&gt;</tt> task calls all the sub-projects uniformly; the <tt>&lt;macrodef&gt;</tt> task keeps the machinery in one place. </p> <p> I hope this mini-series has given you insight into some of the powerful new features in Ant 1.6. I&#8217;m finding that I can do more with less when I use these features. Unfortunately, I&#8217;m also finding that many projects haven&#8217;t taken advantage of these new features. </p> <p> Like production code, build files that contain duplication are costly to maintain. The Ant 1.6 features we&#8217;ve explored are aimed at helping you reduce duplication in your build process so that you spend less time writing and maintaining build files. The question is: When&#8217;s the last time you refactored your build files? </p> Ant 1.6 Goody: <macrodef> http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Macrodef.rdoc Rolling on with our tour of new features in Ant 1.6, let&#8217;s look at another new task that helps reduce duplication and promotes consistency across projects. The <tt>&lt;macrodef&gt;</tt> task lets you create a custom task composed of existing tasks, and specify custom parameters to those tasks on a case-by-case basis. Think of it as Ant&#8217;s way of letting you write reusable methods in your build files. <p> Say, for example, your build file includes the following <tt>test</tt> target that taste-tests the build: </p> <pre> &lt;target name=&quot;test&quot; depends=&quot;compile-tests&quot;&gt; &lt;junit haltonfailure=&quot;true&quot; fork=&quot;false&quot;&gt; &lt;classpath refid=&quot;project.classpath&quot; /&gt; &lt;formatter type=&quot;brief&quot; usefile=&quot;false&quot; /&gt; &lt;batchtest&gt; &lt;fileset dir=&quot;${build.test.dir}&quot; includes=&quot;**/*Test.class&quot; /&gt; &lt;/batchtest&gt; &lt;/junit&gt; &lt;/target&gt; </pre> <p> The <tt>&lt;batchtest&gt;</tt> task creates a test suite containing the tests returned by the <tt>&lt;fileset&gt;</tt> element&#8212;all the tests defined in <tt>*Test.class</tt> files. The resulting suite is then run by the enclosing <tt>&lt;junit&gt;</tt> task. Once you get all the elements and attributes set the way you like, it works like a charm. </p> <p> Tomorrow you&#8217;re writing a new JUnit test, but it&#8217;s not the sort of quick unit test that a programmer on a deadline would want to run frequently as part of the build process. No, your new test belongs in a different test suite than the quick tests. So you decide that you need a new Ant target called <tt>test-database</tt> that runs all of the database-related tests. That target will call all the same tasks as the <tt>test</tt> target, but with three differences: 1) the <tt>&lt;fileset&gt;</tt> will collect only the database tests 2) the value of the <tt>fork</tt> attribute will be set to <tt>true</tt> and 3) the database tests require system properties to be set. </p> <p> It&#8217;s tempting to copy the <tt>test</tt> target and give it a slight makeover, but you know duplication is just a shortcut to madness. Rather, extract out the commonality into a <tt>&lt;macrodef&gt;</tt> task: </p> <pre> &lt;macrodef name=&quot;run-tests&quot;&gt; &lt;attribute name=&quot;classes&quot; /&gt; &lt;attribute name=&quot;fork&quot; default=&quot;false&quot; /&gt; &lt;element name=&quot;options&quot; optional=&quot;true&quot; /&gt; &lt;sequential&gt; &lt;junit haltonfailure=&quot;true&quot; fork=&quot;@{fork}&quot;&gt; &lt;classpath refid=&quot;project.classpath&quot; /&gt; &lt;formatter type=&quot;brief&quot; usefile=&quot;false&quot; /&gt; &lt;batchtest&gt; &lt;fileset dir=&quot;${build.test.dir}&quot; includes=&quot;@{classes}&quot; /&gt; &lt;/batchtest&gt; &lt;options /&gt; &lt;/junit&gt; &lt;/sequential&gt; &lt;/macrodef&gt; </pre> <p> Notice that the <tt>run-tests</tt> macro has two attributes: <tt>classes</tt> and <tt>fork</tt>. When you call the macro, you must provide a value for <tt>classes</tt>. The <tt>fork</tt> attribute, if not specified, has a default value of <tt>false</tt>. The real work happens in the <tt>sequential</tt> task, composed of the same tasks as your original <tt>test</tt> target. The difference here is instances of <tt>@{fork}</tt> and <tt>@{classes}</tt> are replaced with their corresponding attribute values. Additionally, the <tt>&lt;options&gt;</tt> element is replaced with the elements enclosed in an <tt>options</tt> element, if specified when the macro is called. </p> <p> Now change the <tt>test</tt> target to simply call your <tt>run-tests</tt> macro: </p> <pre> &lt;target name=&quot;test&quot; depends=&quot;compile-tests&quot;&gt; &lt;run-tests classes=&quot;**/*Test.class&quot; /&gt; &lt;/target&gt; </pre> <p> Note that these tests run with a <tt>fork</tt> attribute value of <tt>false</tt> and without any options. That is, the default attribute values are used and the optional elements aren&#8217;t provided. Ah&#8230; less XML for you to type and maintain. </p> <p> Finally, define a new target that calls the <tt>run-tests</tt> macro to run just the database tests: </p> <pre> &lt;target name=&quot;test-database&quot; depends=&quot;compile-tests&quot;&gt; &lt;run-tests classes=&quot;**/TestDB.class&quot; fork=&quot;yes&quot;&gt; &lt;options&gt; &lt;sysproperty key=&quot;db.url&quot; value=&quot;${db.url}&quot; /&gt; &lt;sysproperty key=&quot;db.user&quot; value=&quot;${db.user}&quot; /&gt; &lt;sysproperty key=&quot;db.password&quot; value=&quot;${db.password}&quot; /&gt; &lt;/options&gt; &lt;/run-tests&gt; &lt;/target&gt; </pre> <p> In this case, the <tt>fork</tt> attribute is turned on and a few system properties are provided. (Note that any element that can be nested inside of a <tt>&lt;junit&gt;</tt> task can be specified in the <tt>&lt;options&gt;</tt> element.) </p> <p> Extracting the common tasks and defaults out into the <tt>run-tests</tt> macro removed duplication, which means we can change the steps of the testing process in one location: the <tt>run-tests</tt> macro. This works well for common build targets that are complex in that they include several tasks and/or use several properties, such as the <tt>&lt;javac&gt;</tt> task. By comparison, the new <tt>&lt;presetdef&gt;</tt> task is similar to <tt>&lt;macrodef&gt;</tt>, but it doesn&#8217;t allow custom parameters to be specified. In other words, if <tt>&lt;macrodef&gt;</tt> is like a Java method that takes arguments, <tt>&lt;presetdef&gt;</tt> is like a no-arg method. </p> <p> Combined with the new <tt>&lt;import&gt;</tt> task we visited <a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Import.rdoc">last time</a>, use of the <tt>&lt;macrodef&gt;</tt> task leads to shorter build files and consistency across projects. And by writing macros that have intention-revealing names and use intelligent defaults, your build files start to read more like a concise build language. </p> <p> There&#8217;s more to come, so stay tuned for the next new feature&#8230; </p> Ant 1.6 Goody: <import> http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/Ant16Import.rdoc If you&#8217;re using <a href="http://ant.apache.org/">Ant</a> but have yet to upgrade to Ant 1.6, then you&#8217;re missing out. Just to give you a glimpse of what you&#8217;re missing, over the next several weeks I&#8217;ll post quick examples of new features in Ant 1.6 that help reduce duplication in your build process so that you spend less time writing and maintaining build files. <p> To kick-start the tour, let&#8217;s begin with a new feature that promotes consistency across projects. The <tt>&lt;import&gt;</tt> task lets you conveniently mix in tasks from other build files. Say, for example, you have a build file called <tt>build-common.xml</tt> that includes common properties and tasks, such as a <tt>compile</tt> target. </p> <pre> &lt;project name=&quot;common&quot;&gt; ... &lt;target name=&quot;compile&quot; depends=&quot;prepare&quot;&gt; &lt;javac srcdir=&quot;${src.dir}&quot; destdir=&quot;${build.prod.dir}&quot; classpathref=&quot;project.classpath&quot;/&gt; &lt;/target&gt; ... &lt;/project&gt; </pre> <p> Tomorrow you&#8217;re breaking ground on a new Java project, and it&#8217;s up to you to define the one-step build process. Obviously it will need to compile source files, so you need a <tt>compile</tt> target. Rather than falling prey to copy/paste reuse, create a project-specific <tt>build.xml</tt> file and import the existing <tt>build-common.xml</tt> file. </p> <pre> &lt;project name=&quot;dms&quot; basedir=&quot;.&quot;&gt; &lt;import file=&quot;build-common.xml&quot; /&gt; &lt;/project&gt; </pre> <p> By importing <tt>build-common.xml</tt>, the project-specific build file has inherited all the common tasks and properties. For example, you&#8217;ve barely broken a sweat typing angle brackets and you&#8217;re already compiling code: </p> <pre> $ ant compile Buildfile: build.xml prepare: [mkdir] Created dir: /Users/mike/work/dms/build/prod compile: [javac] Compiling 4 source file to /Users/mike/work/dms/build/prod BUILD SUCCESSFUL Total time: 3 seconds </pre> <p> Ah, but your project needs to do some work before and after the compilation step. It&#8217;s tempting to copy the <tt>compile</tt> target and modify it for project-specific needs, but that&#8217;s only because you haven&#8217;t tasted another spice of <tt>&lt;import&gt;</tt>: target overriding. Simply override the <tt>compile</tt> target in your <tt>build.xml</tt> file to add more behavior. </p> <pre> &lt;project name=&quot;dms&quot; basedir=&quot;.&quot;&gt; &lt;!-- Override common properties here. --&gt; &lt;import file=&quot;build-common.xml&quot; /&gt; &lt;target name=&quot;compile&quot; depends=&quot;pre-compile, common.compile, post-compile&quot; /&gt; &lt;target name=&quot;pre-compile&quot;&gt; &lt;echo&gt;Compiling...&lt;/echo&gt; &lt;/target&gt; &lt;target name=&quot;post-compile&quot;&gt; &lt;echo&gt;Done.&lt;/echo&gt; &lt;/target&gt; &lt;/project&gt; </pre> <p> Notice that the project-specific <tt>compile</tt> target uses a dependency order to ensure that the local <tt>pre-compile</tt> target is invoked before the common <tt>compile</tt> target (specified as <tt>common.compile</tt>) and the local <tt>post-compile</tt> target is called at the end. </p> <p> Now you have a project-specific compile step: </p> <pre> $ ant compile Buildfile: build.xml pre-compile: [echo] Compiling... prepare: common.compile: post-compile: [echo] Done. compile: BUILD SUCCESSFUL Total time: 3 seconds </pre> <p> Nothing was compiled because everything was up-to-date from the previous build, but notice that the <tt>common.compile</tt> target was indeed bracketed with your project-specific steps. </p> <p> You&#8217;re done! So, now that your build process is in place, what&#8217;s next? Well, because setting up the build didn&#8217;t take long, you probably still remember that code you need to write. And now that you&#8217;re using the <tt>&lt;import&gt;</tt> task, hopefully you can steer clear of the build file until next week, when we peek at another new feature. </p> Need an Ant Map? http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/NeedAnAntMap.rdoc Many are the build explorers who have hacked their way through the tangled undergrowth of Ant build files in search of target dependencies. A few of these brave souls have not been heard of since disappearing into the jungle with a machete raised high above their heads. We know some of them are still slogging away deep inside the jungle only because they let out a primary scream when they discover that their labyrinth is called Ant 1.6. <p> No doubt, the new &lt;import&gt; and &lt;macrodef&gt; tasks in Ant 1.6 are a boon when it comes to creating a modular build system and reducing duplication across build files. But the extra level of indirection created by a mixin with an overridden abstract target, for example, can quickly throw you off the trail. </p> <p> Carefully lay down your machete, brave explorer, before you&#8217;re minus one good typing finger, and pick up the <a href="http://www.nurflugel.com/webstart/AntScriptVisualizer/">Ant Script Visualizer</a>. It lets you visualize how your Ant targets and build files are related to one another by showing all the relationships between imports, targets, macrodefs, taskdefs, etc. Using <a href="http://www.graphviz.org/">GraphViz</a> (installed separately), Ant Script Visualizer can generate an Ant target treasure map in PNG and SVN output formats, and PDF on Mac OS X (<a href="http://www.nurflugel.com/webstart/AntScriptVisualizer/help/html/html/using_ant_script_visualizer.html">example outputs</a>). <a href="http://www.nurflugel.com/webstart/AntScriptVisualizer/antscriptVisualizer.jnlp">Launch it with Java Web Start</a> to consistently use the freshest version. </p> CruiseControl Action Movie http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/CCActionMovie.rdoc Every time I have an opportunity to talk to a group about continuous integration, I just fire up <a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a> and act out a project episode. Not everyone ends up using CruiseControl on their project, but at least they walk away knowing what a continuous integration tool can do for them. <p> To help spread the word, I made a <a href="http://media.pragprog.com/movies/auto/CruiseControl_MikeClark.html">2-minute screen video with voiceover</a> (8MB, <em><a href="http://www.apple.com/quicktime/download/">QuickTime</a></em>) of CruiseControl in action. The experience is lossy in the sense that I&#8217;ve sacrificed quality to keep the file size to a minimum and, well, it&#8217;s not a live performance. </p> <p> <a href="mailto:mike@clarkware.com">Let me know</a> what you think. </p> Making RSS Feeds Out of CruiseControl Log Files http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/RSSFeedsForCC.rdoc A gentle reader asks where to find the XSLT stylesheet I wrote to make RSS feeds out of <a href="http://cruisecontrol.sourceforge.net/">CruiseControl</a> XML log files. That stylesheet is described on page 29 of the <a href="http://pragmaticprogrammer.com/starter_kit/au/index.html">book</a>, with a footnote mentioning that the file is available on the book&#8217;s web site. Trouble is, finding the file is a bit tricky because it&#8217;s buried in the code bundle, available <a href="http://pragmaticprogrammer.com/starter_kit/au/code.html">here</a>. <p> In the <tt>builds</tt> directory of the code bundle you&#8217;ll find a <tt>buildstatus.xsl</tt> file. If you know anything about XSLT, shield your eyes. I&#8217;m sure I committed more than one XSLT sin when I wrote the file, so please feel free to school me by making it better and contributing the new-and-improved file back. </p> <p> Once you&#8217;ve placed the <tt>buildstatus.xsl</tt> file in a comfy directory on the local hard drive, add an <tt>XSLTLogPublisher</tt> to your CruiseControl <tt>config.xml</tt> file, like so: </p> <pre> &lt;publishers&gt; &lt;XSLTLogPublisher directory=&quot;/path/to/webserver/documents&quot; outfilename=&quot;your_project_build_status.rss&quot; xsltfile=&quot;/path/to/buildstatus.xsl&quot; /&gt; &lt;/publishers&gt; </pre> <p> After CruiseControl has completed a build cycle, you can conveniently monitor your project&#8217;s build status by pointing your favorite RSS reader to a URL similar to the following: </p> <pre> http://your_server:port/your_project_build_status.rss </pre> <p> The generated RSS file will always contain exactly one item&#8212;a summary of the last build. That is, you won&#8217;t see a history of all builds, but you do get a link back to the CruiseControl web application if you want to do build archaeology. </p> <p> Enjoy! </p> Mini Build Server http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/MiniBuildServer.rdoc I realize that by owning a PowerBook I&#8217;m biased, but I can&#8217;t help but think that the new <a href="http://www.apple.com/macmini/">Mac mini</a> would be an ideal dedicated build server for some small to medium-sized projects that lack available machines. It&#8217;s conveniently missing everything you don&#8217;t need in a build server: display, keyboard, and mouse. Yes, the hardware you do get is proprietary, but it runs a UNIX-based operating system that&#8217;s conveniently loaded with everything you want: a rich command-line environment with shells for commanded automation, dynamic languages such as Ruby and Python that excel at project chores, other programming languages such as Java and C/C++, secure connection protocols such as ssh, cron for scheduled automation, and the Apache web server for monitoring builds and serving up RSS feeds. <p> At $499 for the 1.25GHz model, I suspect the Mac mini would pay for itself the first time it detects an integration problem that would have thrashed the team for an hour. Most projects will need to pop for more memory (it ships with 256MB), but even the low-end model has enough horsepower to compile code and run tests. And if the throughput of builds becomes an issue as your project grows, you could buy a bigger box or cluster a few minis together to make an inexpensive build server. </p> <p> Out of the box, plugged into your network, the Mac mini is almost ready, obviously willing, and certainly able to devote its life to continuously baking fresh builds and doing other project chores. I recognize that lots of IS departments won&#8217;t be OK with this. Please choose a machine that works best for your project. The point is you really can&#8217;t afford not to have a dedicated build server, and if cost is an issue, then you might consider starting here. </p> Using CruiseControl with Subversion http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/CCWithSVN.rdoc One of the convenient things about <a href="http://subversion.tigris.org/">Subversion</a> is that it looks and feels like <a href="https://www.cvshome.org/">CVS</a>. If you&#8217;re comfortable with CVS, then learning Subversion is a breeze. <p> To demonstrate the similarities, I ported the CruiseControl configuration files included in the <a href="http://www.pragmaticprogrammer.com/starter_kit/au/scheduled.pdf">Scheduled Builds</a> chapter of the <a href="http://www.pragmaticprogrammer.com/sk/auto/">book</a> to use Subversion. As you read through that chapter, you can pretty much say &quot;Subversion&quot; every time you read the word &quot;CVS&quot;, while ignoring any references to <tt>CVSROOT</tt>. Likewise, any time you see the command <tt>cvs</tt>, think <tt>svn</tt>. Oh, and Subversion <em>does</em> support atomic commits, so the use of a quiet period with CruiseControl is less important. </p> <p> For the <tt>cc-build.xml</tt> file on page 51 of the book (page 10 of the chapter PDF), replace </p> <pre> &lt;cvs command=&quot;co dms&quot; /&gt; </pre> <p> with </p> <pre> &lt;exec executable=&quot;svn&quot;&gt; &lt;arg line=&quot;co /path/to/svn-repo/dms/trunk dms&quot; /&gt; &lt;/exec&gt; </pre> <p> There is an <a href="http://subclipse.tigris.org/svnant.html">Ant task</a> for Subversion, but it&#8217;s not distributed with the current version of Ant. I used the <tt>&lt;exec&gt;</tt> task because it gets this small job done with less configuration steps. </p> <p> For the <tt>config.xml</tt> file on page 59 of the book (page 18 of the chapter PDF), replace </p> <pre> &lt;cvs localworkingcopy=&quot;checkout/dms&quot; /&gt; </pre> <p> with </p> <pre> &lt;svn localworkingcopy=&quot;checkout/dms&quot; /&gt; </pre> <p> The <tt>&lt;svn&gt;</tt> source control element is included with recent releases of CruiseControl. </p> <p> And that&#8217;s all there is to it! </p> MobBuilding http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Build/MobBuilding.rdoc <em>When <a href="http://www.martinicity.net">Mike Blake's</a> team used their own mobile application to serve up a fresh build of that same application, they made sure they had something to help wash the dog food down. Brilliant! He writes:</em> <p> &quot;No more think, time to drink!&quot; shouted Fernando from his seat at a door propped up on plastic sawhorses. This was my favorite thing to hear late on a Thursday at a small start-up company south of San Francisco back at the turn of the century. We developed mobile applications at <a href="http://web.archive.org/web/20010201050500/http://viafone.com/">ViaFone</a>. I worked as the build manager with several talented engineers who constantly introduced me to the latest technologies including <a href="http://ant.apache.org/">Ant</a> and <a href="http://junit.org/">JUnit</a>. So it was no surprise that we had fully automated checkout, build, installation and testing of our core product. </p> <p> Although the build fired off automatically early every morning, there were times when colleagues needed additional builds to use the latest functionality. Since our company mission was to create applications for mobile devices, I decided to try eating a little of our own dog food. I installed a lightweight telnet application on my Kyocera Palm OS phone, had a friend poke a hole in the firewall, and with a few simple shell scripts it was born: The Mobile Build. </p> <p> Thursday drink night had grown from an informal gathering of engineers to a company wide tradition. One Thursday evening at an Irish pub in downtown Frisco, I received a call from a project manager requesting a fresh build. This was a golden opportunity to debut The Mobile Build. I pulled out my stylus, logged on to the build server, and ran a shell script. A tail of the log file scrolled gracefully by on the little monochrome screen. The phone made its way around the pub. Happy engineers watched in turn as their components built and tested successfully. The Guinness tasted sweet just then. &quot;Technically, we&#8217;re all working right now,&quot; said our leader Fernando. Well then, I thought, cheers to automation! </p>