Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enforce the use of exactly one out of two Maven profiles?

I have a Maven project that defines two separate profiles, developer and release (surely you get the drift, here). I want one of these two profiles to be activated at any time, but never both. If both are somehow activated, this build makes no sense and should fail. If neither is activated, this build also makes no sense and should fail.

I'm sure I can write some custom plugin code to achieve this, and I might very well end up going that way, but I'd be interested in achieving this using POM configuration (could be using existing plugins from Maven Central).

It should be possible to activate plugins using -P (--activate-profiles) so <activation> through properties would not be a valid solution. Solutions using activeByDefault would not be valid either, since activeByDefault is generally known as a pitfall, unreliable (and we may in fact activate other profiles, thus rendering activateByDefault unusable).

Your suggestions much appreciated.

like image 467
Sander Verhagen Avatar asked Jul 20 '14 22:07

Sander Verhagen


People also ask

How do I activate a single Maven profile?

Profiles can be activated in the Maven settings, via the <activeProfiles> section. This section takes a list of <activeProfile> elements, each containing a profile-id inside. Profiles listed in the <activeProfiles> tag would be activated by default every time a project use it.


2 Answers

I had a similar need (i.e. for mutual exclusivity of two profiles) and solved it by considering the two target profiles to be internal profiles that shouldn't be specified on the command line: Instead, a controlling system property can either be specified or not. E.g. let's assume that by default you want the "dev" profile to be active. We can then activate/deactivate the relevant internal profiles based on whether the -Drelease option is specified as follows:

<!-- Internal profile: FOR INTERNAL USE ONLY - active if -Drelease is *not* specified. -->
<profile>
  <id>internal-dev</id>
  <activation>
    <!-- Activation via *absence* of a system property to ensure mutual exclusivity
         of this profile with internal-release -->
    <property>
      <name>!release</name>
    </property>
  </activation>
  ...
</profile>

<!-- Internal profile: FOR INTERNAL USE ONLY - active if -Drelease *is* specified. -->
<profile>
  <id>internal-release</id>
  <activation>
    <!-- Activation via *presence* of a system property to ensure mutual exclusivity
         of this profile with internal-dev -->
    <property>
      <name>release</name>
    </property>
  </activation>
  ...
</profile>
like image 113
Steve Chambers Avatar answered Nov 16 '22 02:11

Steve Chambers


This can still be done with Maven Enforcer plugin

Although mutual exclusion, <requireActiveProfile>...<all>false</all>... is buggy as reported by @khmarbaise, there's still the <evaluateBeanshell/> built-in rule that lets one do whatever he wants.

I wrote one especially for this case: XOR of two profiles. I hope it helps.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-enforcer-plugin</artifactId>
                <version>1.4.1</version>
                <executions>
                    <execution>
                        <id>enforce-PROFILE_ONE-XOR-PROFILE_TWO-is-active</id>
                        <goals>
                            <goal>enforce</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <requireActiveProfile>
                                    <profiles>PROFILE_ONE,PROFILE_TWO</profiles>
                                    <all>false</all>
                                </requireActiveProfile>
                                <evaluateBeanshell>
                                    <condition><![CDATA[
                                        // ensure PROFILE_ONE XOR PROFILE_TWO
                                        print("Checking if only one of PROFILE_ONE and PROFILE_TWO profiles is active ...");
                                        boolean profile1 = false, profile2 = false;
                                        for(s: "${project.activeProfiles}".replaceAll("\\[?\\s?Profile \\{id: (?<profile>\\w+), source: \\w+\\}\\]?", "${profile}").split(",")) {
                                            if("PROFILE_ONE".equalsIgnoreCase(s)){ profile1 = true;}
                                            if("PROFILE_TWO".equalsIgnoreCase(s)){ profile2 = true;}
                                        }
                                        print("PROFILE_ONE XOR PROFILE_TWO: "+(profile1 != profile2));
                                        return profile1 != profile2;
                                    ]]></condition>
                                </evaluateBeanshell>
                            </rules>
                            <failFast>true</failFast>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

The tricky part is looping over active profiles, which I've already done here. You can extend it to more than two profiles if you need. But you'll have to write the long xor expression, since beanshell doesn't implement Java xor ^ operator.

like image 28
aymens Avatar answered Nov 16 '22 01:11

aymens