Skip to main content

Fixing two problems with Maven + Mercurial + Hudson: second take

Posted by fabriziogiudici on November 9, 2009 at 11:46 AM PST

In the past weekend I've been able to improve the settings for
automated Maven releases that href="http://weblogs.java.net/blog/fabriziogiudici/archive/2009/10/29/fixing-two-problems-maven-mercurial-hudson">I've
blogged about about ten days ago. Peter Mount href="http://www.retep.org/2009/11/releasing-to-kenai-via-maven.html">complemented
the information with some practical examples on how to use
that stuff invoking Maven with the proper parameters. I've been able to
significantly clean up and improve the Maven configuration, so now a
staged release can be performed exclusively with a sequence of Maven
invocations, specifying profiles instead of a complicated set of
parameters. And I'll show you how to fit it better with a CI
environment such as Hudson.



I'm not repeating the concepts behind this stuff, that have been href="http://weblogs.java.net/blog/fabriziogiudici/archive/2009/10/29/fixing-two-problems-maven-mercurial-hudson">explained
in my previous post, but just showing you the relevant
sections of the POM.



First, the SCM URL is defined by means of a property, which is style="font-family: monospace;">hg.repo.url,
whose value has a default in the properties section:



<scm> style="font-family: monospace;">
   
<connection>scm:hg:http://kenai.com/hg/forceten~src</connection>
style="font-family: monospace;">
   
<developerConnection>scm:hg:${hg.repo.url}</developerConnection>
style="font-family: monospace;">
   
<url>http://kenai.com/projects/forceten/sources/src/show</url>
style="font-family: monospace;">
</scm> style="font-family: monospace;">
<properties> style="font-family: monospace;">
   
<hg.repo.url>https://kenai.com/hg/forceten~src</hg.repo.url>
style="font-family: monospace;">
   
<staging.mvn.repo.url>file://${project.build.directory}/target-maven-repo</staging.mvn.repo.url>
style="font-family: monospace;">
</properties>



Then you define a style="font-family: monospace; font-weight: bold;">“release”
profile which is used to create the staged release, that is to have a
local pair of (Maven;Mercurial) repositories populated with all the
relevant artifacts. The profile overrides and defines some properties,
such as hg.repo.url
and altDeploymentRepository,
that make Maven point to the staging repositories; furthermore it
installs during the initialization phase a couple of goals that scratch
and create the relative directories under the  style="font-family: monospace;">target folder
(the staging Mercurial repo is also initialized). There's still a minor
issue, in the fact that those directories are created for every module,
not only for the main directory, in spite of the style="font-family: monospace;">inherited=false
property (which seems to be severely broken with Maven, or at least
obscure).



<profile> style="font-family: monospace;">
     
<id>release</id>
style="font-family: monospace;">
     
<properties>
style="font-family: monospace;">
style="font-family: monospace;">         
<hg.repo.url>file://${project.build.directory}/dummy-hg-repo</hg.repo.url> style="font-family: monospace;">
style="font-family: monospace;">         
<altDeploymentRepository>release-repo-hudson::default::${staging.mvn.repo.url}</altDeploymentRepository> style="font-family: monospace;">
     
</properties>
style="font-family: monospace;">


     
<build>


         
<plugins>
style="font-family: monospace;">
             
<plugin>
style="font-family: monospace;">
                 
<groupId>org.codehaus.mojo</groupId>
style="font-family: monospace;">
                 
<artifactId>exec-maven-plugin</artifactId>
style="font-family: monospace;">
                 
<executions>
style="font-family: monospace;">
                     
<execution>
style="font-family: monospace;">
                         
<id>clean-release-dirs</id>
style="font-family: monospace;">
                         
<phase>initialize</phase>
style="font-family: monospace;">
                         
<goals>


                             
<goal>exec</goal>
style="font-family: monospace;">
                         
</goals>
style="font-family: monospace;">
                         
<inherited>false</inherited>
style="font-family: monospace;">
                         
<configuration>
style="font-family: monospace;">
                             
<executable>rm</executable>
style="font-family: monospace;">
                             
<arguments>
style="font-family: monospace;">
                                 
<argument>-rf</argument>
style="font-family: monospace;">
                                 
<argument>${project.build.directory}/dummy-hg-repo</argument>
style="font-family: monospace;">
                                 
<argument>${project.build.directory}/target-maven-repo</argument>
style="font-family: monospace;">
                             
</arguments>
style="font-family: monospace;">
                         
</configuration>
style="font-family: monospace;">
                     
</execution>
style="font-family: monospace;">
                     
<execution>
style="font-family: monospace;">
                         
