I can't make Gradle show (highlighted) warnings that I emit from my build script using
logger.warn("something something")
The line is emitted plain, like any other log line, it does not have a WARN next to it, I was expecting some colour with --console=rich, nothing.
Also, the warning is simply emitted at the respective place in the log.
I would like them emitted there but also at the end, or at least something at the end to indicate there were warnings. Supposedly --warning-mode=summary is for this but doesn't have any effect.
I tried all possible combinations like:
gradle --warning-mode=summary build
gradle build --warning-mode=all
gradle build --warning-mode all
gradle build -Dorg.gradle.warning.mode=all --console=rich --info
etc
I tried gradle 5.2 and 5.4.1. No warnings!
warn messages from the logger always look like that. They are visible by default; while info messages are only shown when using --info flag (or something more verbose).
Actually the logger is based on slf4j; but then it is up to Gradle to set the logging format (and they chose not to show the log level, nor the timestamp etc.)
When calling logger.warn(..), that resolves to project.logger. See the reference for Project.getLogger() , and for the Logger .
One way to show colored output (see this SO post) is by using Gradle internal API like
import org.gradle.internal.logging.text.StyledTextOutput;
import org.gradle.internal.logging.text.StyledTextOutputFactory;
def out = services.get(StyledTextOutputFactory).create("my-factory")
out.withStyle(StyledTextOutput.Style.FailureHeader).println('Failure message')
out.withStyle(StyledTextOutput.Style.Success).println('Success message')
A dirty (and trivial) way to show "WARN" in your messages is obviously to use logger.warn('WARN: message').
Finally, instead of printing warnings, tasks can be interrupted by throwing exceptions, so that Gradle will stop the build and show what went wrong, eg. when running gradle taskA with:
task taskB {
doLast{
throw new Exception("error here")
}
}
task taskA {
dependsOn taskB
}
Related
Courtesy of M.Ricciuti who answered my initial 'Migrating from Gradle 4 to 5. How to get mapstruct 1.20.final working with it' question I've an addition question. Created a new new thread because 'add comment' does not allow me enough characters/text.
I would like to have a Gradle 'generateMappers' task to generate the mapstruct source files AND display a message when the sources are generated and preferable one which tells me that nothing is generated because it wasn't needed.
In the old situation we had a generateMappers task which used mapstruct to generate source files AND display a message when the files were created. Now its basically empty.
task generateMappers (type: JavaCompile, dependsOn: compileJava) {
doFirst {
println "\tGenerating mapper classes"
}
doLast {
println "\tMapping classes generated"
}
}
Gradlew -i generateMappers reveals the following.
> Task :eu.myfirm.rest:generateMappers NO-SOURCE
Skipping task ':eu.myfirm.rest:generateMappers' as it has no source files and no previous output files.
:eu.myfirm.rest:generateMappers (Thread[Execution worker for ':' Thread 4,5,main]) completed. Took 0.0 secs.[enter link description here][1]
NOTE: > Task :eu.myfirm.rest:compileJava FROM-CACHE does trigger correctly ONLY when the sources are not there.
By changing the task into 'task generateMappers {...}' I ALWAY get a message - even when no new files are generated because nothing has changed in the mappers. Gradlew --info reveals
> Task :eu.myfirm.rest:generateMappers
Custom actions are attached to task ':eu.myfirm.rest:generateMappers'.
Caching disabled for task ':eu.myfirm.rest:generateMappers' because:
Caching has not been enabled for the task
Task ':eu.myfirm.rest:generateMappers' is not up-to-date because:
Task has not declared any outputs despite executing actions.
Generating mapper classes
Mapping classes generated
Its wrong because caching is disabled and I know this is only cosmetic because whether the sources are there or not I will always get this message.
I've this feeling I'm on the WRONG track and I somehow have to hook into the annotationProcessor to get the required two messages BUT I also would like to have a seperate 'generateMappers' task to call. Any further hints/pointers is greatly appreciated.
So I'm trying to print some stuff to the console in Gradle even if the build fails. How can I do this?
I've found build.finalizedBy(taskName) but that only runs if the build finishes normally.
You can let any build continue on task failures by using the --continue parameter on Gradle invocation. If you do not want to type this parameter all the time you can use the following code in your settings.gradle:
startParameter.continueOnFailure = true
Please note that other tasks may fail due to an earlier task that failed. Using this option, tasks connected via finalizedBy will be executed, but you should only use this option if the tasks are related, even for non-failure cases.
Of course, you can also use lifecycle listeners of the Gradle object or its TaskExecutionGraph. You can use
afterTask
a full TaskExecutionListener implementation
buildFinished (for the whole build)
You can use either gradle.buildFinished or a finalizer task (as you mentioned).
In your example, build.finalizedBy(taskName) will only execute taskName if the build task executes. If the build fails before the build task executes, taskName won't be executed.
e.g., this prints a message based on the result of the build:
gradle.buildFinished { result ->
if (result.failure) {
logger.lifecycle("build failed")
} else {
logger.lifecycle("build successful")
}
}
So I'm trying to write a list of all gradle tasks to a file. I of course could use the tasks command for this, but I want cache it to a file every time any other gradle command is called. So whenever I run ./gradlew build for example, I want the available tasks to be written to a file.
This seemed simple enough, and I wrote the below task to try it out:
task cacheTasks() {
doLast {
allprojects { p ->
p.tasks*.each { t ->
println(p.name + ":" + t.name)
}
}
}
}
The problem is, that I only get a sub-set of all the tasks available. When I run the ./gradlew tasks --all command, many more are printed. It seems that none of the built-in tasks (like build, clean or help) are in the tasks* List when I loop over it, but oddly enough I can reference them directly:
tasks.build { t ->
println("DEBUG:" + t.name)
}
It seems so simple, yet I've been searching in vain for a solution. I even tried looking in the gradle source code to see how the tasks Task works, but I couldn't find any clue as to why this doesn't work.
rootProject.getAllTasks(true) looks like it's retrieving more tasks than rootProject.tasks.
I highly doubt there is a task class in container with name build.
This is what I get when I debug your task:
I am not saying gradle build does not run, but it can be in other forms maybe an instance of org.gradle.api.tasks.GradleBuild. (I am not very sure because the gradle source code is very hard for me to compile and run).
When using
tasks.build { t ->
println("DEBUG:" + t.name)
}
You actually call org.gradle.api.tasks.TaskContainer#create(java.util.Map<java.lang.String,?>, groovy.lang.Closure) and create a new task named build.
'I'm writing build script using net.foragerr.jmeter plug-in, version 1.0.2-2.13.
What my task does is mostly 1) runs plug-in JMeter task and 2) collects application log.
task perfTest(dependsOn: ['jmClean', 'jmRun'],
description:'Runs (cleanly) performance tests on a deployed application and collects the app log if available. ' +
'Use --no-daemon to see progress. Use --info to see all JMeter command-line arguments.') << {
if (logDir.isDirectory()) {
copy {
from "${logDir}"
into "${buildDir}/jmeter-report"
include 'iRePORT.log'
}
}
}
Now, I need to collect the log even if jmRun fails. When I try to implement a solution for this, I am really stuck:
I can't modify jmRun task, because it's a plug-in task
I can't use try/finally and execute another task directly because Gradle is designed not to support this, e.g. see How do I wrap a gradle task in another task?
I can't use --continue flag gradle.startParameter.continueOnFailure = true because it would not continue execution of a dependent task
The only possible workaround that I could think of is to separate log collection, always include it on a command line, e.g. perfTest collectLogs and set gradle.startParameter.continueOnFailure = true in perfTest.
This is far from ideal.
Are there any better solutions? Shouldn't there be a way for Gradle to support scenarios like this?
You could try creating a task like this
task collectPerfTestLogs(type: Copy) {
from "${logDir}"
into "${buildDir}/jmeter-report"
include 'iRePORT.log'
}
and then have perfTest.finalizedBy(collectPerfTestLogs).
To quote Gradle:
Finalizer tasks will be executed even if the finalized task fails.
See https://docs.gradle.org/current/userguide/more_about_tasks.html
I have a pretty standard Gradle build that's building a Java project.
When I run it for the first time, it compiles everything and runs the tests. When I run it a second time without changing any files, it runs the tests again.
According to this thread, Gradle is supposed to be lazy by defaut and not bother running tests if nothing has changed. Has the default behaviour here been changed?
EDIT:
If I run gradle test repeatedly, the tests only run the first time and are subsequently skipped. However, if I run gradle build repeatedly, the tests get re-run every time, even though all other tasks are marked as up-to-date.
the gradle uptodate check logs on info level why a task is not considered to be up-to-date. please rerun the "gradle build -i" to run with info logging at check the logging output.
cheers,
René
OK, so I got the answer thanks to Rene prompting me to look at the '-i' output...
I actually have 2 test tasks: the 'test' one from the Java plugin, and my own 'integrationTest' one. I didn't mention this in the question because I didn't think it was relevant.
It turns out that these tasks are writing their output (reports, etc.) to the same directory, so Gradle's task-based input and output tracking was thinking that something had changed, and re-running the tests.
So the next question (which I will ask separately) becomes: how do I cleanly (and with minimal Groovy/Gradle code) completely separate two instances of the test task.
You need to create test tasks in your build.gradle and then call those specific tasks to run a specific set of tests. Here is an example that will filter out classes so that they don't get run twice (such as when running a suite and then re-running its child classes independently):
tasks.withType(Test) {
jvmArgs '-Xms128m', '-Xmx1024m', '-XX:MaxPermSize=128m'
maxParallelForks = 4 // this runs tests parallel if more than one class
testLogging {
exceptionFormat "full"
events "started", "passed", "skipped", "failed", "standardOut", "standardError"
displayGranularity = 0
}
}
task runAllTests(type: Test) {
include '**/AllTests.class'
testReportDir = file("${reporting.baseDir}/AllTests")
testResultsDir = file("${buildDir}/test-results/AllTests")
}
task runSkipSuite(type: Test) {
include '**/Test*.class'
testReportDir = file("${reporting.baseDir}/Tests")
testResultsDir = file("${buildDir}/test-results/Tests")
}
Also, concerning your build question. The "build" task includes a clean step which is cleaning tests from your build directory. Otherwise the execution thinks the tests have already been ran.