Search code examples
mavenenvironment-variablesmaven-pluginspring-boot-maven-plugin

Maven install command with environment variables file


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.


Solution

  • 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