What is the syntax for a gradle subproject task depending on a parent project's task? - gradle

I need some help with a Gradle build file. I have some subprojects which depend on tasks in the top folder. I just need to take a test task and split it into two separate test tasks. Currently the file system structure looks like (tab indicates files inside a directory):
top-level-project-folder
A.gradle
B.gradle
C-subproject-folder
C.gradle
D-subproject-folder
D.gradle
Contents of A.gradle (before refactor):
subprojects {
tasks.test.dependsOn {
bTask
}
}
apply from: 'B.gradle'
Contents of C.gradle (before refactor):
test {
...
}
After the refactor, C.gradle needs to look like:
test {
...
}
task runDifferentTests(type : Test) {
...
}
The tricky part is that C.gradle's test task currently depends on bTask. However, after the refactor, C.gradle's test task should not depend on bTask, but the new runDifferentTests task should depend on bTask. (Currently, D.gradle's test task is marked as depending on bTask, but it does not actually depend on it -- I'd like to remove that dependency. The only task in the two subprojects which depends on bTask is the new runDifferentTests task.)
I've tried some different things but can't seem to find a working solution.

Just remove the declaration in subprojects and declare your dependency directly in the subproject, in C.gradle:
runDifferentTests.dependsOn rootProject.bTask

There are a few syntax solutions here:
runDifferentTests.dependsOn (":bTask")
runDifferentTests.dependsOn rootProject.bTask
task runDifferentTests(type : Test, dependsOn: [":bTask"]) {
...
}
task runDifferentTests(type : Test) {
dependsOn rootProject.bTask
...
}
//in the root build.gradle to apply to all subprojects at once.
subprojects {
runDifferentTests.dependsOn (":bTask")
}
runDifferentTests.dependsOn {
tasks.findAll { task -> task.name.startsWith('bTask') }
}
: can be used to go a level up instead of rootProject depends on the preference and the project structure

Related

How to include/exclude junit5 tags in gradle cmd?

I want to execute tagged JUnit 5 tests, eg. only slow tests, with gradle.
I want to do the same like this in maven:
mvn test -Dgroups="slow"
But what is the equivalent in gradle? Or is there anything at all?
To execute all JUnit 5 tests which are marked with #Tag("slow"). I know it's quite simple to create a dedicated task like this:
tasks.withType(Test::class.java).configureEach {
useJUnitPlatform() {
includeTags("slow")
}
}
But I have a lot of different tags and I don't want to have a task for each single tag. Or worse, having one task for all permutations.
Another possibility would be to pass self defined properties to the task like this
tasks.withType(Test::class.java).configureEach {
val includeTagsList = System.getProperty("includeTags", "")!!.split(",")
.map { it.trim() }
.filter { it.isNotBlank() }
if (includeTagsList.isNotEmpty()) {
includeTags(*includeTagsList.toTypedArray())
}
}
The last time I checked, Gradle didn't have built-in support for configuring JUnit Platform include and exclude tags via the command line, so you'll have to go with your second approach.
But... there's no need to split, map, and filter the tags: just use a tag expression instead: https://junit.org/junit5/docs/current/user-guide/#running-tests-tag-expressions
You can create a separate task and to choose do you want to run the task or to skip it.
For example add this code in build.gradle:
def slowTests= tasks.register("slowTests", Test) {
useJUnitPlatform {
includeTags "slow"
}
}
Now if you want to run only slow tests:
./gradlew clean build -x test slowTests

Set the properties in the configuration phase of a task in another task

I have spent the last few hours trying to find a solution for my requirement, without luck:
I have a task that has to run some logic in a certain path:
task run(type: MyPlugin) {
pathForPlugin = myPath //Defined as a property in another gradle file
}
I want to set the "pathForPlugin" property dynamically in another task because it has to be read from some configuration file.
task initPaths(type: PathFinder) {
configurationFile = 'C:\\myConfig.conf'
}
The myConfig.conf would look like this:
pathForPlugin = 'C:\\Correct\\Path'
The problem is that "initPaths" has to run before the configuration phase of "run".
I have tried several approaches for this (GradleBuild task, dependsOn, Using Properties in the Plugin for "Lazy Configuration") but every approach only takes effect in the Execution phase leading to the "pathForPlugin" always staying at its default value.
Is there some way i can realize this or should i look for another solution outside of the gradle build?
I found a solution for the problem:
Instead of defining a task "initPaths" i directly used the java class "Pathfinder" in the build script:
import mypackage.PathFinder;
new PathFinder(project).run()
You only have to make sure that this part is above the definition of the task where the properties are used.
I admit this is a bit of a "hacky" solution but it works fine for my requirement.
you can do like this:
ext {
myPath //use it as a global variable that you can set and get from different gradle tasks and files
}
task firstTask {
doLast {
ext.myPath = "your path"
}
}
task run(type: MyPlugin) {
doFirst { //executed on runtime not on task definition
pathForPlugin = ext.myPath //Defined as a property in another gradle file
}
}
//example 2 - create run task dynamic
task initPath {
doLast {
tasks.create(name: "run", type: MyPlugin) {
pathForPlugin = ext.myPath
}
}
}

