Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Sometimes, your dependency might not be hosted publically publicly or may be unavailable for download.

...

After that, any future releases that you promote from the staging repository will be automatically synced to Central (within a few hours).

Generating JavaDoc via Maven

Add the following to your pom.xml to generate a *-javadoc.jar alongside each JAR that is output during the package phase of your build:

Code Block
languagebash
        <build>
          <plugins>
            <!-- More plugins... -->         
           
			<!-- Maven JavaDoc Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-javadoc-plugin</artifactId>
				<version>2.10.4</version>
				<configuration>
					<show>private</show>
					<nohelp>true</nohelp>
				</configuration>
				<executions>
					<execution>
						<id>attach-javadocs</id>
						<phase>package</phase>
						<goals>
							<goal>jar</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

            <!-- More plugins... -->

          </plugins>
        </build>

Generating Sources via Maven

Add the following to your pom.xml to generate a *-sources.jar alongside each JAR that is output during the package phase of your build:

Code Block
languagebash
        <build>
          <plugins>
            <!-- More plugins... -->


			<!-- Maven Sources Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<version>3.0.1</version>
				<executions>
					<execution>
						<id>attach-sources</id>
						<phase>package</phase>
						<goals>
							<goal>jar</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
            <!-- More plugins... -->

          </plugins>
        </build>

Signing Your Artifacts via Maven

See http://central.sonatype.org/pages/working-with-pgp-signatures.html 

...

Code Block
languagebash
export GPG_TTY=$(tty)

Generate and Upload a Keypair

From Maven's own uploading guide:

Panel
titlePGP Signature

To improve the quality of the Central Maven repository, we require you to provide PGP signatures for all your artifacts (all files except checksums), and distribute your public key to a key server like http://pgp.mit.edu. Read Working with PGP Signatures for more information.


If you don't already have one, you will need to generate a GPG key keypair with which you can sign your artifacts.

You will need the gnupg command line tool (on OSX, this can be installed via brew):

Code Block
languagebash
$ gpg --gen-key

...


Once you have generated a keypair, you will need to upload your public key to a public keyserver.

...

NOTE: You may need to share this public key with other keyservers, if your artifacts fail the Central Sync Checks for GPG signing due to a missing key

Manually Signing a Single File

To sign a file with your GPG key:

...

This will output a .asc file that should be included alongside the file that produced the signature.

...

As a consumer, you can then verify the authenticity of the Maven artifacts by using the gpg command line tool:

...

Code Block
languagebash
$ mvn clean package gpg:sign install:install deploy:deploydeploy

This This single command will:

  • Clear out your existing build artifacts
  • Compile and package up your code into a JAR
  • Generate JavaDoc from your project and package it as a JAR
  • Package up your source code as a JAR
  • Sign the JAR and POM files with your GPG key
  • Install the resulting artifacts into your local Maven cache
  • Deploy the resulting artifacts into the remote Nexus repository

...

At some point, you will likely want to assemble a release (non-SNAPSHOT) version of the code that people can be confident will not change out from under them suddenly. This is where releases come in - since they are unique and permanent, users can consume released artifacts confidently without fear of them changing in the future. without warning.

Bundle Your Artifacts

First, perform a full build of your project using the big command from above and the cd to where the build artifacts were output:

Automatically

There is a way to automate this process using the Maven Release Plugin (see below), but I did not fully explore the capabilities of this plugin, as the steps were easy enough to perform manually once I figured out the process.

Manually

Without the Maven Release Plugin, it is still fairly easy to upload your artifacts to the staging server using the steps below.

Bundle Your Artifacts

First, make sure your version string does not end with -SNAPSHOT, then perform a full build of your project using the big command from above and the cd to where the build artifacts were output:

Code Block
languagebash
$ mvn clean package verify
Code Block
languagebash
$ mvn clean package gpg:sign install:install deploy:deploy 
$ cd target/

...

Code Block
languagebash
$ jar cvf bundle.jar *.pom *.jar *.asc

Upload Your Artifact Bundle

Then log into https://oss.sonatype.org/ with your JIRA username / password and choose "Staging Upload" on the left side.

...

Testing a Closed Repository

