How to identify and set a missing environment property in Maven? - maven

I have my build set-up so that I pass in my variable via the command line:
mvn clean install -DsomeVariable=data
In my pom I have:
<someTag>${someVariable}</someTag>
This works fine, but I would like to identify if someVariable is not specified on the command line, and then default it so that my script can continue.
Can this be done in Maven?

You can specify default property value in the properties section of your POM file:
<properties>
<someVariable>myVariable</someVariable>
</properties>
If you want to make sure that the property value is ALWAYS supplied on a command line, then you can use maven-enforcer-plugin.
Here is a link that shows how to enforce system property presence -> http://maven.apache.org/enforcer/enforcer-rules/requireProperty.html
I'll just copy the XML verbatim here in case the above link goes bad.
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0.1</version>
<executions>
<execution>
<id>enforce-property</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>basedir</property>
<message>You must have a basedir!</message>
<regex>\d</regex>
<regexMessage>You must have a digit in your baseDir!</regexMessage>
</requireProperty>
<requireProperty>
<property>project.version</property>
<message>"Project version must be specified."</message>
<regex>(\d|-SNAPSHOT)$</regex>
<regexMessage>"Project version must end in a number or -SNAPSHOT."</regexMessage>
</requireProperty>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>

You can specify the default value as
<properties>
<someTag>defaultValue</someTag>
</properties>
When you run maven command, you can override that value like this
mvn clean package -DsomeTag=newSpecificValue

You can use profiles instead, but you'll need a profile for each
variable.
<profile>
<id>default-value-1</id>
<activation>
<activeByDefault>false</activeByDefault>
<property>
<name>!someVariable</name>
</property>
</activation>
<properties>
<someVariable>DEFAULT-VALUE</someVariable>
</properties>
</profile>

Related

Duplication in maven: are profiles additive to project, or do they replace declared items?

