How to Use Maven Profiles to Selectively Activate Plugins and Other Configuration from the Command Line
Tags: java, tutorial, kotlin, programming
Published: 2022-10-19 13:38:44

[Apache Maven](https://maven.apache.org/) 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](#how-to-specify-profiles).
* [Profile to Enable (De)Activating a Plugin at Build Time](#profile-to-enable-deactivating-a-plugin-at-build-time), using an example profile that configures JaCoCo code coverage.
* [Profiles for Deploying to Multiple Maven Repositories](#profiles-for-deploying-to-multiple-maven-repositories), using an example for deploying to both Maven Central as well as GitHub Packages.
* [Live Example](#live-example) from one of my projects on GitHub.
* [Where You Can Find Me](#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:

```XML
<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.

```XML
<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:

```Shell
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:

```XML
<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](https://www.jacoco.org/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](https://github.com/cicirello/Chips-n-Salsa) where I have configured JaCoCo code coverage using a Maven profile in this way.

```XML
<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:

```Shell
mvn test -Pcoverage
``` 

Or, we can use `mvn package` or anything else that includes the test phase, with something like:

```Shell
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:

```XML
<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:

```Shell
mvn deploy -PprofileOne
```

And if we want to deploy to `repo2`, we use:

```Shell
mvn deploy -PprofileTwo
```

Let's look at a real example, again from [Chips-n-Salsa](https://github.com/cicirello/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:

```XML
<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:

```XML
<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:

```Shell
mvn deploy -PossrhDeploy
```

Or to instead deploy to GitHub Packages, we use:

```Shell
mvn deploy -PgithubDeploy
```


## Live Example

To see a live example of both of these uses of Maven profiles, consult the [pom.xml](https://github.com/cicirello/Chips-n-Salsa/blob/master/pom.xml) of one of my projects. Here is the GitHub repository:

{% github cicirello/Chips-n-Salsa %}


## Where You Can Find Me

Follow me here on DEV:

{% user cicirello %}

Follow me on GitHub:

{% github cicirello/cicirello %}

Or visit my website:

{% embed https://www.cicirello.org/ %}