<id>create-release-dirs</id>
style="font-family: monospace;">
                         
<phase>initialize</phase>
style="font-family: monospace;">
                         
<goals>


                             
<goal>exec</goal>
style="font-family: monospace;">
                         
</goals>
style="font-family: monospace;">
                         
<inherited>false</inherited>
style="font-family: monospace;">
                         
<configuration>
style="font-family: monospace;">
                             
<executable>mkdir</executable>
style="font-family: monospace;">
                             
<arguments>
style="font-family: monospace;">
                                 
<argument>-p</argument>
style="font-family: monospace;">
                                 
<argument>${project.build.directory}/dummy-hg-repo</argument>
style="font-family: monospace;">
                                 
<argument>${project.build.directory}/target-maven-repo</argument>
style="font-family: monospace;">
                             
</arguments>
style="font-family: monospace;">
                         
</configuration>
style="font-family: monospace;">
                     
</execution>
style="font-family: monospace;">


                     
<execution>
style="font-family: monospace;">
                         
<id>init-dummy-hg-repo</id>
style="font-family: monospace;">
                         
<phase>initialize</phase>
style="font-family: monospace;">
                         
<goals>


                             
<goal>exec</goal>
style="font-family: monospace;">
                         
</goals>
style="font-family: monospace;">
                         
<inherited>false</inherited>
style="font-family: monospace;">
                         
<configuration>
style="font-family: monospace;">
                             
<executable>hg</executable>
style="font-family: monospace;">
                             
<workingDirectory>${project.build.directory}/dummy-hg-repo</workingDirectory>
style="font-family: monospace;">
                             
<arguments>
style="font-family: monospace;">
                                 
<argument>init</argument>
style="font-family: monospace;">
                             
</arguments>
style="font-family: monospace;">
                         
</configuration>
style="font-family: monospace;">
                     
</execution>
style="font-family: monospace;">
                 
</executions>
style="font-family: monospace;">
             
</plugin>
style="font-family: monospace;">
         
</plugins>
style="font-family: monospace;">
     
</build>
style="font-family: monospace;">
 
</profile>




A second profile, style="font-weight: bold; font-family: monospace;">“release-commit”,
performs both a Mercurial push from the staging repository and also
invokes the wagon-maven-plugin:merge-repo
goal, which synchronize the real Maven repository with the new
artifacts:



<profile> style="font-family: monospace;">
   
<id>release-commit</id>
style="font-family: monospace;">
   
<build>


       
<plugins>
style="font-family: monospace;">
           
<plugin>
style="font-family: monospace;">
               
<groupId>org.codehaus.mojo</groupId>
style="font-family: monospace;">
               
<artifactId>exec-maven-plugin</artifactId>
style="font-family: monospace;">
               
<executions>
style="font-family: monospace;">
                   
<execution>
style="font-family: monospace;">
                       
<id>push-hg</id>
style="font-family: monospace;">
                       
<phase>initialize</phase>
style="font-family: monospace;">
                       
<goals>


                           
<goal>exec</goal>
style="font-family: monospace;">
                       
</goals>
style="font-family: monospace;">
                       
<inherited>false</inherited>
style="font-family: monospace;">
                       
<configuration>
style="font-family: monospace;">
                           
<executable>hg</executable>
style="font-family: monospace;">
                           
<arguments>
style="font-family: monospace;">
                               
<argument>push</argument>
style="font-family: monospace;">
                           
</arguments>
style="font-family: monospace;">
                       
</configuration>
style="font-family: monospace;">
                   
</execution>
style="font-family: monospace;">
               
</executions>
style="font-family: monospace;">
           
</plugin>
style="font-family: monospace;">


           
<plugin>
style="font-family: monospace;">
               
<groupId>org.codehaus.mojo</groupId>
style="font-family: monospace;">
               
<artifactId>wagon-maven-plugin</artifactId>
style="font-family: monospace;">
               
<configuration>
style="font-family: monospace;">
                   
<source>${staging.mvn.repo.url}</source>
style="font-family: monospace;">
                   
<target>${project.distributionManagement.repository.url}</target>
style="font-family: monospace;">
                   
<targetId>${project.distributionManagement.repository.id}</targetId>
style="font-family: monospace;">
               
</configuration>
style="font-family: monospace;">
               
<executions>
style="font-family: monospace;">
                   
<execution>
style="font-family: monospace;">
                       
<id>merge-repo</id>
style="font-family: monospace;">
                       
<phase>initialize</phase>
style="font-family: monospace;">
                       
<goals>


                           
<goal>merge-maven-repos</goal>
style="font-family: monospace;">
                       
