tags:

views:

53

answers:

1

Let me first explain our infrastructure.

My company produces two enterprise software products (which each in turn include multiple servers). Lets call them ProductA and ProductB.

ProductA is made up of 40 individual projects that are branched together, but are all built separately and treated as individual units. As each of these projects create a large dependency tree, we use Ivy/Ant to manage our dependencies. TeamA is constantly modifying all of these projects, sometimes in backwards incompatible ways, so we publish everything to ivy as (an example) 1.0.0.SVN_REV. When we depend on something, we say 1.0.0.+ and use a conflict resolver that gets us a compatible set of dependencies.

Imagine a dependency graph like:

W -> X -> Y
       \
        -> Z
       /
     V

When our top level project depends on W 1.0.0.+ and V 1.0.0.+, we may not get the latest V as the latest W might not yet be built with the latest Z, so Ivy evicts the latest V, taking the 1.0.0.9 instead of 1.0.0.10 since both the latest W and V 1.0.0.9 depend on Z v1.0.0.6 All of these builds are driven with Bamboo, with dependencies configured to kick child builds when necessary, and thus each of these projects build separately.

So, given this setup, Ivy guarantees that all of our dependencies for the top level build are binary compatible. Now, the top level build may need the latest V to compile correctly, so would fail with a compile error, but if the compile succeeded, we would know for a fact that all the dependencies are binary compatible and that QA won't spend time installing 8 servers to find out some method is missing when W calls into Z.

ProductB leverages about 30 of these projects, but instead of taking the latest, it waits for ProductA's QA team to certify a release and then it starts consuming those dependencies.

Its fairly obvious how Maven would work for ProductB as they always depend on an unchanging set of dependencies.

So, to get to the crux of the question, when evaluating Maven, I see how SNAPSHOT dependencies and publishes give us the basic structure. However, what I don't know or understand is whether Maven, when publishing W, does it modify the POM, to fill in the explicit SNAPSHOT that was used, or does it just say that W depends on X-1.0.0-SNAPSHOT?

And if it doesn't replace the exact X used, how can I get the same binary compatible assurances that Ivy gives me?

The only obvious answer is to take one giant build to make all 40 projects, but that would take considerable time to build when a top level project is the only change. If it were 30 minutes to do the über compile, I would likely see 5-10 commits per build, which would make it difficult to evaluate which dev broke the build. So basically, I'm looking for a different solution than this.

A: 

When ivy publishes to a repository one can optionally specify the release version

<ivy:publish resolver="shared" pubrevision="1.0" status="release">
   <artifacts pattern="dist/[artifact].[ext]" />
</ivy:publish>

The great thing about ivy is that it will generate and publish a "ivy.xml" that will have all the dynamic version numbers resolved at the time of publication. All this you probably already know.

Surprisingly, Maven needs more work. You'll require plugins that will locally edit your POM (and if you have child modules their POMs as well). For more details see the following plugins

So you'll need to make sure your POMs are kosher before calling "mvn deploy".

To be honest I haven't completely abandoned my ivy based builds, because I find it difficult to emulate ivy's easy support for dynamic module interdependencies. I'm sure it's possible, like I said it just appears to be more work, when you're used to working with ivy.

To ease your transition from ivy to Maven, have you considered generating your module POMs using ivy? The following works very well for me:

<ivy:deliver deliverpattern="dist/ivy.xml" pubrevision="1.0" status="release"/>
<ivy:makepom ivyfile="dist/ivy.xml" pomfile="dist/pom.xml">
    <mapping conf="default" scope="compile"/>
    <mapping conf="runtime" scope="runtime"/>
</ivy:makepom>

The deliver task will resolve all dynamic dependencies and create an ivy file that can be used to generate a maven POM. This POM is then published alongside your modules standard artifact, and needs to be specified in the ivy file:

<ivy-module ..
..
    <publications>
         <artifact name="mymod" type="war" conf="master" />
         <artifact name="pom"   type="pom" ext="xml" conf="master" />
    </publications>

Make sure you're using version 2.2.0 of ivy and the standard ivy publish task (see above) should have no problem uploading your artifact and the generated POM

Mark O'Connor