Exclude file from Gradle test dependency - gradle

I have rather expensive tests in my gradle java project, so I would like to avoid running them too often. Unfortunately, gradle reruns the tests on every build, since some log file in the resource-folder is changing.
Is there any way to exclude log-files from the dependency checks of :processTestResources and :test? I tried to include a exclude command in my test task, but this doesn't seem to do anything. My test task is
test {
maxHeapSize = "2048m"
workingDir = "src/test/resources/test-instance"
environment "LD_LIBRARY_PATH", "xpressmp/lib:/opt/gurobi/linux64/lib"
environment "XPRESS", "xpressmp/bin"
environment "XPRESSDIR", "xpressmp"
exclude("*.log")
exclude("*.lp")
}

I think what you are after is
sourceSets {
test {
resources {
exclude '*.log'
}
}
}
Excluding in the task would only exclude the test class from running, not which files are considered input for the task.
Btw. you can also use JUnit Categories to separate your tests into Short-Running and Long-Running tests and then make different tasks or a project property to only run the fast tests or all tests or only the slow tests. Or you can split the tests in different sourcesets and make separate tasks for it.

Define a new Test task:
task notGenericNotFT( type: Test, dependsOn: testClasses ){
filter { excludeTestsMatching 'generic.*' }
// excludes a whole package, "generic". NB this is not a regex:
// '*' is simply "wildcard" and dot means dot ... other more
// sophisticated "ANT-style" patterns are available in class Test
filter { excludeTestsMatching '*_FT' }
// also exclude all test classes ending in "_FT" (e.g. for "functional test")
}
To understand where these things come from, examine class Test and class TestFilter.
Also be aware that the gradle command line parser is quite intelligent and permissive with case-sensitivity (even in Linux!), so you can do this:
...$ ./gradlew notgen
... and it will run (as long as "notgen" designates this task unambiguously).

Related

How to run a single test that is excluded

I have integration tests named with "IT" at the end and the tests are excluded by default. My build.gradle contains:
test {
if (!project.hasProperty('runITs')) {
exclude '**/**IT.class'
}
}
The check task, which is part of build, no longer runs integration tests. All tests (unit + integration) are executed with defined runITs (e.g. ./gradlew -PrunITs=1 check) if it is necessary.
It works very well. The only drawback is than I can't run single integration test with --test (used by IDE) without runITs defined. The command fails with message: No tests found for given includes: [**/**IT.class](exclude rules).
Is there any way (e.g. build variable) how to recognize the run of single test with --test and skip the exclusion?
I have found a solution. My build.gradle now contains:
test {
if (!project.hasProperty('runITs') && filter.commandLineIncludePatterns.empty) {
exclude '**/**IT.class'
}
}
When tests are run with --tests then the list commandLineIncludePatterns in filter is not empty and exclude is not applied.
Details are obvious in test task source: https://github.com/gradle/gradle/blob/dc8545eb1caf7ea99b48604dcd7b4693e79b6254/subprojects/testing-base/src/main/java/org/gradle/api/tasks/testing/AbstractTestTask.java
try invoking the test task to the specific sub-project. if the test is root try
gradle -PrunITs=1 :test --tests 'MServiceTest'
else
gradle -PrunITs=1 :sub-prj:test --tests 'MServiceTest'

Gradle: any difference between task configuration approaches

Is there any difference between two following pieces of code?
May be there is some difference about eager initialization of a task?
tasks.bootJar {
archiveFileName = "some-name"
}
and
bootJar {
archiveFileName = "some-code"
}
They are the effectively the same just different syntax. Both cause the task to be realized or eager initialized. You can confirm this by simply running with debug output: ./gradlew -d
You will see the following line logged:
[DEBUG] [org.gradle.internal.operations.DefaultBuildOperationRunner] Build operation 'Realize task :bootJar' started
For the Groovy DSL, the Gradle team takes advantage of the metaprogramming offered by the Groovy language to dynamically make tasks, extensions, properties, and more "magically" available.
So for this example:
tasks.bootJar {
archiveFileName = "some-name"
}
tasks is of type TaskContainer. If you were to examine all available methods and properties for TaskContainer, you will see that bootJar is not one of them. So Gradle hooks into the Groovy metaprogramming to search for something named bootJar. Since it's on the TaskContainer type, it can be assumed that bootJar is a task.
So if you were to desugar the DSL, the first example is effectively:
tasks.getByName("bootJar") {
}
Now for the second example:
bootJar {
archiveFileName = "some-code"
}
The default scope or this in a Gradle build file is Project. Again, just like before, if you were to examine all available methods and properties, you will not see bootJar as one of them.
Groovy's 'magic' is at play here, but this time around, Gradle will search (my understanding) practically everywhere because there is a lot more available on a Project.
project.extensions.named("bootJar") // exists?
project.hasProperty("bootJar") // exists?
project.tasks.getByName("bootJar") // found it!
To summarize, no there is no difference between the two since both cause the bootJar task to be realized. Use task configuration avoidance wherever possible to make your Gradle builds more efficient:
import org.springframework.boot.gradle.tasks.bundling.BootJar
tasks.named("bootJar", BootJar) {
}

