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.
Table of Contents:
- How to Specify Profiles.
- Profile to Enable (De)Activating a Plugin at Build Time, using an example profile that configures JaCoCo code coverage.
- Profiles for Deploying to Multiple Maven Repositories, using an example for deploying to both Maven Central as well as GitHub Packages.
- Live Example from one of my projects on GitHub.
- Where You Can Find Me.
How to Specify Profiles
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.
<profiles>
<profile>
<id>profileOne</id>
</profile>
<profile>
<id>profileTwo</id>
</profile>
<profile>
<id>profileThree</id>
</profile>
</profiles>
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:
<profiles>
<profile>
<id>profileOne</id>
<build>
<plugins>
<plugin>
<groupId>com.example</groupId>
<artifactId>example-plugin</artifactId>
<version>1.2.3</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>
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.
<profiles>
<profile>
<id>coverage</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>generate-code-coverage-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
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:
<profiles>
<profile>
<id>githubDeploy</id>
<distributionManagement>
<repository>
<id>github</id>
<name>GitHub cicirello Apache Maven Packages</name>
<url>https://maven.pkg.github.com/cicirello/Chips-n-Salsa</url>
</repository>
</distributionManagement>
</profile>
<profile>
<id>ossrhDeploy</id>
<distributionManagement>
<repository>
<id>ossrh</id>
<name>Central Repository OSSRH</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>
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.
Here is the full example:
<profiles>
<profile>
<id>githubDeploy</id>
<distributionManagement>
<repository>
<id>github</id>
<name>GitHub cicirello Apache Maven Packages</name>
<url>https://maven.pkg.github.com/cicirello/Chips-n-Salsa</url>
</repository>
</distributionManagement>
</profile>
<profile>
<id>ossrhDeploy</id>
<distributionManagement>
<repository>
<id>ossrh</id>
<name>Central Repository OSSRH</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Given the above in the pom.xml, to deploy to Maven Central, we use:
mvn deploy -PossrhDeploy
Or to instead deploy to GitHub Packages, we use:
mvn deploy -PgithubDeploy
Live Example
To see a live example of both of these uses of Maven profiles, consult the pom.xml of one of my projects. Here is the GitHub repository:
cicirello / Chips-n-Salsa
A Java library of Customizable, Hybridizable, Iterative, Parallel, Stochastic, and Self-Adaptive Local Search Algorithms
Copyright (C) 2002-2024 Vincent A. Cicirello.
Website: https://chips-n-salsa.cicirello.org/
API documentation: https://chips-n-salsa.cicirello.org/api/
How to Cite
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…
Where You Can Find Me
Follow me here on DEV:
Follow me on GitHub:
Vincent A Cicirello
View My Detailed GitHub Activity
If you want to generate the equivalent to the above for your own GitHub profile, check out the cicirello/user-statistician GitHub Action.
Or visit my website:
Top comments (0)