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é
Related
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 created plugin that is supposed to have Input on Output directory, to run when any of these two changes. When I defined it in build.gradle for single task, it worked fine. When defined in Java by Gradle API, only directory defined as Inputs triggers the re-run of task.
task.getInputs().dir(target.file("./src/main/res/values/"));
task.getOutputs().dir(target.file("./inputs/"));
Tried setting setDidWork(true); but that did not help. And any change in output does not trigger change in UP-TO-DATE status of this task.
I used annotations on task class, that are called in correct time and work.
#OutputDirectory
public File getOutputDir() {
return getProject().getRootProject().file(extension.getOutputPath());
}
#InputDirectory
public File getInputsDir() {
return getProject().getRootProject().file(extension.getPath());
}
I want to run multiple soapui projects in Gradle script. The SOAPUI project files are kept is following location:
d:/soapui/projects/path/a.xml, b.xml etc
Will be there any Gradle script that it will enter into the above mentioned location and execute the each project one by one using testrunner.bat
As #RaGe comments you can use the gradle SOAPUI plugin. However if you're looking for a more custom way you can proceed as follows.
You can generate a task on Gradle to execute testrunner to run your SOAPUI projects. Then you can create dynamically one task for each project you've in a directory path, and using .depends you can make that all these dynamic generated tasks are called when you call the specific task.
Your build.gradle could be something like:
// task to execute testrunner
class SoapUITask extends Exec {
String soapUIExecutable = '/SOAPUI_HOME/bin/testrunner.bat'
String soapUIArgs = ''
public SoapUITask(){
super()
this.setExecutable(soapUIExecutable)
}
public void setSoapUIArgs(String soapUIArgs) {
this.args = "$soapUIArgs".trim().split(" ") as List
}
}
// empty task wich has depends to execute the
// ohter tasks
task executeSOAPUI(){
}
// get the path where are your projects
def projectsDir = new File(project.properties['soapuiProjectsPath'])
// create tasks dynamically for each project file
projectsDir.eachFile{ file ->
if(file.name.contains('.xml')){
// create the tasks
task "executeSOAPUI${file.name}"(type: SoapUITask){
println "execute project ${file.name}"
soapUIArgs = ' "' + file.getAbsolutePath() +'"'
}
// make the depends to avoid invoke each task one by one
executeSOAPUI.dependsOn "executeSOAPUI${file.name}"
}
}
To invoke this you can do it using the follow command:
gradle executeSOAPUI -PsoapuiProjectsPath=d:/soapui/projects/path/
Note that -P is used to pass the parameter for projects dir.
Recently I wrote an answer on how to write gradle task to run SOAPUI which can be also util, if you want check more details here.
Hope this helps,
I am trying to build a gradle plugin, which does the following:
As part of one its tasks, it creates a new configuration
It adds a DefaultExternalModuleDependency to this configuration - more specifically, it constructs a dependency to the application server zip file (available on Nexus). This information can be overridden by the invoking project as well.
Tries to resolve this newly added dependency and then unpacks the file to a local folder
All of this was working well when I had the details hard coded in a build file, but it looks like adding dependencies as part of a task are not treated the same way as having that information available at the parsing time.
So my question is, how do I get the project to reload the configurations / dependencies?
The code looks like the following:
#TaskAction
void installAppserver() {
Dependency dependency = new DefaultExternalModuleDependency(group,name,version)
Configuration configuration = project.configurations.detachedConfiguration(dependency)
configuration.setTransitive(false)
configuration.files.each { file ->
if (file.isFile() && file.name.endsWith('.zip')) {
println 'Attempting to unzip: ' + file + ' into folder: ' + appServerFolder
new Copy().from(project.zipTree(file)).into(appServerFolder).execute()
}
}
}
The problem is that the actual artifacts are not getting resolved!
A task can't configure the build model (that's what plugins do). It's fine to create and resolve a detached configuration in a task. If this doesn't work, there is likely a problem with the task's code, or the dependency it tries to resolve. Note that dependencies can only be resolved if the correct repository(s) are defined.
Instead of new DetaultExternalModuleDependency() (which is an internal class), project.dependencies.create() should be used. Instead of new Copy().execute() (Task#execute must not be called from user code), project.copy should be used.