Triggering Maven profiles from Heroku configured Environment Variables - maven

I am trying to activate a profile in my maven pom as follows:-
<profile>
<id>test</id>
</properties>
<activation>
<property>
<name>env.SITE</name>
<value>test</value>
</property>
</activation>
</profile>
Now i am configuring heroku to have the environment variable SITE as follows:-
heroku config:add SITE=test.
I expect the environment variable to trigger the profile when code is pushed. However this is not happening.

You can do this without a custom build pack.
Use this snippet in your pom.xml to display all properties available on Heroku and pick one that is not in your local: http://florianlr.wordpress.com/2012/04/24/16/
I used env.DYNO
<profile>
<id>heroku</id>
<activation>
<property>
<name>env.DYNO</name>
</property>
</activation>
...
</profile>
...
Works like a charm:)

You can specify the maven profile using the environment variable MAVEN_CUSTOM_OPTS.
In your pom define maven profile activation to be based off the presence of a property. The below example uses the development profile if you specify it and defaults to production if you don't. reference
<profiles>
<profile>
<id>production</id>
<activation>
<property>
<name>!profile-development</name>
</property>
</activation>
</profile>
<profile>
<id>development</id>
<activation>
<property>
<name>profile-development</name>
</property>
</activation>
</profile>
</profiles>
In Heroku set the MAVEN_CUSTOM_OPTS environment variable to use the profile. Note that this variable overrides the default option -DskipTests. reference
MAVEN_CUSTOM_OPTS=-DskipTests -Dprofile-development
In this example the production profile would not need MAVEN_CUSTOM_OPTS declared.

Or you can introduce your own customized Maven settings.xml file, e.g. heroku-settings.xml:
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- activate by setting the MAVEN_SETTINGS_PATH config var to heroku-settings.xml in Heroku project settings tab.
See https://devcenter.heroku.com/articles/using-a-custom-maven-settings-xml for more details.
-->
<activeProfiles>
<activeProfile>production</activeProfile>
</activeProfiles>
</settings>
Then activate the settings by setting the MAVEN_SETTINGS_PATH config var to heroku-settings.xml in Heroku project settings tab

The config vars aren't currently available at compile time. To change the Maven profile you will need to fork the Heroku Java Buildpack.

I solved my problem by adding Heroku Environment like below:
MAVEN_CUSTOM_OPTS=-P<profile_id>
and cut out "activation" tag from pom.xml.
Btw I don't know why this doesn't work (in Heroku I have ENVIRONMENT=test)
<profile>
<id>test</id>
<activation>
<property>
<name>env.ENVIRONMENT</name>
<value>test</value>
</property>
</activation>
...
</profile>

Related

How to override Maven properties using command like options?

I would like to have a Maven property that is set to a default unless -Dmy.prop is set.
So I went into my parent pom and added the property:
<properties>
<my.prop>ABC</my.prop>
</properties>
I ran mvn clean install -Dmy.prop=XYZ, hoping the XYZ would override the ABC but it did not.
You could use a profile to achieve that behaviour.
<profile>
<id>default-prop-a</id>
<activation>
<property>
<name>!prop.a</name>
</property>
</activation>
<properties>
<prop.a>VALUE</prop.a>
</properties>
</profile>

Activating a Child Profile from a Parent Profile

I have the following parent pom.xml file:
<profile>
<id>build_full</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>mymodule_interface</module>
<module>mymodule_switch</module>
<module>mymodule_switch_simulator</module>
<module>mymodule_switch_controller</module>
<module>mymodule_server</module>
</modules>
</profile>
and in my child pom for mymodule_server, I have the following:
<profile>
<id>subprofile</id>
<modules>
<module>...various modules...</module>
</modules>
</profile>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>...various modules...</module>
</modules>
</profile>
How, when I invoke maven: mvn -P build_full, can I force the child module (mymodule_server) to use profile subprofile rather than default?
No, you can't activate a child profile from a parent profile. More generally, you can't activate or deactivate any profile from any other profile (there is a JIRA feature-request MNG-3309). What you can do is activate two profiles based on the same property.
First of all, using a profile that is activated by default is generally not a good idea. What you want is to activate a profile based on some condition (OS version, system property...). To solve your problem, you can activate build_full profile when a certain system property is present, and make sure that subprofile is also activated when that same property is present.
A sample configuration would be the following, where both profiles are activated when the fullBuild system property is set to true. Invoking Maven with mvn -DfullBuild=true ... will thus activate both profiles.
<profile>
<id>build_full</id>
<activation>
<property>
<name>fullBuild</name>
<value>true</value>
</property>
</activation>
<modules>
<module>mymodule_interface</module>
<module>mymodule_switch</module>
<module>mymodule_switch_simulator</module>
<module>mymodule_switch_controller</module>
<module>mymodule_server</module>
</modules>
</profile>
<profile>
<id>subprofile</id>
<activation>
<property>
<name>fullBuild</name>
<value>true</value>
</property>
</activation>
<modules>
<module>...various modules...</module>
</modules>
</profile>
In your case, from the top parent/aggregator folder, you could just run:
mvn clean install -Pbuild_full,!default,subprofile
It will disable any profile having name default (and hence disable the profile in the concerned sub-module) and enable any profile having name subprofile (and hence enable the profile you wanted).
Alternatively, you could configure subprofile as such:
<profiles>
<profile>
<id>subprofile</id>
<activation>
<property>
<name>subprofile</name>
<value>true</value>
</property>
</activation>
....
and then run as following:
mvn clean install -Dsubprofile=true -Pbuild_full
It will have the same effect. You can even avoid the value element and simply specify -Dsubprofile, its existence would be enough to activate the profile (in that case a more meaningful name is suggested, like -DactivateSubprofile). Since you active a different profile, automatically Maven will deactivate the default one.

