How to require system property only if task is executed? - gradle

I have a gradle script with a custom test task:
task integrationTest(type:Test) {
jvmArgs '-DmyParam=' + System.getProperty('myParam')
}
I want to fail the build with a nice message if the property is missing, but only if my task will be executed. I tried adding
task integrationTest(type:Test) {
if (!System.hasProperty('myParam')) throw new InvalidUserDataException("Missing property myParam")
jvmArgs '-DmyParam=' + System.getProperty('myParam')
}
but this will fail even if the integrationTest task isn't called.
How do I check this only when executing the task, instead of on gradle startup?

You can simply use a doFirst closure. The closure will be executed before the task action, so sufficiently early to modify the task, but not in configuration phase, but during execution phase, so, only if the task is executed:
task integrationTest(type:Test) {
doFirst {
jvmArgs '-DmyParam=' + System.getProperty('myParam')
}
}
Please note, that you can use the systemProperty method to define system properties:
systemProperty 'myParam', System.getProperty('myParam')
// instead of
jvmArgs '-DmyParam=' + System.getProperty('myParam')

A colleague helped me find the answer. Moving the exception to a doFirst block will produce the desired result:
task integrationTest(type:Test) {
doFirst {
if (!System.hasProperty('myParam')) throw new InvalidUserDataException("Missing property myParam")
}
jvmArgs '-DmyParam=' + System.getProperty('myParam')
}
or, if you need to fail the build before any task is executed, you can check if the task will be called:
project.gradle.taskGraph.whenReady { 
  if(project.gradle.taskGraph.hasTask(":integrationTest")) {
    if (!System.hasProperty('myParam')) throw new InvalidUserDataException("Missing property myParam")
   }
}

Related

Gradle task lines always getting executed

I have the following Gradle task:
task deploy(type: Exec) {
doFirst {
println 'Performing deployment'
}
final Map properties = project.getProperties()
if (!properties['tag']) {
throw new StopExecutionException("Need to pass a tag parameter")
}
commandLine "command", tag
}
If I run another task I get an error because properties['tag'] is undefined, I guess because Gradle is executing everything in the task except commandLine. Is there a better way to do this or a way to stop Gradle from executing parts of the task even when I'm running another task?
Using Gradle 6.6.1
I use this pattern:
// Groovy DSL
tasks.register("exec1", Exec) {
def tag = project.findProperty("tag") ?: ""
commandLine "echo", tag
doFirst {
if (!tag) {
throw new GradleException("Need to pass a tag parameter")
}
}
}
It adds the tag property if it exists.
If it does not exist, it adds an empty string but checks for this before it actually runs.
It would be great if the Exec task accepted providers as arguments so you could just give it providers.gradleProperty("tag"), but unfortunately it doesn't.

Gradle disable task

Can I disable the task, only for one task?
For example
flywayMigrate {
doFirst {
gradle.startParameter.excludedTaskNames += "test"
// test.enabled = false
}
dependsOn flywayClean
dependsOn build
}
I want you to do flywayMigrate
The tests were turned off.
But when I run clean build tests were run also.
I think you can do it with the task graph of the build as follows:
gradle.taskGraph.whenReady { taskGraph ->
if (taskGraph.hasTask(flywayMigrate)) {
test.enabled = false
}
}
Here is a closure executed then the task graoh is built, just before task are configured or executed. It check's whether flywayMigrate task will be executed and if yes, it disables test task.
Here is how it's described in the official docs.

Creating a task that runs before all other tasks in gradle