</goals>
style="font-family: monospace;">
                       
<inherited>false</inherited>
style="font-family: monospace;">
                   
</execution>
style="font-family: monospace;">
               
</executions>
style="font-family: monospace;">
           
</plugin>
style="font-family: monospace;">


       
</plugins>
style="font-family: monospace;">
   
</build>
style="font-family: monospace;">
</profile>



A third profile, style="font-family: monospace; font-weight: bold;">“release-cancel”,
can be used in alternative to “release-commit”
to throw away everything that has been prepared for the release,
perhaps because we only wanted to run a test. It basically scratches
the local Mercurial repository, so you have to clone it again from the
main remote repository. This could be improved, by just stripping (by
means of the hg
strip
command) the local commits that haven't be pushed
again, but I haven't found so far a simple way to detect the revision
number to strip from (and unfortunately it seems there's no such a
thing as a “strip all local commits” in Mercurial).



<profile> style="font-family: monospace;">
   
<id>release-cancel</id>
style="font-family: monospace;">
   
<build>


       
<plugins>
style="font-family: monospace;">
           
<plugin>
style="font-family: monospace;">
               
<groupId>org.codehaus.mojo</groupId>
style="font-family: monospace;">
               
<artifactId>exec-maven-plugin</artifactId>
style="font-family: monospace;">
               
<executions>
style="font-family: monospace;">
                   
<execution>
style="font-family: monospace;">
                       
<id>strip-hg</id>
style="font-family: monospace;">
                       
<phase>initialize</phase>
style="font-family: monospace;">
                       
<goals>


                           
<goal>exec</goal>
style="font-family: monospace;">
                       
</goals>
style="font-family: monospace;">
                       
<inherited>false</inherited>
style="font-family: monospace;">
                       
<configuration>
style="font-family: monospace;">
                           
<!-- FIXME: would be better to strip local changes -->
style="font-family: monospace;">
                           
<executable>rm</executable>
style="font-family: monospace;">
                           
<arguments>
style="font-family: monospace;">
                               
<argument>-rf</argument>
style="font-family: monospace;">
                               
<argument>.hg</argument>
style="font-family: monospace;">
                           
</arguments>
style="font-family: monospace;">
                       
</configuration>
style="font-family: monospace;">
                   
</execution>
style="font-family: monospace;">
               
</executions>
style="font-family: monospace;">
           
</plugin>
style="font-family: monospace;">
       
</plugins>
style="font-family: monospace;">
   
</build>
style="font-family: monospace;">
</profile>



At last, you need to configure the release plugin so the style="font-family: monospace;">“release”
profile is correctly propagated:



<plugin> style="font-family: monospace;">
   
<groupId>org.apache.maven.plugins</groupId>
style="font-family: monospace;">
   
<artifactId>maven-release-plugin</artifactId>
style="font-family: monospace;">
   
<configuration>
style="font-family: monospace;">
       
<preparationGoals>clean install
verify</preparationGoals>
style="font-family: monospace;">
       
<goals>clean install javadoc:javadoc assembly:assembly
deploy</goals>
style="font-family: monospace;">
       
<arguments>-Prelease
-DaltDeploymentRepository="${altDeploymentRepository}"</arguments>
style="font-family: monospace;">
   
</configuration>
style="font-family: monospace;">
</plugin>



Small tip: note that we are passing style="font-family: monospace;">altDeploymentRepository
- one could wonder why, as it would be automatically re-defined by the
forked Maven invocation. The reason is that its definition is relative
to the current working directory (e.g. style="font-family: monospace;">target/something)
so the re-definition in the forked Maven would set it to style="font-family: monospace;">target/checkout/target/something.



My Hudson job is now configured with a sequence of two Maven
invocations:



mvn -B -Prelease
clean install release:clean release:prepare release:perform
style="font-family: monospace;">
mvn -N
-P${RELEASE_MODE} initialize




The Hudson job is configured with a parameter named style="font-family: monospace;">RELEASE_MODE
which is used to choose whether you want to perform a true release or a
test one.



src="http://www.java.net/sites/default/files/FirefoxScreenSnapz004.png">

I've done also a couple more refinements which prove useful in a Hudson
environment, but it's a matter of another post.



You can see the real-world Hudson configuration href="http://hudson.tidalwave.it/hudson/job/ForceTen%20Release/configure">here
(if the link is broken, try to remove the /hudson part); you can also href="https://kenai.com/website/forceten/maven-repository/releases/it/tidalwave/geo/forceten/0.5.0/forceten-0.5.0-project.tar.gz">download
the related projects sources.

Related Topics >>