How to Use Maven Profiles to Selectively Activate Plugins and Other Configuration from the Command Line
Vincent A. Cicirello
Posted on October 19, 2022
Apache Maven is the software project management and build tool that is preferred by many Java and Kotlin developers, as well as those developing for the JVM more generally. In this post, I explain how you can define profiles in your Maven pom.xml that you can selectively activate from the command line at the time of your build. There are a variety of reasons that you might use this feature. For example, perhaps you deploy build artifacts to different Maven repositories, each requiring different configuration. Or perhaps there is a plugin that you only wish to run during some (but not all) builds. Profiles can be used to accomplish both of these.
We'll use two examples. In the first, we'll use a profile to enable selectively activating the jacoco-maven-plugin to generate a code coverage report during the Maven test phase, but only if the profile was activated at the command line. In the second example, we'll use the case of deploying artifacts to both the Maven Central Repository as well as GitHub Packages.
Before jumping into specific examples, let's begin with an explanation of how to define profiles in your pom.xml. To do so, you will add a profiles section to your pom.xml with the following:
<profiles></profiles>
Within that profiles section, you then add one or more profiles. We're going to focus on profiles that are activated with command line options. To use that feature, we will need to give each of our profiles an id. The profile's id is what we'll use at the command line to activate it.
In the above, we have three profiles with the ids profileOne, profileTwo, and profileThree. To activate a profile from the command line at the time of your build, you use the command line option -P. For example, the following command activates profileTwo while executing the package lifecycle phase:
mvn package -PprofileTwo
The next couple sections of this post provide more specific examples of what you might use a profile for.
Profile to Enable (De)Activating a Plugin at Build Time
One of the ways that I sometimes use Maven profiles is if there is a plugin that I only want to use sometimes. Rather than configuring it in the usual <build></build> section of the pom.xml, you instead configure it within an additional <build></build> section within a profile. Here is a general example of what it will look like:
Above we see a profile named profileOne that includes version 1.2.3 of a plugin named example-plugin with a groupId of com.example. Any configuration required by that plugin would be inserted there as well. Note that our pom.xml will also have the usual <build></build> section elsewhere that we'd use to configure all of our other plugins.
One specific example where I regularly use a profile in this way is for configuring code coverage. In all of my Java projects, I use JaCoCo for generating code coverage reports. I use JaCoCo during the Maven test phase. However, while developing I find it useful at times to exclude coverage reporting to reduce the build time. But in my CI/CD workflows in GitHub Actions, I activate the code coverage profile during pull-requests and pushes to the default branch. For pull-requests, my GitHub Actions workflow comments the code coverage on the PR and uploads the coverage report as a workflow artifact, where I can inspect it as necessary. And during a push to the default branch, my workflow updates coverage badges to keep them up to date with the current state of the default branch. I can also activate the code coverage profile locally while developing, such as prior to submitting a pull-request, to ensure that I didn't miss testing something.
Here is a specific example from a library that I develop called Chips-n-Salsa where I have configured JaCoCo code coverage using a Maven profile in this way.
In the above example, JaCoCo is configured to generate a coverage report during the Maven test phase. But because I've put it within a profile (here named coverage), rather than in the regular <build></build> section, we need to activate the coverage profile from the command line at the time of the build, with the following:
mvn test-Pcoverage
Or, we can use mvn package or anything else that includes the test phase, with something like:
mvn package -Pcoverage
Profiles for Deploying to Multiple Maven Repositories
Are plugins the only thing that you can configure within a Maven profile? No, they are not. They are also highly useful if you regularly deploy artifacts to multiple Maven repositories. Here is an example:
<profiles><profile><id>profileOne</id><distributionManagement><repository><id>repo1</id><name>Name of Repo 1</name><url>https://example.com/url/of/repo1</url></repository></distributionManagement></profile><profile><id>profileTwo</id><distributionManagement><repository><id>repo2</id><name>Name of Repo 2</name><url>https://example.com/url/of/repo2</url></repository></distributionManagement></profile></profiles>
The above example defines two profiles, profileOne and profileTwo, for deploying artifacts to two different Maven repositories. The <distributionManagement> section of a pom.xml only allows specifying one <repository> (although you can also specify a <snapshotRepository>). Profiles offer a way to configure more than one, such that we activate at most one from the command line during deployment.
With the above example, if we want to deploy to repo1, we use:
mvn deploy -PprofileOne
And if we want to deploy to repo2, we use:
mvn deploy -PprofileTwo
Let's look at a real example, again from Chips-n-Salsa, where I publish artifacts of the library on both Maven Central as well as to GitHub Packages. We'll build up to the full example. First, consider the <distributionManagement> configuration below:
So far this is just like the earlier generic example. However, we are not quite done. The githubDeploy profile is all that we need for GitHub Packages. However, we need a bit more for Maven Central. Specifically, there are a couple plugins that we'll need to add to the ossrhDeploy profile above. Maven Central requires that all of our artifacts are signed with GPG. So we'll need to configure the plugin maven-gpg-plugin. Additionally, for Maven Central, our artifacts will initially end up in a Sonatype staging repository. To avoid the need to login to manually release from staging, we'll configure the nexus-staging-maven-plugin to do that for us.
If you use this library in your research, please cite the following paper:
Cicirello, V. A., (2020). Chips-n-Salsa: A Java Library of Customizable, Hybridizable, Iterative, Parallel, Stochastic, and Self-Adaptive Local Search Algorithms. Journal of Open Source Software, 5(52), 2448, https://doi.org/10.21105/joss.02448 .
Overview
Chips-n-Salsa is a Java library of customizable, hybridizable, iterative, parallel, stochastic, and self-adaptive local search algorithms. The library includes implementations of several stochastic local search algorithms, including simulated annealing, hill climbers, as well as constructive search algorithms such as stochastic sampling. Chips-n-Salsa now also includes genetic algorithms as well as evolutionary algorithms more generally. The library very extensively supports simulated annealing. It includes several classes for representing solutions to a variety of optimization problems…
Vincent A. Cicirello - Professor of Computer Science at Stockton University - is a
researcher in artificial intelligence, evolutionary computation, swarm intelligence,
and computational intelligence, with a Ph.D. in Robotics from Carnegie Mellon
University. He is an ACM Senior Member, IEEE Senior Member, AAAI Life Member,
EAI Distinguished Member, and SIAM Member.