views:

73

answers:

3

I'm developing several mavenised projects on my laptop, and periodically pushing to github. I've set up a private hudson server in the cloud that polls the git repositories for updates, and thus performs builds - so far so good.

Unfortunately, when I execute a 'mvn release:prepare' on my laptop to perform a release (say '1.5'), the two commits that occur (changing 1.5-SNAPSHOT to 1.5, then 1.5 to 1.6-SNAPSHOT) are pushed together into my git repo - and Hudson obviously builds the most recent one, ie 1.6-SNAPSHOT - and completely ignores the 1.5 release.

It wouldn't matter so much, but the projects depend on each other, and I would like to declare non-snapshot versions in my poms. However, when project B depends on version 1.5 of project A, it's nowhere to be found in the local maven repository for the hudson user on the Hudson box - because it's never been built - and so the build of project B fails.

It would great if I could make Hudson a little cleverer, and when it sees a maven release version flying through, forces a build and install of that particular version, before proceeding to do a build of the later snapshot commit.

I've been looking through the Hudson plugins, and in particular the 'M2 Release Plugin':

http://wiki.hudson-ci.org//display/HUDSON/M2+Release+Plugin

-however, that plugin seems to be more geared towards manually selecting a build you want to promote up to some more official Maven Repo, rather than forcing Hudson to automatically build & install every release build it comes across.

Update: some of my underlying requirements have led me to rethink what I want to achieve here- apologies for not expressing them earlier:

  • Most of the projects are open-source or intended to be open eventually, and I would like anyone to be able to git clone any single project, checkout a release tag, and do a mvn install without requiring any other repo for dependencies but maven central.
  • In order to get consistent results (across my laptop, the hudson server, and other people's checkouts), this obviously indicates a preference for declaring non-snapshot dependencies in my poms (at least for the release versions).
  • This led me down the path of trying to get Hudson to 'mvn install' the release artifacts as they whizzed past, so that later, Hudson building project B wouldn't fail when it couldn't find project A's release version (which is where this question came from)

Additionally:

  • I use sonotype's wonderful oss hosting, which requires GPG signing - and I don't want to have my GPG key stored on any hardware I can't hold in my hand :) - so bunging it up on the Hudson server in the cloud is not an option.
  • Mentally, having the Hudson server do releases is a bit foreign to me - I really just want it for CI.
+2  A: 

What you need now is to actually perform the release. Quoting the Maven - Guide to using the release plugin:

Performing the release

The plugin will extract file revisions associated with the current release. Maven will compile, test and package the versioned project source code into an artifact. The final deliverable will then be released into an appropriate maven repository.

The release:perform goal will:

  1. Extract file revisions versioned under the new tag name.
  2. Execute the maven build lifecycle on the extracted instance of the project.
  3. Deploy the versioned artifacts to appropriate local and remote repositories.

References

Pascal Thivent
That's not quite the solution I'm look for - I'm aware that 'mvn release:perform' follows a 'mvn release:prepare'.
Roberto Tyley
@Roberto Whether `release:perform` follows `release:prepare` is not really my point. My point is that `release:perform` does *exactly* what you're asking for: _The plugin will extract file revisions associated with the current release. Maven will compile, test and package the versioned project source code into an artifact. The final deliverable will then be released into an appropriate maven repository_. But feel free to ignore.
Pascal Thivent
as it happens, I'm releasing to oss.sonatype.org, where the repo paths are obfuscated until you decide to manually promote a build. Because that's an obfuscated path, I can't easily set my Hudson server to point to that repo... In order for project B to build successfully after I update it's dependency on project A to 1.5, it would be great if Hudson could have built that version of Project A for me, and installed it to it's local repo - rather than waiting for it to sync thru
Roberto Tyley
@Roberto - doesn't `mvn release:perform` invoke the `deploy` lifecycle phase? Then you're covered since `deploy` also includes the `install` phase. http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html
Robert Munteanu
@Robert yep, but unfortunately it's not deploying to anywhere useful for the Hudson server. The Hudson server doesn't currently have it's own Nexus server to point to, it just uses central and it's own local .m2 directory (which is why it would be nice if it could dump it's own builds there). Even if I did have my own Nexus server, I think that deploy:deploy can only support deploying to one location - which I would prefer to be oss.sonatype.org.
Roberto Tyley
@Roberto But... `install` will be triggered so the artifact(s) will be installed in the local repository of the hudson user. There is something unclear about your exact expectations/constraints.
Pascal Thivent
Roberto Tyley
@Roberto I understood that but you can get the 1.5 artifact installed using `release:perform`.
Pascal Thivent
@Pascal, just to clarify, we both mean that 'release:perform' is being executed on my laptop right? If that's the case, given that the Hudson server in the cloud has no access to any Maven repo other than Maven Central and it's own local .m2 directory, how is the 1.5 artifact generated on my laptop going to be available to the hudson server? 'release:perform' would have to scp the artifact from my laptop to the hudson server, dropping it into the hudsons local .m2 repo?
Roberto Tyley
@Roberto Well, actually, I was assuming that the whole release, including `release:perform`, was executed on the build machine. But now that I reread the question more carefully, I realize your laptop is involved. Maybe I went to fast on this. But I'm not sure to understand how you expect things to work and where things are supposed to be published (whether it's a local or remote repository).
Pascal Thivent
@Roberto Just run release:prepare and then release:perform in Hudson. @Pascal has it right. Have you tried it? Try it. I use a freestyle build which is a shell wrapper around these two steps, because I do a few other things after release:perform. I also find it easiest to keep straight when the release build job is a separate job from the CI builds of your project.
Zac Thompson
Roberto Tyley
A: 

You could specify profiles that determine whether the build is to be deployed locally or remotely:

<project>
    <profile>
        <id>local-deploy</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <distributionManagement>
            <repository>
                <id>local-repo</id>
                <name>My Local Repo</name>
                <url>file://my/local/repo/dir</url>
            </repository>
        </distributionManagement>
    </profile>
    <profile>
        <id>remote-deploy</id>
        <activation>
            <activeByDefault>false</activeByDefault>
            <property>
                <name>remote.repo.url</name>    
            </property>
        </activation>

        <distributionManagement>
            <repository>
                <id>remote-repo</id>
                <name>My Remote Repo</name>
                <url>${remote.repo.url}</url>
            </repository>
        </distributionManagement>
    </profile>
</project>

Then you can safely run the release:perform goal and, by passing in a value for remote.repo.url, you also have the option of a remote deploy.

Tim Clemons
@tim - thanks, I can see that profiles would also help with issues like GPG signing which would stop release:perform from working on the Hudson server. However, I think I'm on the verge of self-answering this question as I've reconsidered my workflow and some aspects which I didn't elucidate very well in my question have led me to a chose a different path.
Roberto Tyley
A: 

I've updated my problem description to mention my preference for declaring non-snapshot dependencies in my poms (at least for the release versions), in order to get consistent results (across my laptop, the hudson server, and other people's checkouts) - I really want other people to be able to check out my code and get going with zero mucking about looking for unknowable snapshot dependencies.