Creating exclusive profiles in maven

I currently have a pom with platform specific profiles (e.g. linux 32bit, windows 64 bit, etc...). Additionally, I have set it up to automatically choose the invoker's platform as a default.
Now, assume I am in a linux 32 machine: I also want to build for win64 by invoking mvn -Pwin64 pakage but in doing so, both the linux32 and win64 profiles get activated. I have tried activating the local platform profile with activeProfiles and using ativation tags. The trouble is that -P does not disable all other profiles as explained in the documentation:
This option takes an argument that is a comma-delimited list of
profile-ids to use. When this option is specified, no profiles other
than those specified in the option argument will be activated.
Am I understanding this wrong? How would you handle this?
Note: I know I could run mvn -P-linux32,win64 but that is only valid on linux32 platforms, and any mistakes may result in a bloated build with duplicate classes.
Thanks!
This statement from the profile docs:
As of Maven 3.0, profiles in the POM can also be activated based on properties from active profiles from the settings.xml.
Would lead me to try the solution below. Each developer defines his default platform as a property in his settings.xml file and overrides it on the cmdline if needed.
Developer's settings.xml
<profile>
<id>platform-config</id>
<property>
<name>build.platform</name>
<value>win32</value>
</property>
</profile>
....
<activeProfiles>
<activeProfile>platform-config</activeProfile>
</activeProfiles>
Project's pom.xml
<project>
...
<profiles>
<profile>
<id>win32</id>
<activation>
<property>
<name>build.platform</name>
<value>win32</value>
</property>
</activation>
...
</profile>
<profile>
<id>linux32</id>
<activation>
<property>
<name>build.platform</name>
<value>linux32</value>
</property>
</activation>
...
</profile>
</profiles>
Then, mvn install should activate the win32 profile because the default value for the build.platform property is win32, while mvn install -Dbuild.platform=linux32 will override the default property setting and use the Linux profile instead.
Why don't you use the profile activation by plattform like this:
<project>
...
<profiles>
<profile>
<id>win32</id>
<activation>
<activeByDefault>false</activeByDefault>
<os>
<name>Windows XP</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
</activation>
...
</profile>
</profiles>
</project>

Confused that order matters when defining conditional profiles in maven

I have a configurable property line.ending that I used during the assembly phase of the building of my project to specify the line ending type of my application property files. For that I have created two profiles LF_DOS and LF_UNIX, so that when I launch :
mvn install
or
mvn install -P LF_DOS
line.ending equals 'dos', and when I launch :
mvn install -P LF_UNIX
line.ending equals 'unix'.
My first attempt to do this was simply :
<profile>
<id>LF_UNIX</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<line.ending>unix</line.ending>
</properties>
</profile>
<profile>
<id>LF_DOS</id>
<activation>
<property>
<name>!line.ending</name>
</property>
</activation>
<properties>
<line.ending>dos</line.ending>
</properties>
</profile>
Unfortunately, this always gave me line.ending=dos, whatever LF_UNIX is set or not. Weird... But, the more confusing to me, is that I solved the problem just by changing the profile declaration order, like this :
<profile>
<id>LF_DOS</id>
<activation>
<property>
<name>!line.ending</name>
</property>
</activation>
<properties>
<line.ending>dos</line.ending>
</properties>
</profile>
<profile>
<id>LF_UNIX</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<line.ending>unix</line.ending>
</properties>
</profile>
This works exactly like I want.
My questions is : is this a bug ? Or is it something to know about maven profiles, a kind of limitation that makes profiles order declaration particularly matter in such a case ?
The confusion lies in your understanding of how profile activation works.
You think that this:
<activation>
<property>
<name>!line.ending</name>
</property>
</activation>
means if I don't have a maven property named "line.ending" set, activate this profile. What it really means if I didn't specify -Dline.ending=X on the command line, activate this profile. So unless you run something like this:
mvn clean install -Dline.ending=unix
You are activating this profile and thus having the value set to dos.

What is the best way to parameterize a Maven script to switch between Spring configurations?

What is the best way to parameterize a Maven script to switch between Spring configurations?
I have Maven building a WAR file for a web app. I have alternative spring configurations - one for integration testing with mock objects, one for live production use with real objects.
Ideally, I would like to have one Maven build script that can build either WAR file. At present, I just hack the spring config file before building, commenting in and out the mocks and real objects.
What is the best way to go about this?
I suggest that you use the build profiles.
For each profile, you will define a specific Spring configuration:
<profiles>
<profile>
<id>integration</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>env</name>
<value>integration</value>
</property>
</activation>
<!-- Specific information for this profile goes here... -->
</profile>
<profile>
<id>production</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>env</name>
<value>production</value>
</property>
</activation>
<!-- Specific information for this profile goes here... -->
</profile>
...
You will then activate one profile or the other by setting the parameter env : -Denv=integration for the first profile, -Denv=production for the second profile.
In each profile block, you can specify any information specific to your environment. You can then specify properties, plugins, and so on. In your case, you may change the configuration of the resources plugin in order to include the adequate Spring configuration. For example, in integration profile, you can specify where Maven will search the Spring configuration file:
<profile>
<id>integration</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>env</name>
<value>integration</value>
</property>
</activation>
<build>
<resources>
<resource>/path/to/integration/spring/spring.xml</resource>
</resources>
</build>
</profile>

Resources