Gradle multi project, scope task - gradle

I have a multi project in the following way:
rootProject
Subproject1
Subproject2
task whatever << {
println "WHATEVER"
}
I want to be able to configure task 'whatever' once and execute it from any scope (root or subproject) and be executed only once!
This means:
If I run /gradle whatever, I should get: "WHATEVER"
If I run /subproject1/gradle whatever, I should get: "WHATEVER"
In summary, I don't what to execute the same task several tasks according to the number of projects.
I haven't been able to get such a simple result. Please let me know if you can offer any help! Thanks!

gradle whatever searches for whatever in the current subproject and below. Instead, use gradle :whatever and declare the task in the root project.

Related

I can't find the declaration of a Gradle task

My build.gradle looks like this:
println 'First top level script element'
task first {
println 'First task: Configuration'
doLast {
println 'First task: Action'
}
}
task second(dependsOn: first) {
println 'Second task: Configuration'
doLast {
println 'Second task: Action'
}
}
println 'Second top level script element'
Following my tutorial, I got the following exercises:
Execute the help task and observe the output.
Execute the first task and observe the output.
Execute the second task and observe the output.
Now, I executed:
$ gradle help
And it works. But how can it be if the task help is not declared anywhere?
Am I looking at the correct file at all?
Gradle provides a set of tasks out of the box, including a help task. You may use gradle tasks --all to get a list of all tasks available to your project. This will be particularly useful once you apply plugins to your build script, because those plugins may create tasks implicitly. For a lot of use cases, is it not even necessary at all to manually create tasks. As an example, the following minimal build script provides all you need to build Java projects:
plugins {
id 'java'
}
You may even run gradle tasks in an empty folder (without an build.gradle file) and Gradle will still offer you its default tasks, as it will automatically create a project based on an empty build.gradle file.

Gradle task is broken - cannot execute

import org.apache.tools.ant.filters.ReplaceTokens
task genScript(type:Copy){
copy{
from "../../scripts/script.txt"
into projectDir
filter ReplaceTokens, tokens: [baseName: jar.baseName, version: jar.version, prefix: 'x']
}
}
jar.doLast{
tasks.genScript.execute()
}
genScript executes fine if I just click on it and run. But when I do ..\gradlew clean jar, it gives me the following error:
Could not find method execute() for arguments [] on task ':myModule:genScript' of type org.gradle.api.tasks.Copy.
How to fix it?
I am using Gradle 6.0.1.
You can't programatically execute tasks from other tasks in newer versions of Gradle. Instead, you are supposed to declare task dependencies and Gradle will ensure they get executed in the correct order.
The quick fix is just to make jar depend on your task like this:
jar.dependsOn('genScript')
Alternatively, you could move your logic into the doLast block in the jar task.

Create task for dependency lock in Gradle >5.0

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.

How to call a Gradle subproject’s task from a Gradle test?

I have a project that includes a subproject like so:
Root Project
|----gradle.build
|----SubProject
|----|----gradle.build
The SubProject here contains a copy script that I need called when the root project’s test command is called.
So I have attempted to call the SubProject’s task in the Root project like this:
Task myTest(type: Test) {
Project(‘:SubProject’).tasks.myCopyTask.execut()
}
However, this results in an error, “Could not get unknown property ‘myCopyTask’ for task set.”
Do you know how this call should be done, and what the proper syntax should be?
There a multiple things not working in your example:
You should never call execute on tasks! NEVER! Tasks are called by Gradles task system automatically and calling execute may break this system.
The closure ({ }) you use when creating a task is for configuration. It is not executed when the task gets executed, but when it is created.
Subprojects in Gradle are created and evaluated after the root project is created and evaluated. So tasks from subprojects do not even exist when the root project gets evaluated.
You can solve all these problems by using the dependsOn method with absolute task paths:
task myTest (type: Test) {
dependsOn ':Subproject:myCopyTask'
}

Determine if a task is defined in an external build.gradle file