<placeholder for how to access / test staged artifacts, a note about unit tests / CI, etc>

Release the Bundle

<placeholder for what "Promote" is/means/does>

<placeholder for what happens upon "Release">

Potential Plugins of interest

Insert snippets about:

  • Maven Bundle Plugin, which supposedly helps to automate the process of creating a bundle.jar for upload
  • Maven Release Plugin or Nexus Staging Maven Plugin, which supposedly helps to automate the process of uploading, closing, and promoting uploaded bundles

On the Nexus UI, click "Repositories" on the left side and from the small dropdown in the top-center of the screen, choose "Nexus Managed Repositories"

This will update the list to be quite lengthy. Locate your repository (which should be named after your project's groupId).

Closed repositories should be listed here with a URL in the right-most column, and will likely contain the name of the repository (i.e. eduillinoislis-1007).

Copy this url to a <repositories> section of your downstream POM (remember to remove this section after you finish testing)For example:

Code Block
languagebash
	  <repositories>
  <build>
		  <plugins><repository>
      <releases>
       <!-- More plugins... <enabled>true</enabled>
      </releases>
      <id>ossrh1</id> <!-- This does not need to match the <id> in your settings.xml -->

			<!-- Maven Release Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-release-plugin</artifactId>
				<version>2.5.3</version>
				<configuration>
					<mavenExecutorId>forked-path</mavenExecutorId>
					<useReleaseProfile>false</useReleaseProfile>
					<arguments>-Psonatype-oss-release</arguments>
				</configuration>
			</plugin>

      <name>OSSRH Staging for indri-5.11 release</name>
      <url>https://oss.sonatype.org/content/repositories/eduillinoislis-1007/</url>
      <layout>default</layout>
    </repository>
  </repositories>

You should then be able to build your downstream project using the staged artifacts you specified here! Running "mvn clean package", you should see something similar to the following:

Code Block
languagebash
Michaels-- More plugins... -->


          </plugins>
        </build>

Third-Party Dependencies

What do you do if one of your dependencies has not been uploaded to The Central Repository? All is not lost!

You could reach out to them to see if they are willing to perform the steps necessary to publish them, but it's unlikely that they will be open to this idea if it was not already in their plans, or if they don't use Maven at all..

If the project is open-source and accepts contributions, you could contribute a modified pom.xml allowing them to publish their artifacts to OSSRH or similar.

If you can obtain permission from the developers, they may allow you to publish it on their behalf:

...

  1. DO NOT publish another developer's code without their permission!

...

If found, generate a JAR containing the source code (don't forget to include the LICENSE, if necessary):

Code Block
languagebash
jar -cvf indri-5.11-sources.jar *

...

If found, generate JavaDoc HTML from the source code and bundle it into a separate JAR (don't forget to include the LICENSE, if necessary):

Code Block
languagebash
mkdir -p ./target/javadoc
javadoc -d ./target/javadoc lemurproject.indri
cd target/javadoc
jar -cvf indri-5.11-javadoc.jar *

NOTE: Scala projects can supposedly skip this step

...

Locate compiled binaries (you can choose to download them, or build them yourself if you are able)

Author a simple POM for this dependency. Below is an example POM.xml that might be used for edu.illinois.lis.indri:

Code Block
languagebash
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>edu.illinois.lis</groupId>
    <artifactId>indri</artifactId>
    <version>5.11</version>

    <name>Indri 5.11</name>
    <description>Indri is a text search engine developed at UMass. It is a part of the Lemur project.</description>
    <url>https://sourceforge.net/projects/lemur/</url>

    <licenses>
      <!-- Indri actually uses BSD-old / "original BSD", but its link is no longer available via opensource.org.
             This is likely due to the controversy surrounding the 4th clause -->
      <license>
        <name>BSD-3-Clause</name>
        <url>https://opensource.org/licenses/BSD-3-Clause</url>
      </license>
    </licenses>

    <scm>
      <connection>scm:svn:https://svn.code.sf.net/p/lemur/code/ lemur-code</connection>
      <developerConnection>scm:svn:https://svn.code.sf.net/p/lemur/code/ lemur-code</developConnection>
      <url>scm:svn:https://sourceforge.net/p/lemur/code/HEAD/tree/indri/tags/release-5.11/</url>
    </scm>

    <developers>
      <developer>
        <name>David Fisher</name>
        <email>dfisher@cs.umass.edu</email>
        <organization>University of Massachusetts at Amherst</organization>
        <organizationUrl>http://www.umass.edu/</organizationUrl>
      </developer>

      <developer>
        <name>Stephen Harding</name>
        <email>harding@hobart.cs.umass.edu</email>
        <organization>University of Massachusetts at Amherst</organization>
        <organizationUrl>http://www.umass.edu/</organizationUrl>
      </developer>

      <developer>
        <name>Cameron VandenBerg</name>
        <email>cmw2@andrew.cmu.edu</email>
        <organization>Carnegie Mellon University</organization>
        <organizationUrl>http://www.cmu.edu/</organizationUrl>
      </developer>
    </developers>
</project>

Sign all artifacts with your GPG key (*.pom, *.jar, *-sources.jar, *-javadoc.jar):

Code Block
languagebash
gpg -ab indri-5.11.pom
gpg -ab indri-5.11.jar
gpg -ab indri-5.11-sources.jar
gpg -ab indri-5.11-javadoc.jar

This will produce a .asc file for each artifact

Code Block
languagebash
lambert8:5.11 lambert8$ ls -al
total 65168
drwxr-xr-x  14 lambert8  staff       476 Jun  2 16:50 .
drwxr-xr-x   5 lambert8  staff       170 Jun  2 15:48 ..
-rw-r--r--   1 lambert8  staff     93941 Jun  2 15:18 indri-5.11-javadoc.jar
-rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11-javadoc.jar.asc
-rw-r--r--   1 lambert8  staff  16384085 Jun  2 15:41 indri-5.11-sources.jar
-rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11-sources.jar.asc
-rw-r--r--   1 lambert8  staff    259518 May 22 10:54 indri-5.11.jar
-rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11.jar.asc
-rw-r--r--   1 lambert8  staff      2035 Jun  2 16:49 indri-5.11.pom
-rw-r--r--   1 lambert8  staff       488 Jun  2 16:49 indri-5.11.pom.asc
MacBook-Pro-2:ir-tools lambert8$ mvn clean package
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Building IR Utils 0.1.0
[INFO] ------------------------------------------------------------------------
Downloading: https://oss.sonatype.org/content/repositories/eduillinoislis-1007/edu/illinois/lis/indri/5.11/indri-5.11.pom
Downloaded: https://oss.sonatype.org/content/repositories/eduillinoislis-1007/edu/illinois/lis/indri/5.11/indri-5.11.pom (2.1 kB at 1.5 kB/s)
Downloading: https://oss.sonatype.org/content/repositories/eduillinoislis-1007/edu/illinois/lis/indri/5.11/indri-5.11.jar
Downloaded: https://oss.sonatype.org/content/repositories/eduillinoislis-1007/edu/illinois/lis/indri/5.11/indri-5.11.jar (260 kB at 789 kB/s)
                   ...


[INFO] --- maven-dependency-plugin:2.8:copy-dependencies (default) @ ir-utils ---
                   ...
[INFO] Copying indri-5.11.jar to /Users/lambert8/workspace/ir-tools/target/lib/indri-5.11.jar
                   ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 21.890 s
[INFO] Finished at: 2017-06-03T16:24:25-05:00
[INFO] Final Memory: 59M/746M
[INFO] ------------------------------------------------------------------------

And just like that you've built your downstream project against your staged upstream artifacts! These downstream artifacts can now be used to verify the correctness of your upstream artifacts before releasing them to the public! Typically, your Maven build would also run unit and/or integration tests against the code as well to verify that everything is working properly.

Release the Bundle

Now that your repository is closed and you've tested your artifacts (and you did test your artifacts, didn't you?), you have the option to Release, Promote, or Drop the repository

Release

Choosing Release will finalize the artifacts and release them for public consumption on OSSRH. Choose this when the artifacts are ready to be deployed to concrete version.

NOTE: Make sure your artifacts are ready, as once they are released they are extremely difficult to remove, if not impossible.

Drop

Choosing Drop will remove this staging repository and delete the artifacts within. Choose this if a problem is found during testing and the artifacts need to be re-staged. 

Promote

In more complex setups, choosing Promote will supposedly "promote" your artifacts to a "Build Profile", enqueueing them for some larger build process before release. This option was unavailable to me, so I may be misinterpreting its use.

Enabling Maven Central Sync

If you've made it this far, then your artifacts are ready to be synchronized to Maven Central.

Don't forget to comment back on your OSSRH to enable Maven Central sync for your project's groupId.

NOTE: You will only need to perform this once per groupId, not per project

Potential Plugins of interest

Some plugins that might be worth looking into:

  • Maven Bundle Plugin, which supposedly helps to automate the process of creating a bundle.jar for upload
  • Maven Release Plugin or Nexus Staging Maven Plugin, which supposedly helps to automate the process of uploading, closing, and promoting uploaded bundles

For example:

Code Block
languagebash
	    <build>
		  <plugins>
            <!-- More plugins... -->

			<!-- Maven Release Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-release-plugin</artifactId>
				<version>2.5.3</version>
				<configuration>
					<mavenExecutorId>forked-path</mavenExecutorId>
					<useReleaseProfile>false</useReleaseProfile>
					<arguments>-Psonatype-oss-release</arguments>
				</configuration>
			</plugin>


            <!-- More plugins... -->


          </plugins>
        </build>


Third-Party Dependencies

What do you do if one of your dependencies has not been uploaded to The Central Repository? All is not lost!

You could reach out to them to see if they are willing to perform the steps necessary to publish them, but it's unlikely that they will be open to this idea if it was not already in their plans, or if they don't use Maven at all..

If the project is open-source and accepts contributions, you could contribute a modified pom.xml allowing them to publish their artifacts to OSSRH or similar.

If you can obtain permission from the developers, they may allow you to publish it on their behalf:

  1. First and foremost, ask for the developers' permission to publish their code, consult the license, etc
    1. DO NOT publish another developer's code without their permission!
  2. Locate the source code (if possible)
    1. If found, generate a JAR containing the source code (don't forget to include the LICENSE, if necessary):

      Code Block
      languagebash
      jar -cvf indri-5.11-sources.jar *


    2. If found, generate JavaDoc HTML from the source code and bundle it into a separate JAR (don't forget to include the LICENSE, if necessary):

      Code Block
      languagebash
      mkdir -p ./target/javadoc
      javadoc -d ./target/javadoc lemurproject.indri
      cd target/javadoc
      jar -cvf indri-5.11-javadoc.jar *

      NOTE: Scala projects can supposedly skip this step

  3. Locate compiled binaries (you can choose to download them, or build them yourself if you are able)

  4. Author a simple POM for this dependency. Below is an example POM.xml that might be used for edu.illinois.lis.indri:

    Code Block
    languagebash
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>edu.illinois.lis</groupId>
        <artifactId>indri</artifactId>
        <version>5.11</version>
    
        <name>Indri 5.11</name>
        <description>Indri is a text search engine developed at UMass. It is a part of the Lemur project.</description>
        <url>https://sourceforge.net/projects/lemur/</url>
    
        <licenses>
          <!-- Indri actually uses BSD-old / "original BSD", but its link is no longer available via opensource.org.
                 This is likely due to the controversy surrounding the 4th clause -->
          <license>
            <name>BSD-3-Clause</name>
            <url>https://opensource.org/licenses/BSD-3-Clause</url>
          </license>
        </licenses>
    
        <scm>
          <connection>scm:svn:https://svn.code.sf.net/p/lemur/code/ lemur-code</connection>
          <developerConnection>scm:svn:https://svn.code.sf.net/p/lemur/code/ lemur-code</developConnection>
          <url>scm:svn:https://sourceforge.net/p/lemur/code/HEAD/tree/indri/tags/release-5.11/</url>
        </scm>
    
        <developers>
          <developer>
            <name>David Fisher</name>
            <email>dfisher@cs.umass.edu</email>
            <organization>University of Massachusetts at Amherst</organization>
            <organizationUrl>http://www.umass.edu/</organizationUrl>
          </developer>
    
          <developer>
            <name>Stephen Harding</name>
            <email>harding@hobart.cs.umass.edu</email>
            <organization>University of Massachusetts at Amherst</organization>
            <organizationUrl>http://www.umass.edu/</organizationUrl>
          </developer>
    
          <developer>
            <name>Cameron VandenBerg</name>
            <email>cmw2@andrew.cmu.edu</email>
            <organization>Carnegie Mellon University</organization>
            <organizationUrl>http://www.cmu.edu/</organizationUrl>
          </developer>
        </developers>
    </project>



  5. Sign all artifacts with your GPG key (*.pom, *.jar, *-sources.jar, *-javadoc.jar):

    Code Block
    languagebash
    gpg -ab indri-5.11.pom
    gpg -ab indri-5.11.jar
    gpg -ab indri-5.11-sources.jar
    gpg -ab indri-5.11-javadoc.jar


    1. This will produce a *.asc file for each artifact

      Code Block
      languagebash
      lambert8:5.11 lambert8$ ls -al
      total 65168
      drwxr-xr-x  14 lambert8  staff       476 Jun  2 16:50 .
      drwxr-xr-x   5 lambert8  staff       170 Jun  2 15:48 ..
      -rw-r--r--   1 lambert8  staff     93941 Jun  2 15:18 indri-5.11-javadoc.jar
      -rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11-javadoc.jar.asc
      -rw-r--r--   1 lambert8  staff  16384085 Jun  2 15:41 indri-5.11-sources.jar
      -rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11-sources.jar.asc
      -rw-r--r--   1 lambert8  staff    259518 May 22 10:54 indri-5.11.jar
      -rw-r--r--   1 lambert8  staff       488 Jun  2 15:42 indri-5.11.jar.asc
      -rw-r--r--   1 lambert8  staff      2035 Jun  2 16:49 indri-5.11.pom
      -rw-r--r--   1 lambert8  staff       488 Jun  2 16:49 indri-5.11.pom.asc


  6. Bundle everything up and upload this bundle to the Staging repo in the same way as described above:

    Code Block
    languagebash
    jar -cvf indri-5.11-bundle.jar *.jar *.pom *.asc


TL;DR

Do the one-time steps:

  • Generate or import a PGP key
  • Upload your key to the keyserver
  • Create an account on OSSRH JIRA
  • Create New Project ticket

Add this to your pom.xml:

Code Block
languagebash
        <build>
          <plugins>
            <!-- More plugins... -->

            <!-- Maven GPG Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-gpg-plugin</artifactId>
				<version>1.6</version>
				<executions>
					<execution>
						<id>sign-artifacts</id>
						<phase>verify</phase>
						<goals>
							<goal>sign</goal>
						</goals>
					</execution>
				</executions>
			</plugin>


			<!-- Maven JavaDoc Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-javadoc-plugin</artifactId>
				<version>2.10.4</version>
				<configuration>
					<show>private</show>
					<nohelp>true</nohelp>
				</configuration>
				<executions>
					<execution>
						<id>attach-javadocs</id>
						<phase>package</phase>
						<goals>
							<goal>jar</goal>
						</goals>
					</execution>
				</executions>
			</plugin>


			<!-- Maven Sources Plugin -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<version>3.0.1</version>
				<executions>
					<execution>
						<id>attach-sources</id>
						<phase>package</phase>
						<goals>
							<goal>jar</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

            <!-- More plugins... -->
          </plugins>
        </build>

Execute this:

Code Block
languagebash
export GPG_TTY=$(tty)
mvn clean deploy

If all goes well, you should be prompted to enter the passphrase for your PGP key, and your artifacts should be deployed!

Common Problems

  • ioctl failed to allocate tty
    • Execute export GPG_TTY=$(tty) before executing
  • *.asc.asc files in target/ folder
    • GPG plugin is executing twice, double-check your POM settings against the command executed
    • NOTE: It is unnecessary to explicitly specify the gpg:sign or verify goals
  • HTTP 400
    • You are deploying a SNAPSHOT to a release repo, or vice versa

Bundle everything up and upload this bundle to the Staging repo in the same way as described above:

Code Block
languagebash
jar -cvf indri-5.11-bundle.jar *.jar *.pom *.asc

...