1

Is there any way to execute the environment variables file .env along with maven commands such as mvn clean install or mvn clean deploy. The main idea behind the concept that I'm looking for similar kind of solution:

mvn clean install -DenvFile=/path/<filename>.env

OR

mvn clean deploy -DenvFile=/path/<filename>.env

OR

mvn clean package -DenvFile=/path/<filename>.env

Note: Not trying to produce the environment specific builds. In dev environment, my intention to run the junit tests with all the environment variables configured from <filename>.env.

where, the above maven commands should set all the environment variables from <filename>.env and then execute the maven plugins. In IntelliJ, there's a envFile plugin which exactly do the same.

Don't want to have environment specific properties dev|staging|prod.properties in my project because it's messy and hard to manage. I'd rather prefer to have one single environment specific file filename.env which contains all the dynamic/changeable properties.

application.properties

spring:
  cloud:
    config:
      uri: http://config-service:${CONFIG_SERVICE_PORT}
      fail-fast: true
      password: ${CONFIG_SERVICE_PASSWORD}
      username: user

Environment File: .env

CONFIG_SERVICE_PORT=8080
CONFIG_SERVICE_PASSWORD=123

Now when I deploy the application in different environments like AWS, GCP and Azure. All I need to change the environment variables in the .env file and run the application java -DenvFile=/path/<fileName>.env -jar application.jar and it will do the magic.

My problem is related with maven-sure-fire plugin for testing in dev-mode, which require these environments variables for spring context.

Any help would be appreciated.

Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
Deminem
  • 672
  • 8
  • 19
  • 2
    Why making a build environment specific? Maven ideally should run the same regardless the environment you're running in. How will plugins benefit from environment variables like this? Could you show a use case? And the last question - how is "spring-boot-maven-plugin" related to the question? Do you have some concrete use case in mind for it? – Mark Bramnik Apr 20 '20 at 10:54
  • @MarkBramnik - Not trying to make build environment specific. Please don't confuse yourself with maven `install/deploy/package` commands. The intention behind here, to keep all the dynamic/changeable properties at one place .env. So even if I run the application in different environments like `java -DenvFile=/path/.env -jar application.jar` the application will pick up all the properties and run accordingly. All I just need to change .env for different environments to run my application. – Deminem Apr 20 '20 at 13:25
  • @MarkBramnik - With maven the problem lies in junit testing, when you run the maven commands like highlighted above `install/deploy/package` it basically execute the unit/integration tests and those read the values from .properties. I don't want to have environment specific `application-.properties` in my project, because it's messy. I believe the good approach would be to keep one single `environmentVariables.env` file and change the properties according to specific environments for application installation or deployment. – Deminem Apr 20 '20 at 13:38
  • @MarkBramnik - Do you have any thoughts around this issue? [here](https://stackoverflow.com/questions/61341341/embedded-mongodb-not-picked-up-for-application-test). – Deminem Apr 21 '20 at 13:26

1 Answers1

1

Ok from your comments it seems like you're looks for two different solutions:

  1. Run the application in different environments with java -DenvFile=/path/<fileName>.env -jar application.jar
  2. Solution for running tests.

These are different issues I'll try to address both

Issue 1

When you run java -jar this means that the artifact is already assembled (with the help of spring boot maven plugin as far as I understand). This jar is a ready to go spring boot application and maven is basically irrelevant here - maven is a build system, spring is a runtime framework and we're talking about the runtime.

Spring boot has a lot of ways to achieve what you want. A "Native" spring boot way which is close to your situation is running the application with "--spring.config.location=file:// with all the required configurations

It looks like this (see here for complete documentation):

java -jar application.jar --spring.config.location=myprops.properties

Even if you have some properties defined in src/main/resources/application.properties this method allows to override them effectively providing a way to run different configurations in different environments.

This has an advantage over the .env files because it can run in the same way in all the OS-es, even Windows ;) Since Java is OS independent - I believe its the best you can achieve.

Of course you can wrap the java -jar line in some kind of bash script and load / execute a series of export commands before running the jvm, but again, its less "spring-y" way.

Issue 2

Maven runs the tests (unit/integration) in a way that spring boot maven plugin is irrelevant. Its all about surefire/failsafe and spring boot testing framework.

I'll assume you're asking about integration tests because I believe this is all irrelevant for unit tests, since those should not require any environment variables at all and should be run without spring at all (junit/mockito should do the job)

I'll also allow myself to keep the assumption that the way of overriding/configuring the spring boot application via yaml or properties file is better than .env and will provide spring test configuration solution here:

With these assumptions you can create a yaml file in the following path: src/test/resources/application-test.yml

This file can contain configurations relevant for tests and will override anything written in src/main/resources/application.yml. Note, since application-test.yml resides in test sources, spring boot maven plugin won't package it into the application.

Depending on the exact way of doing integration tests you might consider also using @TestPropertySource annotation to provide the custom properties/yaml file that doesn't follow spring boot's default convention. Its especially useful for spring driven tests that do not bootstrap with the spring boot full fledged support (read the tests that use junit's spring runner but don't have annotation @SpringBootTest)

Another possibly useful annotation is @ActiveProfile("myprofile"). This will cause spring boot tests to automatically load file src/test/resources/application-myprofile.yml (or application-myprofile.properties)

Last but not least I'll refer the second comment with "dev/prod/staging/properties" in the source. When it comes to tests - there should be only one file application-test.yml. However note that when you're using yaml, its possible to define configurations for many spring boot profiles in the same file:

# default value
foo:
 bar: 1

---
spring:
  profiles: staging
foo:
  bar: 2

--- 
spring:
  profiles: prod
foo:
  bar: 3

Some relevant SO thread

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Thanks for providing the valuable information. Accepting it as the answer, because it helped me to fix my integration test. I was missing the `@TestPropertySource` that's why the `application-test.properties` with `@ActiveProfile("test")` was not picked up for integration tests. – Deminem Apr 21 '20 at 12:42
  • Do you have any thoughts on this issue? [here](https://stackoverflow.com/questions/61341341/embedded-mongodb-not-picked-up-for-application-test). – Deminem Apr 21 '20 at 13:23
  • I think it depends on how exactly the test is written, whether you have @SpringBootTest annotation or not, and if you do with which properties this annotation is configured. If you want - feel free to ask another question (its a different topic really) and provide a link here - I'll try to do my best to answer as the time permits – Mark Bramnik Apr 21 '20 at 13:39
  • I have created a new question and posted the link in my previous comment. I'm puzzled with `Spring Data` mongoDb properties for integration test, I want to run embedded mongoDb against integration test with different configurations. And this is working, the embedded mongoDb start with it's configuration from `TestConfig` class. And placed `@DataMongoTest(excludeAutoConfiguration= {EmbeddedMongoAutoConfiguration.class}) which means it should not read `Spring Data` configurations for mongoDb from `application-test.properties`. But unfortunately, this is not happening here. – Deminem Apr 21 '20 at 17:39