Monthly Archives: December 2014

Publish Maven bits to Maven Central using the Standard Deploy Plugin (2)

In the first post of this series, we discussed how to publish Maven bits to Maven Central using the standard Maven deploy plugin. This is an eight step process to set up and execute, and we discussed the first two steps in the previous post of this series.

We will discuss the five of the remaining steps in this post, and I will create another post with particular focus on how to do the code signing with GnuPG in an automated multi-module Maven build.

Step 3: Request an account in Sonatype JIRA and create a ticket to set up a Nexus repository

The process of how to request an account and have a Nexus staging repository set up is described in the OSSRH guide. The staging repository is restricted to a specific group ID. If you maintain multiple projects and eventually want to publish all of them, request a top-level group ID in the ticket.

As an example, if you own the domain “domain.com” and you have two projects with the planned group IDs “com.domain.project1” and “com.domain.project2”, request the repository to being set up for “com.domain”, even if the concrete request is for the project with the group ID “com.domain.project1”.

Step 4: Add the OSSRH repository to the distribution management section in the POM

I do not publish SNAPSHOT builds in my project, but Sonatype generally supports them. They are located in a different repository though.

Configure the distribution management section to deploy the bits automatically into the staging repository on Sonatype using the standard Maven deploy plugin:

<distributionManagement>
  <!--
  uncomment this section if you want to deploy SNAPSHOT builds
  <snapshotRepository>
    <id>ossrh</id>
    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
  </snapshotRepository>
  -->
  <repository>
    <id>ossrh</id>
    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
  </repository>
</distributionManagement>

See the “util” project parent POM and related source file here for an example.

Step 5: Add your credentials for OSSRH to the “settings.xml” file in your home directory

The Maven deploy plugin will need the Sonatype jira credentials to submit the bits to the staging repository. It is really not very secure to use the primary credentials directly here, but unfortunately Sonatype does not support using a tokenized form of the credentials at this point.

<settings>
  ...
  <servers>
    ...
    <server>
      <id>ossrh</id>
      <username>jira-username</username>
      <password>jira-password</password>
    </server>
    ...
  </servers>
  ...
</settings>

Be sure to always use the same ID whenever referring to the OSSRH repository: The ID used in the repository ID of the “distribution management” section of the POM must match the ID used in the settings’ server section.

Edit: continue reading…

Publish Maven bits to Maven Central using the Standard Deploy Plugin (1)

There are several automated options to publish artifacts that have been created in a Maven build to a Maven repository. The deploy process may depend somewhat on the repository being used. For example, if a project is not hosted by one of the big players, it might be necessary to deploy through a “proxy” mechanism that eventually forwards the artifacts to Maven Central, rather than deploying there directly.

One of these proxy services is provided by Sonatype as their “OSS Repository Hosting” or “OSSRH” service. The OSSRH service provided by Sonatype is free, and allows staging of one’s artifacts and then promoting them to Maven Central.

Sonatype provides detailed instructions on how to use the service, heavily promoting their “Nexus Staging Maven Plugin” for Maven based builds in combination with the Maven Release plugin. While there is nothing wrong with using these plugins, I find it hard to integrate into enterprise builds where the build process is a little more formalized and a well-defined branching and tagging process should be obeyed.

Following the eight steps outlined below, projects can be deployed to Maven Central using the standard Maven deploy process. The client side (i.e. the Maven build, tagging, branching, etc) can still be easily automated by employing a build system such as Jenkins, giving the build engineer tight control over how the build is performed. However, once the artifacts have been deployed, it is still necessary to “promote” them from the OSSRH Staging Area to Maven Central. While this step can be fully automated when using the Nexus Staging and the Maven Release plugins as recommended by Sonatype, I do not mind this last manual step and find it useful to be able to review the staged artifacts before they are published to Maven – in particular as releases are not that frequent. On the other hand, if a project uses OSSRH to also publish SNAPSHOT artifacts, which are commonly released with a much higher frequency than regular releases, it might be prudent to either follow a hybrid approach (using the staging plugin for SNAPSHOTS, and the regular Maven process for other releases), or to adopt a project workflow that fits in the boundaries defined by the Nexus Staging Maven Plugin.

The examples below are based on a utility library that I published through this process and commonly use as a Maven dependency. This particular project is a multi-module Maven build.

Step 1: Create a GnuPG key pair, and publish the public key

Sonatype has an excellent guide on how to generate and manage keys with GnuPG. They are very clear about the requirement that the key used to sign the artifacts cannot be a subkey. This is not very desirable from a security and key management perspective, but unfortunately necessary due to limitations of Maven and Nexus, which can only verify signatures against a primary key.

Step 2: Set up the Maven build so that it meets the OSSRH requirements

Like for the key management guide with GnuPG, Sonatype has published very detailed instructions on the requirements a project must meet so that it can be published to Maven Central through Sonatype’s OSSRH.

I noticed a few things than merit additional clarification in addition to what is mentioned in Sonatype’s guide:

  • The build must produce a source and a Javadoc package in addition to the artifact. This is tricky in case a project is a mere resource project, that is, a container for resource files. In this case, it will usually not contain Javadocs. However, as Sonatype requires Javadocs to be present, it is possible to satisfy this requirement by creating a “fake” Javadocs file. This can be done by creating a src/main/javadoc directory and adding a README.txt file. The fake Javadoc can then be included by adding the plugin below. See the “build-tools” project POM and related source file here for an example.
    <build>
      ...
      <plugins>
      ...
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <executions>
            <execution>
              <id>empty-javadoc-jar</id>
              <phase>package</phase>
              <goals>
                <goal>jar</goal>
              </goals>
              <configuration>
                <classifier>javadoc</classifier>
                <classesDirectory>${basedir}/src/main/javadoc</classesDirectory>
                <includes>
                  <include>**/*</include>
                </includes>
              </configuration>
            </execution>
          </executions>
        </plugin>
      ...
      </plugins>
      ...
    </build>
    
  • The group ID must be owned by the project. For example, a project cannot write to the google.com group ID unless it is authorized to do so. If necessary, reserve a group ID for the project when requesting access to OSSRH.
  • The parent POM of the project must contain a “developers” section, but that section does not necessarily have to contain an email address that is trivially machine readable. You may try to protect your email address against UBE, like in the example below.
        <developers>
        <developer>
          <name>Mike Beiter</name>
          <email>michael AT beiter.org</email>
          <url>https://www.michael.beiter.org</url>
        </developer>
      </developers>
    

Edit: continue reading…