Tuesday 7 February 2012

Ivy based subproject as maven module

I have previously written about the challenges of integrating an Ivy based subproject (like the play framework) into a build that is otherwise Maven based. After some work it is now working although the support feels a bit rudimentary.Here are the highlights on how to make it work

Prepare play framework:
The play framework must be installed and available to Hudson.

Dependency management is done by maven
Instead of duplicating maven's settings.xml configuration in Ivy, you can rely on the fact that maven will resolve any dependencies and place them in the local Maven repository before any Ivy commands are executed. This way the Ivy settings only need to contain a reference to the local repository and not muck around with remote resolutions.

Depending on how you create the dependencies.yml (see below), you might need to specify the dependencies twice, once for Maven and once for Ivy

Clean the extra directories:
Since play likes to spread its files more than just the normal src/ and target/ make sure the clean plugin cleans these extra directories as well

Generate Ivy configuration (conf/dependencies.yml):
Instead of checking in the Ivy config file into your SCM, you need to generate this as part of the build.This can be done using antrun to simply echo the file out before the compile stage. The reason is twofold.

Firstly the path to the local maven repository needs to be set

Secondly, if the dependencies.yml file is in SCM, then it would still point to the old versions when Maven is doing the release step unless some work is done to have Maven roll these versions forward and commit the changes to this file. It is easier to just generate the file on the fly.

Compile step:
The "precompile" command of the play compiler needs to be invoked instead of relying on the normal java compiler. Using antrun/exec plugin to do this task is easiest.

Package step:
This time the "war" command of the play compiler needs to be invoked. After the play compiler has run the resulting exploded war directory needs to be zipped and replace the war file generated by the normal war plugin so Maven picks up our custom package.

Care should be taken as to where the exploded war file is generated to. The reason is that you can run into a play bug. If you generate the war file within the Maven module, you must also exclude the output directory in order to avoid endless recursion. That in itself is not the problem, The problem arises if you choose "target" as your output  directory. Then you will have a clash between the play bug where the exclude directories are not evaluated from the module directory but on the full path, and the release plugin's checkout of the code into "target/checkout"

Since the Ivy parts are not fully integrated into maven, it does not understand when maven puts target folders on the classpath. This causes a problem during the release:prepare step when maven only executes "clean verify", because then Ivy cannot find the built dependencies. The trick is to reconfigure release:prepare to run "clean install" as preparation goals.

Outstanding issues:

  • Sometimes the play tests can leave hanging processes
  • Since play opens a socket, running concurrent build can clash. However the play part is usually so quick that even if SCM polling is set to every minute it is not a problem. 

No comments:

Post a Comment