Passing properties to a gradle build - gradle

I admit I am quite new to gradle but I did not expect to be unable to understand something as simple as the example below. I can read the gradle documentation about checking whether a project property have been set or not using a hasProperty(String propertyName) call and I am sitting here and have no idea why something so basic does not work.
I believe my mind must be so much "ant like" oriented that for sure I am missing something ordinary basic
task printSystem() << {
println system
println "has property: " + hasProperty("system")
}
and invoking that task with the command below:
$gradle printSystem -Psystem=mySystem
mySystem
has property: null
So my questions would be:
Why system is printed out but hasProperty returns null?
How should I check for the existence of the project property called "system"?
Is there a different way for testing for a project property as opposed to a system property?
How would you pass a system property from the command line?
This is from, the gradle documentation and I believe I am reading it right
19.2.1. Checking for project properties
You can access a project property in your build script simply by using its name as you would use a variable. If this property does not exist, an exception will be thrown and the build will fail. If your build script relies on optional properties the user might set, perhaps in a gradle.properties file, you need to check for existence before you access them. You can do this by using the method hasProperty('propertyName') which returns true or false.

You need to explicitly invoke hasProperty on the project instance - without it, hasProperty is invoked on some local context. The following example works:
task printSystem() << {
println system
println "has property: " + project.hasProperty("system")
}
Because non-existing properties (system is not defined in the script) are taken from the project instance. If you won't pass the system property, an exception will be thrown on println.
project.hasProperty('propName')
Not sure if I understood right, but you can access project properties via the project instance and system properties via the System class.
Using -D switch - gradle -Dprop=value

Related

How to deactivate the caching of gradle properties?

Depending on the user, a different set of properties are load from a file.
ext.userProps = new Properties(defaults.userProperties)
file("env/configurations/user_${userName}.properties").withInputStream { userProps.load(it) }
User runs the first build -> everything works fine
User changes a property in the file
Runs the build again -> gradle still uses the old properties
Workaround: running gradlew clean after every change to a properties file. Then it works as expected.
How can I tell gradle directly, to not cache the loaded properties?
Edit:
The properties are then used to make string replacements in configuration files.
ext.dbconfig = ""
ext.siteProps = new Properties(defaults.siteProperties)
file("env/configurations/site_${siteName}.properties").withInputStream { siteProps.load(it) }
ext.userProps = new Properties(defaults.userProperties)
file("env/configurations/user_${userName}.properties").withInputStream { userProps.load(it) }
ext.tokens = [
// WEB-INF/web.xml
smtpHostName : "${siteProps.'mail.smtp.host'}".toString(),
smtpPassword : "${siteProps.'mail.smtp.password'}".toString(),
hibernateSchemaCreation : "${userProps.'hibernate.schema.creation'}".toString(),
documentExportMode : "${userProps.'document.exportMode'}".toString(),
multipartConfigLocation : "${siteProps.'multipartConfigLocation'}".toString(),
// META-INF/context.xml">
'hibernate.datasource.url': "${userProps.'hibernate.datasource.url'}".toString(),
'hibernate.dialect' : "${userProps.'hibernate.dialect'}".toString(),
'hibernate.connection.username' : "${userProps.'hibernate.connection.username'}".toString(),
'hibernate.connection.password' : "${userProps.'hibernate.connection.password'}".toString(),
'hibernate.connection.driver.class': "${userProps.'hibernate.connection.driver.class'}".toString(),
]
The problem is that you are using external data to impact the execution result of some tasks, without letting Gradle know. This breaks the up-to-date checking.
Have a look at the documentation on up-to-date checking and in particular the Runtime API which enables you to tell existing Gradle tasks that another input needs to be considered.
Once all inputs are declared properly, changing these properties file will cause Gradle to re-execute the relevant tasks.
So given what you indicated, you most likely want to enhance the processResource task, which will then properly be run whenever a properties file change. That will in cause change the produced jar, which will cause tests to re-run, etc ...

Build Gradle getProperties before running already made task

