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());
}
Related
I am trying to do something like this:
jar {
doLast{
from "build/libs/TheJar.jar"
into "."
}
}
So far, I have tried various tutorials including all forms from this answer but non have worked. The only thing that works is calling a separate task but I'd like to know why my construction is wrong and why can't I run something after the jar or shadowJar tasks.
It looks like you took some parts of the answers in the linked post and somehow mixed them without knowing what your final code actually does.
Tasks in Gradle may have a type (e.g. Copy, Jar, ...). This type defines what the task will do once it gets executed (so called task actions). A task without a type won't do anything when its executed, unless you add task actions manually. Using doFirst will add the passed action (also called closure) to the start of the list of task actions, using doLast will add it to the end of the list.
Everything outside of doFirst and doLast closures is not part of the execution of the task, but can be used to configure the task:
task example {
doLast {
println "second action"
}
doFirst {
println "first action"
}
println "configuration"
}
Run the code above with gradle example and you will see the order of the log messages as configuration, first action, second action.
Task configuration will run, even if the task won't be executed later on. Even if you call gradle (without any task names as arguments), the console will still print configuration. This was the actual problem in the linked question.
Lets come to the real question: How to copy a file?
Well, Gradle offers two ways to copy a file. The first one is the task type Copy. You can create a task based on this type, apply your configuration and then either call it directly from the command line or define task dependencies using dependsOn or finalizedBy:
task copySomeFiles(type: Copy) {
from '...'
into '...'
}
However, you don't want to create an additional task. Gradle also has a method called copy that may be called anywhere in your script and will instantly copy the files:
copy {
from '...'
into '...'
}
The code above will copy your files, but it will copy your files every time Gradle executes (which may be often, e.g. when using an IDE). To solve this problem, you may move your code with copy to a task action, e.g. inside a doFirst or doLast closure:
jar {
doLast {
copy {
from "build/libs/TheJar.jar"
into "."
}
}
}
As you can see, your code was missing the copy statement. Now, whenever your task jar gets executed, its last task action will copy the files as intended.
Bonus question: Why is there no error?
The "problem" in your case is that your code is perfectly valid Gradle code. The task jar is of type Jar. Every task of type Jar may be configured using methods called from and into. The method from adds files to the JAR file and the method into sets the destination directory inside the JAR. So instead of copying, your code configures the underlying task jar. However, this has no negative consequences, as this configuration gets applied inside doLast, which only runs once the JAR file has already been created. Something that already happened cannot be configured.
I want to create a task which to execute
dependencies --update-locks ':'
I had a configuration:
dependencyLocking {
lockAllConfigurations()
}
I try with
task lockDependencies {
dependsOn = ['dependencies','--update-locks *:*']
}
But have:
What went wrong: Could not determine the dependencies of task ':lockDependencies'.
Task with path '--update-locks :' not found in root project
You cannot pass Gradle command line parameters as a task dependency, that's what your error above is about.
The state of writing locks, either with --write-locks or --update-locks, is something that happens really early in the build lifecycle.
You can somewhat control it from a task with the following:
* Create a placeholder task in your build script
* In the settings.gradle(.kts) query the requested tasks from the command line, and if it is there, mutate the start parameters:
if (startParameter.taskNames.contains('placeHolder')) {
startParameter.setWriteDependencyLocks(true)
}
Note that this is not an option if you are trying to lock the classpath of the build itself, which is one of the motivations behind using a command line flag.
Note also that this just allows replacing a flag, like --update-locks *:* with a task invocation like updateLocks but will not work if that task is wired as a dependency of other tasks, as it needs to be requested explicitly. And doing the start parameter mutation after the task graph is computed is too late in the lifecycle.
The best way to do this in my opinion is to add inside the build.gradle file the following code:
dependencyLocking {
lockAllConfigurations()
}
task commitLockDependencies {
'git add /gradle/dependency-locks '.execute()
}
init {
dependsOn('commitLockDependencies')
}
And then inside the settings.gradle the following line:
startParameter.setWriteDependencyLocks(true)
Working with gradle 7.1.
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 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 writing a custom plugin that contains a copy task. The task is supposed to fetch either a wsdl file or a zip containing wsdl and xsds from a maven repository. In the case of the zip file it will use ziptree to expand the files.
When this is done, another task will use wsimport to create a client jar from these files.
My current attempt is to use a plugin boolean property to differentiate. The following code is what I'm trying to achieve:
void addTasks(Project project) {
project.task('downloadWSDL', type: Copy) {
if (project.wsimport.zipped) {
from { project.configurations.wsdl.collect { project.zipTree(it) }}
into { project.wsimport.wsdlDir }
} else {
from { project.configurations.wsdl }
into { project.wsimport.wsdlDir }
}
}
}
The problem here is that project.wsimport.zipped is not set (I suppose false) in the configuration phase. I have tried to put it in a closure, but it seems to then still do the zipped path even though the property is set to false.
How can I configure a task like this based on a condition?
Will a working solution function as expected when checking if it is up-to-date?
I have thought an alternative approach might be to have 2 different tasks and modify the dependsOn of a depending class dynamically, but I suspect it will run into a similar problem.
Thank you.