Maven: profile-based properties used in plugins section - java

I would like to mention I am relatively new in Maven configurations.
My situation:
I use Maven 3.0.5 to build J2E application
the application is deployed in four different environments: local, dev, test and prod
I use maven profiles to configure environment-specific configurations
I have defined these configurations in properties files in the file system.
This is the file system for those:
<my-project-root>
---profiles
------local
---------app.properties
------dev
---------app.properties
------test
---------app.properties
I load the corresponding property file with the following logic in my pom.xml:
<profiles>
<profile>
<id>local</id>
<!-- The development profile is active by default -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>local</build.profile.id>
</properties>
</profile>
<profile>
<id>dev</id>
<properties>
<build.profile.id>dev</build.profile.id>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<build.profile.id>prod</build.profile.id>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<build.profile.id>test</build.profile.id>
</properties>
</profile>
</profiles>
<build>
<finalName>MyProject</finalName>
<plugins>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>profiles/${build.profile.id}</directory>
</resource>
</resources>
</build>
With this configuration I can use the respective properties for my current profile almost everywhere. Everywhere, but the <plugins> section. I would pretty much like to load e.g, my database url or credentials from such properties files, but if I include them in the app.properties they are not evaluated in the plugins section (e.g. I get value of ${endpoint} as database endpoint).
How do I get the properties loaded from files for the profile accessible in the <plugins> section?
PS: Yes, if I add those properties directly in the pom.xml as properties under <profiles> tag, they are accessible, but I would rather keep my passwords off the pom.

I was able to do what I wanted to do. I used properties-maven-plugin linked from, say this answer.
What I did was the following:
I added the properties-maven-plugin to read the files I needed loaded
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-2</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>profiles/${build.profile.id}/app.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
Regretfully, here I was not able to make the plugin read all property files in a directory, but I find this good enough.
I also needed to remove the error the plugin definition above gave for me in Eclipse (Plugin execution not covered by lifecycle configuration). To do thatI followed the instructions from the following post.
With those steps the properties I needed became available for the plugins, that used them.
Note: actually the properties get loaded after the compile maven command, but this is good enough for me, as all my property-dependant goals are to be executed after compile goal in sequence of goal calls in all my cases.

Related

How to prevent running tests when specific spring profile is active?