I’m trying to use a Java, Serenity-BDD project with gradle version 4.8+, but the application is not pulling the CLI arguments of -Denvironment and -Dservicebranches. I have these properties as blank values in my local.properties file, and they’re not getting assigned when my app runs.
./gradlew --build-cache build -Dwebdriver.remote.url=${SELENIUM_REMOTE_URL} -Denvironment=${ENVIRONMENT} -Dservicebranches=${SERVICE_BRANCHES} -Dtags=${TAGS}
I have a local.properties file with properties that are being successfully dependency injected into the project (through Serenity-Spring). I'm hoping that these CLI arguments will override these values:
servicebranches=
environment=local
But right now, anything specified in the CLI arguments are not being passed into the project. Either through DI, or through explicitly grabbing the environment variables in the build.gradle, which what I've tried hasn't been working.
Here's a few things which I have tried in the build.gradle:
//task integrationTests() {
// doFirst
// {
// def environment = System.getProperty('environment')
// def servicebranches = System.getProperty('servicebranches')
// }
// tasks.build.execute()
//}
//integrationTests.dependsOn(build)
//build.doFirst{
// systemProperties System.properties
// def environment = System.properties['environment']
// environment = environment //This actually flags with 'Silly assignment'
//}
build.doFirst{
def environment = System.getProperty('environment')
def servicebranches = System.getProperty('servicebranches')
}
The latest one seems to still be missing a step, because the program is still working, but the args are still not getting through. I've even tried -Denvironment=potato, and no errors have come up because I do not have a property or properties file named that.
I've also tried using the -P tag instead of -D tag, but that doesn't seem to be working either.
All I’m trying to do is use build.gradle to use System.getProperty(‘environment’) and System.getProperty(‘servicebranches’) before I use the already created ‘build’ task that comes with Serenity. How would I do this? Do I build a whole new task, where I use these getProperties, and then call the build task? Do I have to specify the assignment of these same named variables in the local.properties file?
-D is for system properties in Gradle. Try with -P instead (https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)
I know this is a very old question but here's what I did to solve my problem, I got the idea from here: https://github.com/serenity-bdd/serenity-documentation/pull/120/files
Serenity was not pulling the environment from gradle to use EnvironmentSpecificProperties, it kept saying "undefined property for environment 'null" when I removed the default environment. I had to add this to my Gradle file:
test {
systemProperty 'environment', System.properties['environment']
}

How to set multiple properties for Maven on Teamcity

The configuration passes a property to Maven using the "Additional Maven command line parameters" setting for the Maven runner.
This is done with -Darguments='' so the maven-release-plugin can use the arguments on each run as it forks new processes.
For one property the configuration is:
-DsomeProp=%teamcity.agent.name% -Darguments='-DimportantProp=true'
The problem is when passing multiple properties like so:
-DsomeProp=%teamcity.agent.name% -Darguments='-DimportantProp=true -DsecondProp=file_on_disk.name'
For the multiple properties configuration the Build log shows that importantProp gets resolved as true -Dsecondprop=file_on_disk.name which is expectedly an invalid value.
The second property secondProp is then not applied as the string gets absorbed into the value of importantProp.
The reason to do this is to simplify test runs on TeamCity and not to change the poms for each test.
I see hardly any examples for this configuration on TeamCity.
your props differ by -DsecondProp=true. So, you should create only one prop for a pass to build. Let's name mainProp
Also, we need to add new prop which contains empty if not checked or -DsecondProp=true if checked. Create checkbox parameter additionalParam with
checked value - -DsecondProp=true
unchecked value - `` (nothing)
Now we need to add this cb parameter our mainProp.
mainProp = -DsomeProp=%teamcity.agent.name% -Darguments='-DimportantProp=true %additionalParam%'
When you will triggered the build you can check the checkbox and pass -DsomeProp=%teamcity.agent.name% -Darguments='-DimportantProp=true -DsecondProp=true
Applying a configuration parameter to the configuration twice has worked. Thanks for the configuration parmeter suggestion Senior Pomidor.
Create configuration parameter in build parameters or build template %mavenArguments%:
-DpropCheck=true -DpropPath=file_on_disk-1.path
Then apply the supplied configuration parameter in the Additional Maven command line parameters on the Maven build step (works directly on the build step or through build template) like this:
%mavenArguments%
-Darguments='%mavenArguments%'
I still have no idea why it's not applied correctly by writing directly into the Additional Maven command line parameters but it finally works.

How to use variable outside the task in gradle script

I am stuck in a situation where need to read a file (for some values, let's say version number) from inside a war file and use it somewhere else in the same script (I am exploding the war file for this purpose using a Copy task). To explain the need, I will write down with the example below:
Defined the variable:
def projVersion = "NULL"
Exploding the war:
task explodedWar(type: Copy) {
from zipTree("$buildPath/projectName.war")
into file("$buildPath/projectName")
}
Reading the file from exploded folder and getting a value:
task warVersion(dependsOn : ['explodedWar']) <<{
Properties versionFile = new Properties()
versionFile.load(new FileInputStream("$buildPath/projectName/META-INF/MANIFEST.MF"))
ext.projVersion = versionFile.getProperty("Version")
}
When Using the variables new value outside the task (This part is throwing Error):
println "Variables new value: " + warVersion.projVersion
When Using the variables new value inside some other task (This part is Successful):
task VersionPrint(dependsOn : ['warVersion']) <<{
println "Project Version under print task" + warVersion.projVersion
}
Basically, I am able to use the new value of the variable inside any other task in the same script, but when I am trying to use the variables new value outside the task areas (sorry but it's a need), it is throwing error:
Error (When using variable outside the task) ***
* What went wrong:
A problem occurred evaluating root project 'Scripts'.
> Could not find property 'projVersion' on task ':warVersion'
Let me know, Am I trying to achieve something which is achievable? or is it going to be rule breaking way for gradle?
If it is possible what I am searching for, please let me know the solution, how to achieve.
You're not thinking about the build lifecycle correctly.
When you define the warVersion task, which depends on explodedWar, you're telling Gradle that you want to set the property projVersion during the execution of the warVersion task.
This means that you can't attempt to read the property until after the warVersion task is run. Otherwise, it will not be defined. If you attempt to "use the value outside of a task", you're no longer waiting for the warVersion task to run. Code that is outside of the scope of a task will be executed during the configuration phase, not the execution phase.
when I am trying to use the variables new value outside the task areas (sorry but it's a need), it is throwing error:
You need to refactor how you define the projVersion variable.
You could refactor your code so you don't need to use the value outside of tasks.
You could use the new PropertyState API for lazy-evaluated properties.
You could change your logic to execute during the configuration phase.
The last is not ideal as it bypasses task conveniences, such as up-to-date checking. However, you can try it out by changing your copy task to call Project#copy, then read the properties file and declare your properties value, all outside of the scope of tasks:
copy {
from zipTree("$buildPath/projectName.war")
into file("$buildPath/projectName")
}
Properties versionFile = new Properties()
versionFile.load(new FileInputStream("$buildPath/projectName/META-INF/MANIFEST.MF"))
ext.projVersion = versionFile.getProperty("Version")
This code will be executing during the configuration phase. Now, anywhere after this point you should be able to reference ext.projVersion.

TeamCity server url from build script

I heed to use TC API from build script (gradle). I can read user name and password, from project properties, but I have to read serverUrl as well. But I did not find property teamcity.serverUrl described in doc (right there)
May be this property is missed only on our build TC server?
This very parameter is a configuration parameter
Such parameters can be used in web UI, but are not implicitly passed to Gradle build
In your case, use Additional Gradle Command Line Parameters field in build step configuration and add following flag:
-PserverUrl=%teamcity.serverUrl%
This will pass the value explicitly. You can access server url in gradle like this:
println("Server url is $project.serverUrl")
UPD
If customising paramteres is not an option, you can use another way. There is a system property teamcity.configuration.properties.file that contains path to a file, that contains all the configuration parameteres in usual properties format. So, inside Gradle do something like:
def configFilePath = project["teamcity.configuration.properties.file"]
def props = new Properties();
props.load(new File(configFilePath).newDataInputStream())
def serverUrl = props["teamcity.serverUrl"]

Resources