Showing posts with label Nexus. Show all posts
Showing posts with label Nexus. Show all posts

April 22, 2009

Maven Setting for Using a Single Repo Manager

In a previous post I have tried to explain why it's a good idea to define your Maven repository in your settings.xml file instead of the POM.

Of course, there is some information available on how to do this, for instance in the Maven Settings Reference, the Mirrors Guide, or the great Nexus book from Sonatype.

Nevertheless, this setup of repositories, proxies and mirrors can be a bit tricky (and is quite confusing when just starting with Maven), so here is how we did that.

How should it look like?

We use the Nexus repository manager and especially do like the repository groups which combine repositories into single logical repo. (This feature is also implemented by other products like Archiva or Artifactory, see this Feature Matrix).

Now, here is the approach we want to implement:

  • Access the repository group "internal" for release and snapshot versions of all internal artifacts that have been produced by our company
  • Use the "public" repository group to provide release versions of all external artifacts (we don't want external snapshots!)
  • For downloading plugins, use both the "public" as well as the "internal" repository group to get release versions (we don't want to use snaphot version of plugins!)
  • Don't use any other repository than "public" or "internal", no matter what is configured in project's POM, inherited POM, transitive dependencies, dependencies of plugins, etc. -- never ever!


Defining the Repositories

This is the required repository definition:

  • We use a profile (that is activated by default) to group the repositories. This is actually not required, but gives a bit more flexibility.
  • For artifact resolution, there are two repositories with id "central" and "internal" to provide public (external) respectively internal artifacts.
  • The definition for "central" repository is overriding (by using the same id) the "central" repository already defined in the implicit super POM, which is using repo1.maven.org for downloads.
  • The given URLs are only bogus and are overridden by mirror settings – see below.
  • Additionally, we define the same two repositories "central" and "internal" as plugin repositories (required by Maven to find plugins). However, in contrast to artifacts, snapshots are not allowed at all.

And here is how the code looks like:

<profiles>
<profile>
<id>repo-config</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>

<repositories>
<!-- repo "central": override Maven default,
mirrored to Nexus group "public" -->
<repository>
<id>central</id>
<url>http://central</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<!-- repo "internal": provides internal release and snapshot artifacts,
mirrored to Nexus group "internal" -->
<repository>
<id>internal</id>
<url>http://internal</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</snapshots>
</repository>
</repositories>

<pluginRepositories>
<!-- plugin-repo "central": override Maven default,
mirrored to Nexus group "public" -->
<pluginRepository>
<id>central</id>
<url>http://central</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<!-- plugin-repo "internal": provides internal plugin releases,
mirrored to Nexus group "internal" -->
<pluginRepository>
<id>internal</id>
<url>http://internal</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>

</profile>
</profiles>

Defining the Mirrors

After defining the repositories, two issues are left: we have to specify the correct URLs, and to make sure nobody uses any other repository. Both of this is done with the <mirrors> definition.

  • Repository with id "internal" is mapped to the URL of the "internal" Nexus group; that is, Maven uses that URL instead of what is given with the repository definition (the bogus URL http://internal).
  • Every other repository (specified by using <mirrorOf>*</mirrorOf>) is mapped to the URL of the "public" Nexus group.
  • This last definition not only maps the "central" repository to the correct URL, but also any other repository and hence ensures every request is locked down to the internal repository manager.

Again, here is the section from settings.xml file:

<mirrors>
<mirror>
<id>nexus-internal</id>
<name>Nexus internal repository group</name>
<url>http://our-nexus-server:8081/nexus/content/groups/internal</url>
<mirrorOf>internal</mirrorOf>
</mirror>
<mirror>
<id>nexus-public</id>
<name>Nexus public repository group</name>
<url>http://our-nexus-server:8081/nexus/content/groups/public</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>

What about the Proxy?

The <proxy> section in the settings.xml file can be used to define a network proxy that is used for some or all of your HTTP requests. In our configuration, since the Nexus repository manager is running on an internal server and Maven is configured to not connect to any other server, we just don't need this setting.

See Configuring a proxy for more details on Maven Proxies. BTW, it should now be very clear that mirrors in the Maven world are something completely different than proxies...

March 27, 2009

Maven Repositories: define in POM or settings?

If you are using Maven for more than just playing, you certainly have a repository Manager installed to both proxy artifacts downloaded from public repositories, and host your own artifacts to make them available to other team members and teams. (If you really really don't have one yet, consider using Nexus, an open source Maven repository manager created by Sonatype.)

Well, so you use a repository manager. Now, you need to tell Maven to use it to download all the missing artifacts. Moreover, as an organization, you usually want to control where the artifacts are downloaded from. This means you need to make sure that all developers are using the identical set of repositories for all the projects.

There are two placed you could use to configure your repositories: in the project's POM, or in the <settings> element on the settings.xml file. This post will discuss both ways and tell you which one you should use ;-)

The POM


The "innocent way" is to add a definition like this to your POM:

<repositories>
<repository>
<id>internal</id>
<name>Company internal repo</name>
<url>http://your.company.org/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
Maven uses all declared repositories to find missing artifacts. If it can't find what it's looking for, Maven will also fall back to the repository central which is defined in the built-in parent POM. However, this is usually not what you want; instead, all artifacts should be proxied by your repository manager.

This can be prevented by "overloading" the central repository with your own repository manager, i.e. you just add a definition with <id>central</id>.

When using a central repository manager, the definition of repositories should be the same for all your projects. This is usually done by putting this stuff to a company's base POM. But... if someone is starting in a clean environment, Maven will have to know where the repository is to find the project's parent POM, where it will find where the repository is... you're stuck.

Moreover, any POM that is included by transitive dependencies may specifiy additional repositories which are not redirected like the central repo. These external repositories are used by Maven to find all dependencies, even your internal ones that for sure are not hosted there; and you still do not really control where the artifacts are coming from.

Hence, using POM to define your repositories does not really solve any problem. Just don't do that!

The Settings


So, we end up with the alternative and recommended way of defining your repositories: the settings.

To really make sure that all developers and all projects are using the identical set of repositories, you should use mirrors to tell Maven to redirect all artifact requests to your internal repository manager.

Both the mirror and repository settings can be defined in the settings.xml file. I think I will do another post to explain what a good setup would look like...

There are two locations for settings.xml file:

  1. the Maven installation at $M2_HOME/conf/settings.xml
  2. the user's local settings: ${user.home}/.m2/settings.xml
Both can contain the same set of definitions. So, which one to use?

Actually, both locations require the Maven user (your team members) to manually do some configuration in their setting file. This is general not preferred for the known reasons: everybody needs to do this manually, no automatic update if settings change later on, unexpected behaviour when someone forgets to adopt his/her file etc.

The only way to avoid these drawbacks is to avoid all manual editing work, i.e. provide a central version of the settings file that is checked in to your sourcecode management system (SCM). This can't be done for the second option (user's settings) but it can be done for the first (installation settings) – if you put Maven installation under source control.

This sounds a bit strange at first (after all, it's an executable!) but is really clever IMO, for the following reasons:

  • You make sure everybody uses the same version of Maven; no more Maven version dependencies!
  • You can use a relative path from your projects to the Maven installation if they are part of the same source repository, for instance in batch files, Eclipse launch configurations etc.
  • The correct settings are applied automatically and may be updated in the repository without requiring any editing by the developers (except for updating).
  • Maven installation is only around 2 MB of size, which is not really an issue for any SCM.


The Bottom Line


To summarize, by putting your Maven installation in your SCM as part of your project environment, and using central settings to configure Maven to use your repository manager, you reduce dependency to local environment. And stabilizing your builds is always a good thing!