It was wanting to use non-snapshot versions in my dependencies that led to this question- Hudson's normal behaviour didn't make using 'release' versions easy, at least without waiting for the release version of the dependency to cycle thru to maven central.

However, I've decided that if I want to be true to my underlying requirement - that people can easily checkout and build my code - then that is what I have to do: i.e. wait for maven central to sync up.

I only want to hold myself to this for release builds (otherwise I'd never get anything done!), and so will happily develop using snapshot deps - up until the point where I actually do want to make a version release, at which point I want all the deps to be properly available in maven central.

I wasn't aware of any way to enforce this until recently, but a bit more googling found me the 'enforcer' plugin:

http://maven.apache.org/enforcer/enforcer-rules/requireReleaseDeps.html

-with the 'onlyWhenRelease' flag set to true, it looks like it should perfectly enforce what I want to do.

In answer to my original headline question then ('How can I make Hudson automatically build & install release artifacts, rather than just snapshots?'), my answer is:

  1. There appears to be no completely trivial way of making Hudson do this (without the side-effect of Hudson also attempting to do a 'release' with every checkin it detects, which can require additional 'profile' configuration to stop the actual normal actions of a release, eg GPG signing)
  2. Don't do that.
Roberto Tyley
Given all the additional requirements (or unsaid) that you didn't mention in the initial question, using Hudson to do the release does indeed not sound like a good idea (which is actually true in most cases).
Pascal Thivent