Provided you have the following defined in your POM.xml:
<project>
<!-- ... -->
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profiles>
<profile>
<id>foo</id>
<build>
<plugins>
<plugin>
<artifactId>plugin-X</artifactId>
<!-- plugin config -->
</plugin>
<plugins>
</build>
<profile>
</profiles>
</project>
If the plugin config for plugin-X is exactly the same for profile foo as it is for a build without a selected profile, do you have to redeclare the plugin at all on the profile level? If so, do you also have to redeclare all config settings for it?
If you declared plugin-Y in project.profile.build.plugins instead of plugin-X (but left it declared on the project level), which plugins would be run when you run mvn -P foo? Only plugin-Y, or also plugin-X?
More generally speaking, are profiles additive to what is declared on the project level, or do they override it? (If they are additive, how do you "remove" entities that were declared on a project level when you run a build profile and don't want them for that specific profile?)
I know profile configuration gets inherited from parent pom files ("from either the build/plugins or pluginManagement sections of the parent") with options "merge", "append", and "override". I think what I really want to know is: how does maven behave when the same/similar information is defined on the project and profile levels in the same pom file...
This isn't a full answer, but another piece of the puzzle - in addition to my earlier comments, and maven's Guide to Configuring Plug-ins.
Given the following pom.xml file:
</profiles>
<properties>
<foo>main</foo>
<bar>main</bar>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>${foo}</echo>
<echo>${bar}</echo>
<echo>${baz}</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>p</id>
<properties>
<bar>prof</bar>
<baz>prof</baz>
</properties>
</profile>
</profiles>
</project>
When I run mvn validate, I get the following output:
[echo] main
[echo] main
[echo] ${baz}
Running mvn validate -P p however yields:
[echo] main
[echo] prof
[echo] prof
That means that properties at least are merged, appending new items and replacing those that are redefined.
Also, if I add another plugin to the profile (such as surefire), it will execute when running the profile with mvn <phase> -P p, so the profile inherits antrun and adds surefire. Plugin re-definitions however replace the original; adding
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<configuration>
<target>
<echo>Tada!</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
only prints Tada!, but no longer the original antrun output (even when changing the new addition's phase to initialize. Adding <inherited>true</inherited> to any of the two plugin definitions doesn't make a difference. The behaviour might be plugin-specific, though.

In maven, how to override plugin configuration in settings.xml

I want to override a particular plugin configuration that's defined in the pom.xml. I don't want to modify the pom.xml for various reasons. Is there a way to define a config attribute for that plugin in settings.xml that override corresponding pom.xml plugin config?
In the below example, you'll notice that the plugin xx-plugin is defined in profile1 in pom.xml. In my settings.xml I've already defined profile2 to override property prop1 from pom.xml. But how to override config3. I apologize if this is a silly question. I am a little new to maven.
This is what my pom.xml looks like:
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>CCC</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
This is what my settings.xml looks like:
<profile>
<id>profile2</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<prop1>overriden-value</prop1> <!-- This works -->
</properties>
<!-- Somehow override config3 here -->
<!-- <config3>DDD</config3> -->
</profile>
AFAIK you can only override properties with settings.xml profiles. You'd have to change your plugin's configuration to use a property instead of a fixed value:
<!-- define your property -->
<properties>
<prop1>CCC</prop1>
</properties>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.xx.yyy</groupId>
<artifactId>xx-plugin</artifactId>
<executions>
<execution>
<id>xx-install</id>
<phase>install</phase>
<goals>
<goal>xx-install</goal>
</goals>
<configuration>
<config1>AAA</config1>
<config2>BBB</config2>
<config3>${prop1}</config3> <!-- I want to override this with value DDD -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Remember that profiles with activeByDefault set to true will get deactivated if any other profile gets activated in your build invocation. See http://maven.apache.org/guides/introduction/introduction-to-profiles.html
If you do not want to change the pom.xml for a plugin you can set the configuration as JVM parameter when running maven as stated in the Generic Configuration chapter of the Maven Guide to Configuring Plugins.
Example:
mvn my-plugin:my-goal -Dplugin.property=ABC
Example for the wildfly plugin (this is where I needed it and did not want to change the pom.xml of a demo project when deploying to a server group in a domain context):
mvn clean install wildfly:deploy -Dwildfly.serverGroups=<server-group-name>
The maven documentation also states that most plugins define help goals to explain users how to configure them.
Exaple for the wildfly plugin:
mvn wildfly:help -Dgoal=deploy -Ddetail

How can I set path in this Maven plugin?

I'm new to Maven plugins, and I need to get this plugin working to run the sencha cmd tool to minify our JavaScript app as part of the daily build process.
Currently the executable tag has a hard coded path, but I'm wondering if I can specify the path as an environment variable, and then access that environment variable in the code below so it can be run on any machine?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>sencha-compile</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>C:\Sencha\Sencha\Cmd\4.0.2.67\sencha.exe</executable>
<arguments>
<argument>app</argument>
<argument>build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
Check my Sencha ExtJS 5 + Sencha Cmd 5 + Maven integration example at:
https://github.com/dobromyslov/sencha-extjs-maven
You have to set environment variable:
Export it in console via:
$ export SENCHA_CMD="/path/to/your/Sencha/Cmd/5.0.0.116/sencha"
Also you can add this export statement to your ~/.bashrc or /etc/profile file in order to make it permanent.
Or add new environment variable on Windows.
Set Sencha Cmd build environment:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Default build environment -->
<sencha.env>production</sencha.env>
</properties>
<profiles>
<!-- Development profile -->
<profile>
<id>dev</id>
<activation>
<property>
<name>env</name>
<value>development</value>
</property>
</activation>
<properties>
<sencha.env>testing</sencha.env>
</properties>
</profile>
<!-- Production profile -->
<profile>
<id>prod</id>
<activation>
<property>
<name>env</name>
<value>production</value>
</property>
</activation>
<properties>
<sencha.env>production</sencha.env>
</properties>
</profile>
</profiles>
Then use the following Maven plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>sencha-compile</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<!-- Set path to your Sencha Cmd executable-->
<executable>${env.SENCHA_CMD}</executable>
<arguments>
<argument>-sdk</argument>
<argument>${basedir}/src/main/webapp</argument>
<argument>app</argument>
<argument>build</argument>
<argument>--clean</argument>
<argument>--environment</argument>
<argument>${sencha.env}</argument>
<argument>--destination</argument>
<argument>${basedir}/src/main/webapp/build</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
And run
$ mvn compile
To answer your question, you can reference system environment variables from within a maven pom file with this syntax:
${env.NAME_OF_VARIABLE}
See this link for more details:
https://maven.apache.org/pom.html#Properties
If you named the environment variable PATH_TO_SENCHA_EXE you could reference it like this:
<executable>${env.PATH_TO_SENCHA_EXE}sencha.exe</executable>
As an alternative to environment variables, you could consider creating a property in your pom to contain this path. Then you could change the value used for different environments by passing a new value for the property on the command line or by loading a properties file in your pom that may contain this property. There are many options here.
Edit:
I found the latter suggestion has been covered on SO at the following link (and likely other places):
Reading properties file from Maven POM file

Define different value per profile for same Maven property

I'm facing a problem with maven property per profiles. I have two profiles, each one has the same property 'prop.key' with different values. When I call mvn clean package -PA -PB or mvn clean package -PB -PA both are using the same value 'B-1.0-SNAPSHOT'. I'm using maven 3.0.4.
Below my POM :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.module</groupId>
<artifactId>test-module</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<prop.key>UNKNOWN</prop.key>
</properties>
<profiles>
<profile>
<id>A</id>
<properties>
<prop.key>A-${project.version}</prop.key>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>A</id>
<phase>package</phase>
<configuration>
<tasks name="a" description="a-desc">
<echo message="RUN A = ${prop.key}" level="info"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>B</id>
<properties>
<prop.key>B-${project.version}</prop.key>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>B</id>
<phase>package</phase>
<configuration>
<tasks name="b" description="b-desc">
<echo message="RUN B = ${prop.key}" level="info"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
I have found 'similar topic' but with opposite result!
Is it a bug or a feature of maven?
You can write
mvn package -PA,B
for short.
The result is the same:
[echo] RUN A = B-1.0-SNAPSHOT and
[echo] RUN B = B-1.0-SNAPSHOT
This is the correct behaviour of maven.
One property can only have one specific value per run. You can overwrite a "default value" with a version in a profile. But if you redefine it in two profiles and activate both, one of the profiles "wins".
It is not possible to have one value per profile for one and the same property. Profiles do not have their own variable scope. Properties are always global.
I would think you get this behavior because last parameter for profile gets picked.
Try
mvn clean package -PA,B
See Maven introduction to profiles.
Profiles can be explicitly specified using the -P CLI option.
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.
When you run mvn package -PA,B, maven will read both profiles A and B, and the properties from later one in the pom.xml file will take precedence (B is defined below A in pom.xml), result in <prop.key>B-${project.version}</prop.key> will be used.

How to define conditional properties in maven?

For instance, I would like to have property Configuration set to ${env:AAA} if there is an environment variable AAA and to some other constant value if there is no such environment variable.
How do I do it in maven 2?
It appears as though you activate a profile conditionally...
<profiles>
<profile>
<activation>
<property>
<name>environment</name>
<value>test</value>
</property>
</activation>
...
</profile>
</profiles>
The profile will be activate when the environment variable is defined to the value test as in the following command:
mvn ... -Denvironment=test
On the off-chance that a system property is acceptable, you can simply define the property in your POM file and override when required:
<project>
...
<properties>
<foo.bar>hello</foo.bar>
</properties>
...
</project>
You can reference this property elsewhere in your POM by referring to ${foo.bar}. To override on the command line, just pass a new value:
mvn -Dfoo.bar=goodbye ...
You can set a property conditionally using maven-antrun-plugin. Example setting install.path + echoing the value:
<plugin>
<!-- Workaround maven not being able to set a property conditionally based on environment variable -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<property environment="env"/>
<condition property="install.path" value="${env.INSTALL_HOME}" else="C:\default-install-home">
<isset property="env.INSTALL_HOME" />
</condition>
<echo message="${install.path}"/>
</target>
</configuration>
</execution>
</executions>
</plugin>

Resources