Prerequisites
Basic Concepts
For the below examples, a Maven <command> will typically be of the form mvn clean package install where mvn is the command being run, and clean/package/install/etc are phases of the Maven project you're building.
Maven includes several predefined phases to cover the default lifecycle:
- clean - clears out old build artifacts
- test - run the Maven surefire plugin to execute your tests and display the result (i.e. JUnit, TestNG, etc)
- package - download dependencies (if necessary) and build up new artifacts into the target/ folder
- install - installs built artifacts (assumes package) from your target/ folder into your local .m2 Maven repository, allowing local Maven projects to consume the built artifacts
- install-file - install a JAR file manually to your .m2 repo, allowing local Maven project to consume the JAR
- deploy - publish built artifacts (assumes package) to a remote Maven repository, allowing local Maven projects to consume the built artifacts
- deploy-file - publish a standalone JAR file manually to a remote Maven repository, allowing other remote Maven projects to consume the JAR
For a full list of these lifecycle goals: https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference
How it Works
Every Maven project contains a file called pom.xml at the project root. This file is the POM or Project Object Model, which tells Maven everything it needs to know about the project's dependencies and build steps.
Running a Maven command will parse the current project's POM to determine available phases/goals, and execute them according to the details defined within.
The pom.xml can also link off to various other XML documents describing various pluggable aspects of the build process:
- build.xml: if you're using the Maven Antrun Plugin, this file tells Ant how to execute
- assembly.xml: If you're using the Maven Assembly Plugin, this file tells Maven how to package your application (JAR, WAR, ZIP, etc)
Nested Projects
POMs can also exist in subfolders of the root. Every subproject's POM inherits the values defined by the parent, creating a nested hierarchy.
Values in subprojects will override values in the parent project, so we must first compute an "effective POM" by walking down the POM tree from root project to our target subproject and collect all values encountered.
Usage
Now that you've heard the basics, let's try it out!
Via Maven
The following command will run Maven's clean and install phases natively:
$ mvn clean install
This is a very common command to build a Maven project from source, and install its built artifacts into your .m2 cache for local consumption.
Via Docker
The following command will run the same phases within a Docker container, without needing to install Maven on your machine:
$ docker run -it --rm -v $(pwd):/build -w /build maven:3-jdk-8 mvn clean install
Publishing Artifacts (Advanced)
To easily run your own test Nexus repository via Docker (untested):
$ docker run -d -p 8081:8081 --name nexus sonatype/nexus:oss
Open-Source Software Repository Hosting (OSSRH)
See http://central.sonatype.org/pages/ossrh-guide.html
For a more long-term solution for hosting your (open-source) Maven artifacts, you can follow these steps to deploy them to OSSRH.
Working with GPG Keys
See http://central.sonatype.org/pages/working-with-pgp-signatures.html
Generate a Keypair
You will need the gnupg command line tool (on OSX, this can be installed via brew):
$ gpg --gen-key
Upload to Keyserver
Once you have generated a keypair, you will need to upload your public key to a public keyserver.
To list existing keys:
$ gpg --list-keys /Users/<USERNAME>/.gnupg/pubring.kbx ---------------------------------- pub rsa2048 2017-05-05 [SC] [expires: 2019-05-05] <YOUR_KEY_ID_WHICH_WILL_BE_FAIRLY_LONG> uid [ultimate] Craig Willis (https://github.com/craig-willis) <willis8@illinois.edu> uid [ultimate] Garrick Sherman (https://github.com/gtsherman) <gsherma2@illinois.edu> uid [ultimate] Mike Lambert (https://github.com/bodom0015) <lambert8@illinois.edu> sub rsa2048 2017-05-05 [E] [expires: 2019-05-05]
Then execute the following command to upload your public key:
$ gpg --keyserver hkp://pool.sks-keyservers.net --send-keys <YOUR_KEY_ID_WHICH_WILL_BE_FAIRLY_LONG>
where <YOUR_KEY_ID_WHICH_WILL_BE_FAIRLY_LONG> is pulled from the output above
Signing a Single File
To sign a file with your GPG key:
$ gpg -ab ir-utils-0.1.0.jar
NOTE: You will be asked to enter your GPG key's passphrase
This will output a .asc file that should be included with the file that produced it.
Verifying GPG Signatures
As a consumer, you can verify the authenticity of the Maven artifacts by using the gpg command line tool:
$ gpg --verify target/ir-utils-0.1.0.jar.asc gpg: assuming signed data in 'target/ir-utils-0.1.0.jar' gpg: Signature made Thu Jun 1 21:21:16 2017 CDT gpg: using RSA key <YOUR_KEY_ID_WHICH_WILL_BE_FAIRLY_LONG> gpg: Good signature from "Craig Willis (https://github.com/craig-willis) <willis8@illinois.edu>" [ultimate] gpg: aka "Garrick Sherman (https://github.com/gtsherman) <gsherma2@illinois.edu>" [ultimate] gpg: aka "Mike Lambert (https://github.com/bodom0015) <lambert8@illinois.edu>" [ultimate]
This will output the signature data from the .asc file, which should give you some confidence that the artifacts were not modified or replaced by a malicious party.
Third-Party Dependencies
To publish a single SNAPSHOT artifact to a repository:
$ mvn deploy:deploy-file -Dfile=./indri-5.11.jar -DgroupId=edu.illinois.lis -DartifactId=indri -Dversion=5.11-SNAPSHOT -Dpackaging=jar -Durl=https://oss.sonatype.org/content/repositories/snapshots/ -DrepositoryId=ossrh
For staging a new release:
$ mvn deploy:deploy-file -Dfile=./indri-5.11.jar -DgroupId=edu.illinois.lis -DartifactId=indri -Dversion=5.11 -Dpackaging=jar -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2 -DrepositoryId=ossrh
NOTE: If you attempt to deploy a SNAPSHOT to staging, or a non-SNAPSHOT to snapshots, the command will fail.
Staging a New Release
Syncing to Maven Central
See http://central.sonatype.org/pages/requirements.html
OSSRH will sync your released artifacts with Maven Central on your behalf, but still has a strict list of requirements for artifacts synced to Maven Central.
In general, the requirements are as follows:
- Final bundle.jar must include:
- Project POM (i.e. pom.xml)
- Compiled JAR (i.e. ir-utils-0.1.0.jar)
- JavaDoc JAR (i.e. ir-utils-0.1.0-javadoc.jar)
- Sources JAR (i.e. ir-utils-0.1.0-sources.jar)
- GPG signatures for all of the above (i.e. ir-utils-0.1.0.jar.asc, ir-utils-0.1.0-javadoc.jar.asc, etc)
- Final pom.xml must include:
- Project coordinates: groupId / artifactId / version
- Project name and description
- License information
- Developer information
- SCM information
- Final pom.xml must NOT include:
- <repositories> tags
- <pluginRepositories> tags