Dear all,
I am starting with Jenkins and the matter of having different
properties for different environments (eg: devel, integration, test
have different database connections) is giving me nightmares.
The different environments we have in our MAVEN project are:
- DEV, for developers' machines, who use Eclipse. Developers run a
jetty server to fire up a development version of the webapp
- DEVTEST. This one is for database JUNIT tests on developers'
machines. Spring loads this environment's database details form a file
(see bellow).
- INTEGRATION. In Jenkins, the database for junit tests is different
- PROD. For production system
Using spring, I followed this approach to managing properties:
http://www.summa-tech.com/blog/2009/04/20/6-tips-for-managing-property-files-with-spring/
I ended up with a Spring configuration like so:
<jee:jndi-lookup jndi-name="java:comp/env/my.env"
id="currentEnvironment"/>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>#{'classpath:/iwrs-' + currentEnvironment +'.properties'}</
value>
</list>
</property>
</bean>
This works fine in containers - namely jetty, our development
container, and Tomcat, our production one. As long as we give the
container the JNDI property, the correct iwrs-ENV.properties file will
be loaded.
However, for junit tests this doesn't work, because junit tests
running in eclipse or tests running in a maven goal are not run inside
a JNDI-enabled container. And the problem is that we essentially need
two files, an iwrs-DEVTEST.properties for developers and an iwrs-
INTEGRATION.properties in Jenkins.
I then tried to use environment variables to sort this out. The Spring
file being picked up in tests has:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/iwrs-${env.nameWTF}*.properties
</value>
</list>
</property>
In Eclipse, I changed the installed JRE's properties to add -
DnameWTF=DEVTEST. I was hoping that in Jenkins all I needed was to add
a String parameter to the build nmaed nameWTF and set it to
INTEGRATION to make it work.
I was out of luck. This property isn't being picked up by Jenkins'
maven run. It fails spectacularly with:
Caused by:
org.springframework.beans.factory.BeanDefinitionStoreException:
Invalid bean definition with name 'sessionFactory' defined in class
path resource [hibernate/spring-SF.xml]: Could not resolve placeholder
'hibernate.exposeTransactionAwareSessionFactory'
This is a property I set in the .properties file, so it isn't picking
my property up. What is strange is that, while it doesn't seem to be
picking the properties file, after the failing log I read:
[INFO] Executing tasks
[echo] ECHO XXX Displaying 3 environment variables
[echo] [BAR] ${
env.name}
[echo] [WTF] INTEGRATION
Which comes from the following Maven snippet:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>ECHO XXX Displaying 3 environment variables</echo>
<echo>[BAR] ${
env.name}</echo>
<echo>[WTF] ${env.nameWTF}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
As you see in ${env.nameWTF}, this is the environment variable, so it
has been set correctly.
Do you have any idea where the problem might be? Do you have any
suggestion regarding a better way to use .properties files, spring,
maven in multiple environments?
Any help appreciated. I feel completely lost in my quest for making CI
work.
Regards,
Miguel Almeida