Teaching Mavenized Grails to Survive mvn release:prepare release:perform with Hudson

A mavenized Grails project has 2 competing sources stating the version of the application

  1. <version> within pom.xml
  2. app.version within application.properties

If 2. does not match 1. the grails-maven-plugin will abort the build, urging you to manually fix the version mismatch. Although somewhat clumsy, the release will still succeed if you edit application.properties and re-start the failing mvn release:prepare. However, you’re somewhat stuck, if the release is to be performed from within a continous integration server (e.g. Hudson).

Thus I devised a work-around, that will compare both versions and update the version within application.properties if required. My work-around is far from perfect, as I was unable to integrate it within the Maven lifecycle defined by the grails-maven-plugin. This lifecycle will always and unconditionally bind its own code to the validate phase first (aborting on version mismatches). Therefore I resorted to binding my repair action to the clean phase and changed the goals of the maven-release-plugin to perform a clean before invoking the deploy. Note that this will produce a consistent war (both pom and application.properties set to the release version), but will not resolve the discrepancy within the tagged sources (i.e. application.properties will still state the snapshot version).

Here’s my code. It uses a profile, which is only activated, if the file application.properties is actually present. Thus the code can be included within a parent pom.xml that might be used with non-Grails projects as well:

<profiles>
 <profile>
  <id>enable-reset.application.properties</id>
  <activation>
   <activeByDefault>false</activeByDefault>
   <file>
    <exists>application.properties</exists>
   </file>
  </activation>
  <build>
   <pluginManagement>
    <plugins>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-release-plugin</artifactId>
      <configuration>
       <!-- invoke clean first - see below -->
       <goals>clean deploy</goals>
      </configuration>
     </plugin>
    </plugins>
   </pluginManagement>

   <plugins>
    <!--
     Allow release:prepare/perform to succeed with Grails
     app. Reset application.properties.app.version to
     project.version Sorta hack on clean, as
     grails-maven-plugin:validate ALWAYS runs first and
     connot be preceeded by any other execution
    -->
    <plugin>
     <artifactId>maven-antrun-plugin</artifactId>
     <version>1.3</version>
     <executions>
      <execution>
       <id>reset.application.properties</id>
       <phase>clean</phase>
       <goals>
        <goal>run</goal>
       </goals>
       <configuration>
        <tasks>
         <taskdef resource="net/sf/antcontrib/antlib.xml"
          classpathref="maven.plugin.classpath" />
         <if>
          <available file="application.properties" />
          <then>
           <property file="application.properties"
            prefix="application.properties" />
           <if>
            <not>
             <equals arg1="${project.version}"
              arg2="${application.properties.app.version}" />
            </not>
            <then>
             <propertyfile file="application.properties"
              comment="Grails Metadata file">
              <entry operation="=" type="string" key="app.version"
               value="${project.version}" />
             </propertyfile>
            </then>
           </if>
          </then>
         </if>
        </tasks>
       </configuration>
      </execution>
     </executions>

     <dependencies>
      <dependency>
       <groupId>org.apache.ant</groupId>
       <artifactId>ant</artifactId>
       <version>1.7.1</version>
      </dependency>
      <dependency>
       <groupId>org.apache.ant</groupId>
       <artifactId>ant-nodeps</artifactId>
       <version>1.7.1</version>
      </dependency>
      <dependency>
       <groupId>ant-contrib</groupId>
       <artifactId>ant-contrib</artifactId>
       <version>1.0b3</version>
       <exclusions>
        <exclusion>
         <groupId>ant</groupId>
         <artifactId>ant</artifactId>
        </exclusion>
       </exclusions>
      </dependency>
     </dependencies>
    </plugin>
   </plugins>
  </build>
 </profile>
</profiles>

Links:

About Reiner

Born 1954 in Ratisbon (Bavaria, Germany), in 1976 punched cards at Berlin Technical University, caught hacking one of its mainframes by Horst Zuse (son of Konrad Zuse), started studying computer science and soon was offered a job whithin their computer department doing systems programming for IBM VM/370. While studying, jobbed around Germany at various places doing all sorts of things, then returned to Berlin to work at SRZ (computer aided typesetting). Never finished my master degree, but chose to take up self-employed work (which didn't turn me rich nor famous). Now working for a mid-sized software company within a very promising department as head of server software development.
This entry was posted in English, Grails, Maven. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s