Using `dependsOn` from within a custom plugin, Gradle

Possible duplicate: How to write dependsOn in Custom plugin
I've got a custom Gradle plugin with two tasks, A and B. I declare the two tasks like this in my plugin:
project.task('A') << {
....
}
project.task('B') << {
....
}
How can I make task B dependOn task A? Usually you can say task myTask(dependsOn: 'myOtherTask'), but the syntax requirements for working within a plugin don't seem to allow this type of dependency declaration.
project.task('B', dependsOn: project.property('A')) ) << {
....
}

gradle tar include nested files at top level

In gradle (1.9), I have multiple subprojects. Each one uses the application plugin to create a tar and cli. I am trying to get all these tars into a unified tar, but I am having a lot of trouble.
Here is the tar format I am looking for:
${project.name}/${subproject.name}.tar
I have tried using both the Tar task and the distribution plugin, but for each one, I am not able to find a clean way to just get the generated tars (or any tar), and put them at top level, excluding everything else.
Here is a sample using the distirbution pluging, but its not giving the output I like
apply plugin: 'distribution'
distributions {
testing {
contents {
from(".")
exclude "*src*"
exclude "*idea*"
exclude "*.jar"
exclude ".MF"
filesMatching("**/build/distributions/*.tar") {
if(file.name == "${project.name}-testing.tar") {
exclude()
} else {
name file.name
}
}
}
}
}
Here is what I would like (but not working):
apply plugin: 'distribution'
distributions {
testing {
contents {
include "**/*.tar" // shows up at top level
}
}
}
EDIT:
Getting closer.
distributions {
testing {
contents {
from subprojects.buildDir
includeEmptyDirs false
include "**/*.tar"
exclude "**/${project.name}-testing.tar"
}
}
}
This will give me ${project.name}/distribution/${subproject.name}.tar
Here is the solution for your problem. Put the following to the root project:
task distTar(type: Tar) {
destinationDir = new File("$buildDir/distributions")
baseName = 'unifiedTar'
}
subprojects {
// definitions common to subprojects...
afterEvaluate {
def distTar = tasks.findByName('distTar')
if(distTar) {
rootProject.distTar.dependsOn distTar
rootProject.distTar.inputs.file distTar.archivePath
rootProject.distTar.from distTar.archivePath
}
}
}
then invoke "build distTar" on the root project - it will assemble "unifiedTar.tar" in "build/distributions" subfolder (of the root project).
How it works:
"task distTar(...)" declares a new task of type Tar in the root project.
"subprojects" applies the specified closure to each subproject.
"afterEvaluate" ensures that the specified closure is called AFTER the current project (in this case subproject) is evaluated. This is very important, because we are going to use properties of the subproject which are defined only after it's evaluation.
"tasks.findByName" allows us to determine, whether the given task is defined for given project. If not, it returns null and the following code is not performed. This way we stay agnostic regarding the nature of the subproject.
"dependsOn" ensures that distTar of the root project depends on distTar of the given project (and, therefore, is executed later than it).
"inputs.file" ensures that distTar on root project is not executed, if none of the constituent tars has changed.
"from" adds constituent tar to unified tar.

Moving built-in gradle tasks work to doLast/built-in tasks shourtcuts

I want to create a simple sync task that slightly change it behaviour depending on build type (e.g. debug/release) and I use boolean variable 'dummy' decrared in gradle.taskGraph.whenReady:
gradle.taskGraph.whenReady {taskGraph ->
dummy = false
if (taskGraph.hasTask(':dummybuild')) {
dummy = true
}
}
The problem is that task configured by the following way has configuration scope, i.e. before whenReady so it doesn't have access to the 'dummy' variable:
task copySkins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
if (!dummy) exclude dummyExclude
}
Right now I'm using this workaround
task copySkins {
inputs.dir skinsFrom
outputs.dir skinsInto
doLast {
task skins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
if (!dummy) exclude dummyExclude
}
skins.execute()
}
}
Is it possible to
detect/setup some build properties in some other place except whenReady
move sync task work to doLast
or at least have some shortcut for sync task (.execute() looks quite ugly)
1) whenReady event allows user to access fully-initialized task graph: all initialization is finished and tasks are ready to run. The only situation, when you need to detect/setup build properties here, is when you need to introspect current build setup.
If you do not need this information, you can place your initialization anywhere in your build script. At the very end, it is nothing but groovy script.
apply plugin: 'java'
def now = new Date()
compileJava.doFirst {
println "It is ${now}. We are starting to compile"
}
2) You can not move sync task work to doLast. But you can always add your actions to doFirst ;) I think, this should work:
task copySkins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
doFirst {
if (!dummy) exclude dummyExclude
}
}
3) With all said before, missing sync task shortcut should not be that painfull

Resources