...
Sometimes, your dependency might not be hosted publically publicly or may be unavailable for download.
...
Code Block | ||
---|---|---|
| ||
$ mvn clean package gpg:sign install:install deploy:deploy |
This single command will:
...
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 | ||
---|---|---|
| ||
$ mvn clean package verify | ||
Code Block | ||
| ||
$ mvn clean package gpg:sign install:install deploy:deploy
$ cd target/ |
...
Code Block | ||
---|---|---|
| ||
$ 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 | ||
---|---|---|
| ||
<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 | ||
---|---|---|
| ||
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:
...
- 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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
<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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
<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:
- First and foremost, ask for the developers' permission to publish their code, consult the license, etc
- DO NOT publish another developer's code without their permission!
- Locate the source code (if possible)
If found, generate a JAR containing the source code (don't forget to include the LICENSE, if necessary):
Code Block language bash 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 language bash 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 language bash <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 language bash 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 language bash 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
Bundle everything up and upload this bundle to the Staging repo in the same way as described above:
Code Block language bash 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 | ||
---|---|---|
| ||
<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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
jar -cvf indri-5.11-bundle.jar *.jar *.pom *.asc |
...