I have a Spring Boot application build on Maven. I'm using Spring profiles to distinguish environment-specific configuration. I would like to prevent running tests when a specific Spring profile is active. Reason: I would like to prevent running tests with production properties (spring.profiles.active=prod). I would like to do this globally (maybe with some Maven plugin) instead of on each test separately.
Do you have any checked solutions for this?
<profiles>
<profile>
<id>prod</id>
<properties>
<maven.test.skip>true</maven.test.skip>
</properties>
</profile>
</profiles>
You can use #IfProfileValue annotation. But you have to add some values to your active profile and read it with mentioned annotation. You can read more here (section 3.4.3): https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#integration-testing
EDIT:
Another solution is to exclude all (or selected tests) tests in the Surefire plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>${exclude.tests}</exclude>
</excludes>
</configuration>
</plugin>
...
<profile>
<id>prod</id>
<properties>
<exclude.tests>**/*.*</exclude.tests>
</properties>
</profile>
And then when you run mvn clean test -Pprod all tests will be skipped

Spring Boot pom - how to inherit profiles and properties from aggregator pom?

Objectives
I'm adding integration tests to a Maven build. I want to achieve the following goals:
Only unit tests are run by default.
It must be possible to run only integration tests.
Current state
The task becomes more complicated because this is an existing application with a confusing structure (hierarchy) of maven modules. I'll try to explain.
So I have an aggregator pom (super pom) that looks like
<groupId>com.group.id</groupId>
<artifactId>app-name</artifactId>
<modules>
<module>SpringBootApp1</module>
<module>SpringBootApp2</module>
</modules>
<packaging>pom</packaging>
<profiles>
<profile>
<id>Local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- Only unit tests are run when the development profile is active -->
<skip.integration.tests>true</skip.integration.tests>
<skip.unit.tests>false</skip.unit.tests>
</properties>
</profile>
<profile>
<id>Test</id>
<properties>
<!-- Only integration tests are run when the test profile is active -->
<skip.integration.tests>false</skip.integration.tests>
<skip.unit.tests>true</skip.unit.tests>
</properties>
</profile>
</profiles>
and a few module poms that do not inherit from super pom (they inherit from spring-boot-starter-parent) and look like
<groupId>com.group.id</groupId>
<artifactId>spring-boot-app</artifactId>
<packaging>jar</packaging>
<name>Spring Boot app</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<build>
<finalName>SpringBootApp1</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<skipTests>${skip.unit.tests}</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.21.0</version>
<executions>
<!-- Invokes both the integration-test and the verify goals of the Failsafe Maven plugin -->
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>${skip.integration.tests}</skipTests>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
As you see I define skip.integration.tests and skip.unit.tests properties in the aggregator pom (property values are different for different profiles) and try to use them in module poms.
Problem
When I execute mvn clean test -P Test or mvn clean verify -P Test to run tests I see that properties are not applied (e.g. unit tests are executed although skip.unit.tests is true).
I could declare aggregator pom as parent of module pom and maybe it would solve the problem, but module poms already have spring-boot-starter-parent declared as their parent.
Questions
Is it possible to use properties from aggregator pom without making it a parent?
How can I separate integration tests from unit tests by using properties in aggregator pom?
ps. I assure you that I adhere to naming conventions: unit tests are named like *Test.java and integration tests are named like *IT.java. So maven-failsafe-plugin and maven-surefire-plugin distinguish them.
If you can make your aggregator as a parent for your modules, and than configure aggregator to have spring-boot-starter-parent as parent this problem will be solved.(assuming your aggregator does not have any parent currently).
Or you can pass skip test property from command line like -Dskip.unit.tests=true(where you call your mvn clean verify).
As a side note, when you execute mvn test command you don't have to specify integration test to skip, because it is later in the lifecycle.(it won't be executed any way)

Configure active profile in SpringBoot via Maven

I'm trying to set an active profile in Spring Boot application using Maven 3.
In my pom.xml I set default active profile and property spring.profiles.active to development:
<profiles>
<profile>
<id>development</id>
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
but every time I run my application, I receive the following message in logs:
No active profile set, falling back to default profiles: default
and the SpringBoot profile is set to default (reads application.properties instead application-development.properties)
What else should I do to have my SpringBoot active profile set using Maven profile?
Any help highly appreciated.
The Maven profile and the Spring profile are two completely different things. Your pom.xml defines spring.profiles.active variable which is available in the build process, but not at runtime. That is why only the default profile is activated.
How to bind Maven profile with Spring?
You need to pass the build variable to your application so that it is available when it is started.
Define a placeholder in your application.properties:
spring.profiles.active=#spring.profiles.active#
The #spring.profiles.active# variable must match the declared property from the Maven profile.
Enable resource filtering in you pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
When the build is executed, all files in the src/main/resources directory will be processed by Maven and the placeholder in your application.properties will be replaced with the variable you defined in your Maven profile.
For more details you can go to my post where I described this use case.
Or rather easily:
mvn spring-boot:run -Dspring-boot.run.profiles={profile_name}
There are multiple ways to set profiles for your springboot application.
You can add this in your property file:
spring.profiles.active=dev
Programmatic way:
SpringApplication.setAdditionalProfiles("dev");
Tests make it very easy to specify what profiles are active
#ActiveProfiles("dev")
In a Unix environment
export spring_profiles_active=dev
JVM System Parameter
-Dspring.profiles.active=dev
Example: Running a springboot jar file with profile.
java -jar -Dspring.profiles.active=dev application.jar
You can run using the following command. Here I want to run using spring profile local:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=local"
In development, activating a Spring Boot profile when a specific Maven profile is activate is straight. You should use the profiles property of the spring-boot-maven-plugin in the Maven profile such as :
<project>
<...>
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>development</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profiles>
</...>
</project>
You can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Pdevelopment
If you want to be able to map any Spring Boot profiles to a Maven profile with the same profile name, you could define a single Maven profile and enabling that as the presence of a Maven property is detected. This property would be the single thing that you need to specify as you run the mvn command.
The profile would look like :
<profile>
<id>spring-profile-active</id>
<activation>
<property>
<name>my.active.spring.profiles</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>${my.active.spring.profiles}</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</profile>
And you can run the following command to use both the Spring Boot and the Maven development profile :
mvn spring-boot:run -Dmy.active.spring.profiles=development
or :
mvn spring-boot:run -Dmy.active.spring.profiles=integration
or :
mvn spring-boot:run -Dmy.active.spring.profiles=production
And so for...
This kind of configuration makes sense as in the generic Maven profile you rely on the my.active.spring.profiles property that is passed to perform some tasks or value some things.
For example I use this way to configure a generic Maven profile that packages the application and build a docker image specific to the environment selected.
You should use the Spring Boot Maven Plugin:
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.1.RELEASE</version>
<configuration>
<profiles>
<profile>foo</profile>
<profile>bar</profile>
</profiles>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
I would like to run an automation test in different environments.
So I add this to command maven command:
spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=productionEnv1"
Here is the link where I found the solution: [1]https://github.com/spring-projects/spring-boot/issues/1095
I wanted to clarify the excellent answer https://stackoverflow.com/a/42391322/13134499 from Daniel Olszewski if you want to use it just for tests.
How to bind Maven profile with Spring for tests?
As you did, define the variable in pom.xml
...
<properties>
<spring.profiles.active>development</spring.profiles.active>
</properties>
Define a placeholder in your application-test.properties in src/test/resources:
spring.profiles.active=#spring.profiles.active#
Enable resource filtering in you pom.xml:
<build>
...
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
<testResources>
</build>
file structure:
/src/main/resources
=>
application.properties:
spring.profiles.active:#spring.profiles.active#'
application-dev.properties
application-prod.properties
IDE-Eclipse:
Right click on the project=>Run As=>Run Configuration=>Arguments=>VM Arguments:-Dspring.profiles.active=dev
CMD:
mvn spring-boot:run -Dspring.profiles.active=dev
mvn clean install -Dspring.profiles.active=dev

how to perform task for different profiles using maven

I am new to Maven.
I want to perform database connection for different users so my problem is that where I should provide this JDBC connection and how to provide this connection for different users?
I know how to provide profiles for different users but where should I perform database connection and how it get invoked?
Best approach would make your database connection properties (like username/password, url, etc) external. Within a profile you could than define per user the values for the properties and use the maven resource filtering to set them.
Within your maven project you would for example have a config directory (in src/config/settings.prp) which for example contains the following entries:
userName = ${userName}
password = ${password}
db-driver = ${dbDriver}
db-url = ${dbUrl}
Within the pom you would have
<project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>filter-db-settings</id>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/config</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/config</directory>
</resource>
<filtering>true</filtering>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugins>
</build>
<profiles>
<profile>
<id>user-A</id>
<properties>
<userName>userA</userName>
<password>secret</password>
<dbDriver>com.driver.db</dbDriver>
<dbUrl>jdbc://db-url</dbUrl>
</properties>
</profile>
<profiles>
</project>
The plugin will filter the files in src/config and replace the maven placeholders by the values as specified within your profile. Since the profile contains a password you could move it to your settings.xml so that it is not checked in with the project itself possibly exposing the password to unwanted parties.
WARNING: Haven't verified the plugin above so might contain small mistakes.
Best practice it to put the property file NOT within the generated artifact. By doing this you get the freedom to use the same artifact fro different users and the only thing you need to change are the properties in the external property file, (which will be given to user beside the artifact).
The following article explains how you can externalize the properties with spring Externalized Configuration.

Maven versions plugin: reference a rule.xml from a maven dependency?

I am using the mvn versions:display-dependency-updates versions:display-plugin-updates goals to check for dependencies or plugins updates.
My maven project is a multi module one, which looks like this:
moduleA
|- moduleB1
| |- moduleC
|- moduleB2
|- build-config/rules.xml
Since there is some unwanted updates, like betas I don't want, I've made a filter (which works). I use it like that:
<profile>
<id>maven-version-plugin-1</id>
<activation>
<property>
<name>version.rules.uri</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<configuration>
<rulesUri>${version.rules.uri}</rulesUri>
</configuration>
</plugin>
</plugins>
</build>
</profile>
I am forced to use a profile and a property version.rules.uri because it must refer to an existing file (by default it points to ./build-config/rules.xml, but it is also in my settings.xml with an absolute path).
I'd like to avoid that by:
publishing an independent build-config project
referencing this project using some uri: m2:myGroupId:myArtifactId:version:scope:jar/rules.xml
Now the question: is there an implementation of Maven Wagon Plugin (which is used by maven versions plugin) that allow for reading a repository entry such as a jar ?
This works for me:
<rulesUri>file:///${session.executionRootDirectory}/maven-version-rules.xml</rulesUri>
For the meaning of the variable ${session.executionRootDirectory}, see
Finding the root directory of a multi module maven reactor project.
Based upon the documentation for the plugin this is possible:
You can provide your ruleset xml file also within a jar, if you want to distribute your ruleset xml as Maven artifact. Therefore you have to declare the containing jar as direct dependency of the versions-maven-plugin and to use classpath as protocol.
I just tried it out and got it to work.
Create a new folder for the new version-rules artifact, as so:
version-rules
|- files
\- version-rules.xml
\- pom.xml
The pom.xml is pretty basic:
...
<artifactId>my-version-rules</artifactId>
<packaging>jar</packaging>
<build>
<defaultGoal>package</defaultGoal>
<resources>
<resource>
<directory>files</directory>
<filtering>false</filtering>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
</plugins>
</build>
...
run a mvn install to install this artifact.
Then, in the other pom, you configure the versions plugin as follows:
...
<build>
...
<pluginManagement>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<rulesUri>classpath:///version-rules.xml</rulesUri>
</configuration>
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my-version-rules</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
...
</plugins>
...
</pluginManagement>
...
</build>
...

Categories

Resources