07 February 2011

Maven Snapshot Repositories with Nexus

When you have a Maven build which depends on more than one external repository, it is usually a good idea to work with a repository manager. A repository manager also enables you to share your artifacts with other team members.

Nexus Open Source is probably the most popular Maven repository manager. Once it's set up correctly, it requires little or no maintenance, at least that's my experience after using it in different projects over the last three years.

I've just finished setting up Nexus for my current project, but this time, I spent almost a day chasing a problem related to snapshot repositories.

I had set up the Public Repositories group of Nexus as a mirror for Maven central and configured the Nexus Snapshots repository as an additional snapshot-enabled repository for the snapshots from my own project:



<mirrors>
    <mirror>
      <id>mynexus</id>
      <mirrorOf>central</mirrorOf>
      <name>Nexus</name>
      <url>http://nexus.example.com/content/groups/public</url>
    </mirror>
  </mirrors>

  <profile>
    <id>mysnapshots</id>
    <repositories>
      <repository>
        <id>mysnapshots</id>
        <url>https://nexus.example.com/content/repositories/snapshots</url>
        <snapshots>
          <enabled>true</enabled>
        </snapshots>        
       </repository>
     </repositories>
  </profile>

  <activeProfiles>
    <activeProfile>mysnapshots</activeProfile>
  </activeProfiles>

I did not enable snapshots for Central as suggested in the Nexus book, to avoid picking up any snapshots except my own. This setup worked fine in my local workspace and on our build server, but then my off-site co-workers started complaining about build failures.

They had error messages of the kind

Unable to find resource 'com.example.foo:jar:0.0.1-SNAPSHOT' in repository mysnapshots (http://nexus.example.com/content/repositories/snapshots)

even though they could see the required artifact in the given repository via the Nexus interface. Or so we thought...

It turned out that we'd simply misinterpreted the Maven console messages:

Downloading: http://nexus.example.com/content/repositories/snapshots/com/example/foo/0.0.1-SNAPSHOT/foo-0.0.1-SNAPSHOT.pom

should have given us a clue to the root cause, seeing that snapshot resources in remote repositories always have the SNAPSHOT suffix replaced by a timestamp, so the message really should have been something like

Downloading: http://nexus.example.com/content/repositories/snapshots/com/example/foo/0.0.1-SNAPSHOT/foo-0.0.1-20110207.090228-284.pom

The problem was the configuration of the Public Repositories group in Nexus which includes the hosted Snapshots repository by default. This appears to have led to the following scenario:

  • Client requests com.example.foo:jar:0.0.1-SNAPSHOT.
  • Maven tries to locate this artifact in Central.
  • Central is mirrored to Nexus Public Repositories, which includes Nexus Snapshots, which hosts the requested artifact.
  • Thus, Maven has found a match in Central and tries to download it from Central.
  • Now since Snapshots are not enabled for Central, the SNAPSHOT to timestamp conversion does not take place and Maven tries to download a non-existing resource, failing with a somewhat misleading error message.

Solution:


After deleting the Snapshots repository from the Public Repositories group in Nexus, all builds were working fine on all sites.

No comments: