Assume I have a description in a file and I want to use the file contents for setting a property in Gradle. What I'm currently doing is something like that
String myChangeNotes = file('resources/META-INF/change-notes.html').text
String myDescription = file('resources/META-INF/description.html').text
patchPluginXml {
changeNotes = myChangeNotes
pluginDescription = myDescription
}
It works, but it does not reload the file when it changes. I guess I have to make a task that has as input the two HTML files so that Gradle knows when they change, but I'm not sure how to proceed.
How would I do it so that the changeNotes and pluginDescription properties of patchPluginXml are reloaded each time the files change on disk?
You already have a task that has the contents of the files as input. As you read the files in the configuration phase, they are always read freshly when you start your build. The changeNotes and pluginDescription fields of the patchPluginXml task (if we talk about the gradle-intellij plugin) are defined as inputs, so if their value changes, the task will be re-run. So everything seems to be set up correctly.
Related
I am currently working with a project (using gradle) that needs a properties file in the same package to the class that consumes it (I can't change this config). I have added the file in my package, but when I execute the gradle build command omits the file, and only adds the .class file. The app is deployed as a war file.
I have tried editing the war task, but I can't find the way to make the properties file to be added:
war {
from('src/main/com/foo/bar') {
include 'b.properties'
into 'WEB-INF/classes/com/foo/bar'
}
}
The war task does execute (I have added a prinln and it executes). Also, I have tried changing the paths, but no results. Also replacing from('path') to from (file('path')), but still doesn't seem to add the file anywhere.
How should I achieve this? Thanks!
Is there anything stopping you from following Gradle's convention for resources?
Eg put your property file at src/main/resources/com/foo/bar/b.properties
If you do this you won't need any task customisations
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 ...
In an attempt to follow the doc, I added a task like this to my build.gradle file:
task createStartScripts(type: CreateStartScripts) {
applicationName = 'dc-coverage-calculator'
}
I then executed
./gradlew clean installDist
at which point I expected to find a file at build/install/dc-coverage-calculator/bin/dc-coverage-calculator, but no files with dc-coverage-calculator were created anywhere the build folder. Instead, gradle continued to use the default application name, based on the mainClassName.
I also tried removing the hyphens from the app name.
Unfortunately it doesn't work this way. You've added a new task whereas yo need to modify the existing one, which will be done this way:
startScripts {
applicationName = 'dc-coverage-calculator'
}
Grab a demo here.
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.
I have task which generates picture, so I want to write test for it that compares this picture binary with picture previously generated in the resource folder.
def setupSpec() {
project = ProjectBuilder.builder().build()
generatePicTask = project.tasks.create(SomePlugin.GENERATE_PIC_TASK_NAME, GeneratePicTask)
}
def 'create Picture test'() {
when:
File fileName = new File("Info")
then:
generatePicTask.createPicture(fileName)
expect:
fileName.exists()==true
}
But there is error that
C:\Users\User\AppData\Local\Temp\gradle1393280218367058727projectDir\build\Info.PNG
(The system cannot find the path specified)
The picture is generated in the the action closure in the task generatePicTask.
The project object is dummy project so I don't know even it was executed. How I can fix this?
I see 3 problems with your current approach:
Your test shouldn't rely on the current working directory. Therefore instead of creating a file like this:
File fileName = new File("Info")
use a junit TemporaryFolder rule for example. have a look at
with using e.g. http://garygregory.wordpress.com/2010/01/20/junit-tip-use-rules-to-manage-temporary-files-and-folders/ for more details
It seems GeneratePicTask task not generate the 'build' directory
Ensure that the output directory (the parent folder of the created image exists). You can use gradle annotations e.g. #OuputDirectory to let gradle take care of that. otherwise before generating your image do something like 'fileName.parentfile.mkdirs'
In general the way to go is to split the configuration of your task and task execution:
generatePicTask.setPicture(fileName)
generatePicTask.create() // your #TaskAction annotated method
cheers,
René