I have a gradle task that is created at runtime to call another task ("myOtherTask") which is in a separate gradle file. The problem is if that other task doesn't exist an exception will be thrown. Is it possible to check that a task exists in an external gradle file before attempting to call it?
Example:
task mainTaskBlah(dependsOn: ':setupThings')
task setupThings(){
//...
createMyOtherTask(/*...*/)
//...
}
def createMyOtherTask(projName, appGradleDir) {
def taskName = projName + 'blahTest'
task "$taskName"(type: GradleBuild) {
buildFile = appGradleDir + '/build.gradle'
dir = appGradleDir
tasks = ['myOtherTask']
}
mainTaskBlah.dependsOn "$taskName"
}
You can check if the tasks exists. For example if we wanted to simulate this we could make the task creation triggered by a command line property
apply plugin: "groovy"
group = 'com.jbirdvegas.q41227870'
version = '0.1'
repositories {
jcenter()
}
dependencies {
compile localGroovy()
}
// if user supplied our parameter (superman) then add the task
// simulates if the project has or doesn't have the task
if (project.hasProperty('superman')) {
// create task like normal
project.tasks.create('superman', GradleBuild) {
println "SUPERMAN!!!!"
buildFile = project.projectDir.absolutePath + '/build.gradle'
dir = project.projectDir.absolutePath
tasks = ['myOtherTask']
}
}
// check if the task we are interested in exists on the current project
if (project.tasks.findByName('superman')) {
// task superman exists here we do whatever work we need to do
// when the task is present
def supermanTask = project.tasks.findByName('superman')
project.tasks.findByName('classes').dependsOn supermanTask
} else {
// here we do the work needed if the task is missing
println "Superman not yet added"
}
Then we can see both uses cases rather easily
$ ./gradlew -q build -Psuperman
SUPERMAN!!!!
$ ./gradlew -q build
Superman not yet added
This won't help you find if the task is in a specific external file, but if you just want to determine if a task is defined in any of your imported gradle files...
From gradlew help I see there is a tasks task.
Sadly, gradlew tasks doesn't always show all taks. Some of my projects have an integrationTest task while others do not, in which case I can only go as far as build. However, the default tasks command lists integrationTestClasses but not integrationTest.
From gradlew help --task tasks I can see there is a report expanding --all parameter that we can use.
Now, I can see all tasks via gradlew tasks --all, so a simple grep can tell me whether or not the task I want exists. In bash, this might look like:
TASK="integrationTest"
if gradlew tasks --all | grep -qw "^$TASK"
then
gradlew clean integrationTest
else
gradlew clean build
fi
FYI --
Personally, I needed something to tell me in a git pre-commit hook whether the integrationTest task existed or not, so I know whether I can run gradlew integrationTest or if I have to stop at gradlew build. Not finding an answer here, I kept looking, and this is what I came up with to solve my problem. Hopefully, this is of use to others as well.
I made a little "tool" for stuff like that - maybe it comes in handy for some of you...
$ cat if_gradle_task_exists
#!/bin/sh
TASKS=$(./gradlew tasks --all)
BUILD="./gradlew "
for COMMAND in $#; do
echo "$TASKS" | grep -q "$COMMAND" && BUILD="$BUILD $COMMAND"
done
$BUILD
You can append as many tasks as you like and only the existing ones are executed.
I use it in combination with alias as a kind of super api wrapper for tasks I want to be done in different projects (and I don't want to have to care if any of the specific tasks really do exist):
alias ge='~/.config/bin/if_gradle_task_exists eclipse initDb createTestUsers startLdapServerMock startBrokerMock'
That allows me to be as lazy as ge
stumpf#HV000408:/c/devel/workspace/myproject $> ge
to set up the project for eclipse and prepare all needed servers for local development.
The list of tasks produced will need some time to be set-up, so I wouldn't recommend to use it as a full gradlew wrapper though.
Regards

Resources