I need to create an initialize task that will run before all other task when I execute it.
task A {
println "Task A"
}
task initializer {
println "initialized"
}
If I execute gradle -q A, the output will be:
>initialized
>Task A
Now if i'll add:
task B {
println "Task B"
}
Execute gradle -q B, and I get:
>initialized
>Task B
So it doesn't matter which task I execute, it always get "initialized" first.
You can make every Task who's name is NOT 'initializer' depend on the 'initializer' task. Eg:
task initializer {
doLast { println "initializer" }
}
task task1() {
doLast { println "task1" }
}
// make every other task depend on 'initializer'
// matching() and all() are "live" so any tasks declared after this line will also depend on 'initializer'
tasks.matching { it.name != 'initializer' }.all { Task task ->
task.dependsOn initializer
}
task task2() {
doLast { println "task2" }
}
Or you could add a BuildListener (or use one of the convenience methods eg: Gradle.buildStarted(...))
Seems like you aim execution phase, and you want a task precursing each task or just run as a first task in the execution phase?
If you want a task to always execute in every project before each other task after its being evaluated you can add a closure to he main build.gradle:
allprojects {
afterEvaluate {
for(def task in it.tasks)
if(task != rootProject.tasks.YourTask)
task.dependsOn rootProject.tasks.YourTask
}
}
or
tasks.matching {it != YourTask}.all {it.dependsOn YourTask}
You can also use the Task Execution Graph to define the lifecycle. There are few ways of achieving your goal, depending on your needs and a project structure.
The previously suggested solution with dependsOn works fine, but I don't like about it that it changes and clutters the task dependencies. The first solution coming to my mind is using Gradle Initialization Scripts. They are really cool. But, the usage is a bit tedious: currently there is no way to have a default project-local Gradle init script. You have to either explicitly specify the script(s) on command line, or place them in USER_HOME/GRADLE_HOME.
So another solution (already briefliy mentioned by #lance-java) which can be used to run some initialization, like a init task/script, is "build listeners". Depending on how early/late the initialization code should run, I use one of these two:
gradle.afterProject {
println '=== initialized in afterProject'
}
or
gradle.taskGraph.whenReady {
println '=== initialized in taskGraph.whenReady'
}
Here the docs of the Gradle interface and of BuildListener.
Note that some of the events occur very early, and you probably can't use them because of that, like e.g. beforeProject and buildStarted (explanations here and there).

How to run/execute a gradle task?

How to run this gradle task/include it in build task (https://github.com/prashant-ramcharan/courgette-jvm)
task regressionSuite(type: Test, dependsOn: testClasses) {
systemProperty('name', 'value')
include '**/RegressionTestSuite.class'
outputs.upToDateWhen { false }
}
When I do gradle clean regressionSuite is always giving me build successful.. but it's not executing the specified class. Specific file is in the path.
I'm new to gradle.. any help much appreciated!!
you need to configure also the testClassesDir and the classpath property of the test task, otherwise the class you define in your pattern can't be found nor the test can be executed:
task regressionSuite(type: Test) {
systemProperty('name', 'value')
include '**/RegressionTestSuite.class'
outputs.upToDateWhen { false }
classpath = sourceSets.test.runtimeClasspath
testClassesDir = sourceSets.test.output.classesDir
}

How do I alias gradle task as if it were called with -x parameter?

I want instead of gradle cleanIdea idea -x compileJava -x compileTestJava
call something like gradle ideaNoRecompile
You can use TaskExecutionGraph to do it. First of all, you need to provide a custom task, named ideaNoRecompile, when during the configuration phase, you need to check, whether this graph contains ideaNoRecompile task (that means, that this task will be executed. And if this task should be executed, then you can use a closгre to skip all the tasks, you don't want to be executed. Something like this:
task ideaNoRecompile(dependsOn:idea) {
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(ideaNoRecompile)) {
compileJava.enabled = false
compileTestJava.enabled = false
}
}
}
I've found another similar answer:
task ideaNoRecompile {
finalizedBy allprojects*.tasks*.idea
doFirst {
def skipTasks = ['compileJava', 'compileMirah', 'processResources', 'classes', 'compileTestJava', 'compileTestMirah', 'processTestResources', 'testClasses', 'jar', 'mergeProperties', 'generateModuleManifest' ] as Set
allprojects*.tasks*.each {
if (skipTasks.contains(it.name))
it.enabled = false
}
}
}

Resources