A code generator task in a multi-project gradle build

I have studied thousand similar questions on SO and I am still lost. I have a simple multiproject build:
rootProject.name = 'mwe'
include ":Generator"
include ":projectB"
include ":projectC"
with a top level build.gradle as follows (settings.gradle):
plugins { id "java" }
allprojects { repositories { jcenter() } }
and with two kinds of project build.gradle files. The first one (Generator) exposes a run command that runs the generator taking the command line argument:
plugins {
id "application"
id "scala"
}
dependencies { compile "org.scala-lang:scala-library:2.12.3" }
mainClassName = "Main"
ext { cmdlineargs = "" }
run { args cmdlineargs }
The code generator is to be called from projectB (and an analogous projectC, and many others). I am trying to do this as follows (projectB/build.gradle):
task TEST {
project (":Generator").ext.cmdlineargs = "Hurray!"
println ("Value set:" + project(":Generator").ext.cmdlineargs )
dependsOn (":Generator:run")
}
Whatever I try to do (a gradle newbie here) I am not getting what I need. I have two problems:
The property cmdlineargs is not set at the point that task :projectB:TEST is run. The println sees the right value but the argument passed to the executed main method is the one configured in Generator/build.gradle, not the one in projectB/build.gradle. As pointed out in responses this can be work around using lazy property evaluation, but this does not solve the second problem.
The generator is only run once, even if I build both projectB and projectC. I need to run Generator:run for each of projectB and projectC separately (to generate different sources for each dependent project).
How can I get this to work? I suppose a completely different strategy is needed. I don't have to use command line and run; I can also try to run the main class of the generator more directly and pass arguments to it, but I do find the run task quite convenient (the complex classpath is set up automatically, etc.). The generator is a Java/Scala project itself that is compiled within the same multi-project build.
Note: tasks aren't like methods in java. A task will execute either 0 or 1 times per gradle invocation. A task will never execute twice (or more) in a single Gradle invocation
I think you want two or more tasks. Eg:
task run1(type:xxx) {
args 'foo'
}
task run2(type:xxx) {
args 'bar'
}
Then you can depend on run1 or run2 in your other projects.

How can I share build code script for all my gradle projects (not just subprojects)

I want to have this code snippet
test {
testLogging.showStandardStreams = true
}
Shared for all my gradle projects. Is that possible? Preferrably something I add to ~/.gradle/common.gradle or similar.
Probably the best way to inject build logic into existing build scripts without touching them is using init scripts. So you can create a script like testlogging.gradle that looks like this:
allprojects {
tasks.withType(Test) {
testLogging.showStandardStreams = true
}
}
As you can see I use tasks.withType(Test) instead of test here to reference the test task by type. That has some benefits:
this script works also for builds with no task with name test. This could likely happen (e.g. in multiproject builds)
this script would also apply for any other tasks in your build that are of type Test. Some projects use integTest etc.
To auto apply this script on your machine, you can put it in the folder ~/.gradle/init.d. Gradle considers every .gradle file in there as init script and applies them to each build.
To learn more details about init scripts check the according chapter in the gradle userguide.

Skip a task when running another task

I added a task to my gradle project:
task deploy() {
dependsOn "build"
// excludeTask "test" <-- something like this
doFirst {
// ...
}
}
Now the build task always runs before the deploy task. This is fine because the build task has many steps included. Now I want to explicitly disable one of these included tasks.
Usually I disable it from command line with
gradle deploy -x test
How can I exclude the test task programmatically?
You need to configure tasks graph rather than configure the deploy task itself. Here's the piece of code you need:
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(deploy)) {
test.enabled = false
}
}
WARNING: this will skip the actions defined by the test task, it will NOT skip tasks that test depends on. Thus this is not the same behavior as passing -x test on the command line
I don't know what your deploy task does, but it probably just shouldn't depend on the 'build' task. The 'build' task is a very coarse grained lifecycle task that includes tons of stuff you probably don't want.
Instead it should correctly define its inputs (probably the artifacts that you wanna deploy) and then Gradle will only run the necessary tasks to build those inputs. Then you no longer need any excludes.
I ran into a similar problem. Here is how I prevent "test" from running when I run "intTest" and want the ITs to run alone:
test {
onlyIf { !gradle.startParameter.taskNames.contains("intTest") }
}
An alternative that doesn't depend on certain tasks being run explicitly:
test {
onlyIf { !gradle.taskGraph.hasTask(":intTest") || gradle.taskGraph.hasTask(":check") }
}

Resources