Maven deployment via Ant

Post to Twitter

We are no Maven lovers, because it helps to forget how things work. But we think the dependency management is useful. It's great for developers who need specific library versions without managing them manually.

The user aspect is one thing, but nobody tells you that it's not trivial to release libraries. One problem is the pre-deployment process. Before you are able to deploy your jar files, you have to do a lot of things like GPG key generation, publishing GPG key, find the right repository, prepare your build, special pom cration and so on.

If you already have release builds with version numbers, javadoc and source archives, you'll save a lot of time. If you don't have complete and clean release builds - see you later.

Let's start with a good documentation about requirements:
https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide

Of course, it assumes that you'll use Sonatype as your repository, but all others are not too different.

This posting is not a complete documentation. It simply shows the problems we had.

Our simple pom files:
pom.xml (jvxall)
pom.xml (jvxclient)

The first is with dependencies and the second without, because our client doesn't have dependencies.

The real problems started with the integration in our ant script, because the documentation of Maven plugins were awful. It's easier to read the source code than to find out how plugins work. One example: Read following plugin documentation and tell me the valid values for "types" and "classifier". There are no examples on the page! Google around and copy/paste a little bit - awful!

Here's a working ant call

<typedef resource="org/apache/maven/artifact/ant/antlib.xml"
            uri="antlib:org.apache.maven.artifact.ant"
            classpath="${build}/maven/maven-ant-tasks-2.1.3.jar" />

<condition property="gpgexecutable"
     value="C:\Program Files\GNU\GnuPG\pub\gpg.exe" else="gpg">
    <and>
        <os family="Windows" />
   </and>
</condition>

<artifact:mvn>
    <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.4:sign-and-deploy-file" />
    <arg value="-Durl=${mvn.url}" />
    <arg value="-DrepositoryId=${mvn.id}" />
    <arg value="-DpomFile=${maven.tmp}/jvxall/pom.xml" />
    <arg value="-Dfile=${mvn.jvx.jar}" />
    <arg value="-Dfiles=${mvn.jvx.sources.jar},${mvn.jvx.javadoc.jar}" />
    <arg value="-Dclassifiers=sources,javadoc" />
    <arg value="-Dtypes=jar,jar" />
    <arg value="-Pgpg" />
    <arg value="-Dgpg.executable=${gpgexecutable}" />
</artifact:mvn>

Above call submits e.g. jvx-1.1.jar, jvx-1.1-javadoc.jar and jvx-1.1-sources.jar to the repository.

Why one call instead of 3 separate calls, as described in the documentation?

Short: It's better :)
Long: It's better to submit all dependent files in one "maven session". Above call creates a new maven project and if you call this command per file, there's no logical connection between them. If you plan to deploy snapshot releases - forget it - it doesn't work with different calls because every upload gets a new buildnumber. But all files need the same buildnumber! Such deployments can't be used. If you read the Sonatype document, you saw that "deploy" task didn't deploy javadoc and sources! The "stage" task did. I'm not sure, but I think they had the same problem with separate uploads! Trust me, above call works with snapshots and final releases.

Our naming conventions

<property name="mvn.jvx.jar" value="${release}/maven/${release.name}-${versionnumber}${maven.version.postfix}.jar" />
<property name="mvn.jvx.sources.jar" value="${release}/maven/${release.name}-${versionnumber}${maven.version.postfix}-sources.jar" />
<property name="mvn.jvx.javadoc.jar" value="${release}/maven/${release.name}-${versionnumber}${maven.version.postfix}-javadoc.jar" />

(${maven.version.postfix} is -SNAPSHOT for snapshot releases and empty for final releases)

Repository Id, URL

${mvn.id} = sonatype-nexus-staging
${mvn.url} = https://oss.sonatype.org/service/local/staging/deploy/maven2

Other problems?

Proxy settings for Maven, Use an external GPG key, Autentication.

If you copy the following settings.xml to <users.home>/.m2 and modify it to fit your needs, it should solve all problems:

<?xml version="1.0" encoding="UTF-8"?>

<settings>
  <servers>
    <server>
      <id>sonatype-nexus-snapshots</id>
      <username>username</username>
      <password>password</password>
    </server>
    <server>
      <id>sonatype-nexus-staging</id>
      <username>username</username>
      <password>password</password>
    </server>
  </servers>
  <profiles>
    <profile>
      <id>gpg</id>
      <properties>
        <gpg.passphrase>gpgkey</gpg.passphrase>
      </properties>
    </profile>
  </profiles>
  <proxies>
    <proxy>
      <id>firewall</id>
      <active>true</active>
      <protocol>http</protocol>
      <host>10.0.0.1</host>
      <port>3128</port>
      <username></username>
      <password></password>
      <nonProxyHosts>localhost,127.0.0.1</nonProxyHosts>
    </proxy>
    <proxy>
      <id>firewall-2</id>
      <active>true</active>
      <protocol>https</protocol>
      <host>10.0.0.1</host>
      <port>3128</port>
      <username></username>
      <password></password>
      <nonProxyHosts>localhost,127.0.0.1</nonProxyHosts>
    </proxy>
  </proxies>
</settings>

We configured the proxy via ant build.xml

<target name="proxy.check">
  <condition property="proxy.enabled">
    <and>
      <socket server="10.0.0.1" port="3128"/>
    </and>
  </condition>
</target>

<target name="proxy" depends="proxy.check" if="proxy.enabled">
  <property name="proxy.host" value="10.0.0.1"/>
  <property name="proxy.port" value="3128"/>
  <property name="proxy.user" value=""/>
  <property name="proxy.pass" value=""/>
   
  <setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"
            proxyuser="${proxy.user}" proxypassword="${proxy.password}"/>
</target>

Simply add "proxy" task as dependency of another task.

Maybe it's easier to release libraries with other build systems or maybe it works out-of-the-box with Maven itself, but the whole process is really bad.

Good luck!