Maven profiles – Operating Systems (OS) specific build profiles
In this article, we’ll learn about how to create different
build profiles for windows and Mac OS. The same concept can be replicated to
other operating systems or environment specific builds.
Let’s define a use case.
Let’s say we have project in which we want to compile and package
Angular 2+ project using maven build. Angular 2+ project is dependent on
Node.js (npm) and Angular CLI (ng CLI). We can use Maven Exec plugin for invoking
npm and ng CLI commands.
On Mac OS “npm” and “ng” commands works without any
additional extension. To run same commands on Windows operating system we need
to append .cmd extension. This means if we have mixed folks in development team
who uses both Windows and Mac OSx then every time pom.xml file needs to be
updated. What if someone pushes this file to central code repository? This will
obviously break the builds on CI/CD (e.g. Jenkins server). This is just one
scenario, there may be other use cases where build command/process has to be
different based on operating systems or environment and it is not good idea to
modify pom.xml file locally for build and leave room for accidental
commits/push. This is where Maven profiles comes handy.
Let’s continue with same Angular 2+ build example. On Mac OS,
the build section (that is responsible for building Angular project using Maven
exec plugin) of pom.xml file would look like:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Omitted remaining pom.xml for simplicity -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
<execution>
<id>ui-npm-install</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>ui-aem-build</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>ng</executable>
<arguments>
<argument>build</argument>
<argument>--prod</argument>
<argument>--outputHashing</argument>
<argument>none</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>npm-clean</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>rm</executable>
<arguments>
<argument>-rf</argument>
<argument>node_modules</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Omitted remaining pom.xml for simplicity -->
</project>
Look at the line # 18, 33, 52 and 54. These commands are OS
dependent and if we run a maven build with this configuration on Windows, it’ll
fail.
To handle this in Maven way, we could create separate
profile for Max OS and Windows. Following pom.xml file shows an example of OS
specific build profiles.
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- Omitted remaining pom.xml for simplicity -->
<profiles>
<!-- Max OSX specific build profile -->
<profile>
<id>macOSBuild</id>
<activation>
<!-- Profile is active by default -->
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
<execution>
<id>ui-npm-install</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>ui-aem-build</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>ng</executable>
<arguments>
<argument>build</argument>
<argument>--prod</argument>
<argument>--outputHashing</argument>
<argument>none</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>npm-clean</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>rm</executable>
<arguments>
<argument>-rf</argument>
<argument>node_modules</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
</build>
</profile>
<!-- Windows OS specific build profile -->
<profile>
<id>winOSBuild</id>
<activation>
<!-- Profile is NOT active by default -->
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<!-- Execute UI Build as part of standard Maven "generate-resource" phase -->
<execution>
<id>ui-npm-install</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>npm.cmd</executable>
<arguments>
<argument>install</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>ui-aem-build</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>ng.cmd</executable>
<arguments>
<argument>build</argument>
<argument>--prod</argument>
<argument>--outputHashing</argument>
<argument>none</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>npm-clean</id>
<configuration>
<workingDirectory>.</workingDirectory>
<executable>rmdir</executable>
<arguments>
<argument>/s</argument>
<argument>node_modules</argument>
</arguments>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<!--<phase>prepare-package</phase> -->
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
</build>
</profile>
</profiles>
<!-- Omitted remaining pom.xml for simplicity -->
</project>
Few important observations
·
We have moved the plugin “exec-maven-plugin” configuration inside XML tag
·
Created two profiles “macOSBuild” and “winOSBuild”
(line 9 and 78 respectively)
·
“macOSBuild” profile is active by default
(line 12). This means on Mac OS, we can simply run the “mvn clean install”
command and Mac profile will be automatically picked up for build
·
To execute build on Windows OS, we need to explicitly
tell maven to use “winOSBuild” profile. This can be done via “mvn clean install -PwinOSBuild”
I hope this simple concept will help you to avoid manual changes
of pom.xml and keep your project away from accidental risk of build failures.
Comments