How can I configure Gradle to fail build at the end (not fail fast) if there is anything printed on standard error output by any task or plugin?
I haven't found a way to do it in the official API.
Here’s a sample build.gradle that shows how this can work:
// create a listener which collects stderr output:
def errMsgs = []
StandardOutputListener errListener = { errMsgs << it }
// add the listener to both the project *and* all tasks:
project.logging.addStandardErrorListener errListener
project.tasks.all { it.logging.addStandardErrorListener errListener }
// evaluate the collected stderr output at the end of the build:
gradle.buildFinished {
if (errMsgs) {
// (or fail in whatever other way makes sense for you)
throw new RuntimeException(errMsgs.toString())
}
}
// example showing that the project-level capturing of stderr logs works:
if (project.hasProperty('projErr'))
System.err.print('proj stderr msg')
// example showing that the task-level capturing of stderr logs works:
task foo {
doLast {
System.err.print('task stderr msg')
}
}
// example showing that stdout logs are not captured:
task bar {
doLast {
System.out.print('task stdout msg')
}
}
The examples in the second half are only there to show that it works as expected. Try the build with various command line args/options:
# doesn’t fail:
./gradlew bar
# fails due to project error:
./gradlew -PprojErr bar
# fails due to task error:
./gradlew foo
# fails due to both task and project error:
./gradlew -PprojErr foo
Related
If I change my ~/.gradle/init.gradle to the following:
def hi() {
println "hello"
}
hi()
initscript {
}
Then running a gradle build outputs:
hello
> Task :prepareKotlinBuildScriptModel UP-TO-DATE
BUILD SUCCESSFUL in 366ms
But if I change ~/.gradle/init.gradle to this:
def hi() {
println "hello"
}
initscript {
hi()
}
Then the gradle build outputs:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 6
* What went wrong:
A problem occurred evaluating initialization script.
> Could not find method hi() for arguments [] on object of type org.gradle.api.internal.initialization.DefaultScriptHandler.
Why is this?
And how can I invoke hi() from within the initscript block?
see link below to understand the initscript closure better - in short you can not do actions inside; you can only configure - see diff example of linking actions to tasks https://docs.gradle.org/current/userguide/init_scripts.html#sec:writing_an_init_script
Credit to ephemient from the Gradle community-support slack channel:
buildscript, initscript, plugins, and pluginManagement are all
special blocks that extracted and run separately, before any other
part of the script. this is necessary because Gradle needs to use them
to set up the build environment for the rest of the script. you cannot
use anything defined outside of the block, in these blocks.
Another note: if I change init.gradle to
initscript {
def hi() {
println "hello"
}
hi()
}
then the following error is output:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 2
* What went wrong:
Could not compile initialization script '/Users/aloneitan/.gradle/init.gradle'.
> startup failed:
initialization script '~/.gradle/init.gradle': 2: Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 2 column: 5. File: _BuildScript_ # line 2, column 5.
def hi() {
^
1 error
It appears that the answer is that it is not possible to define a method to be used inside initscript using Groovy
It is worth noting that it is possible in Kotlin, though.
I have created a complex pipeline. In each stage I have called a job. I want to see the console output for each job in a stage in Jenkins. How to get it?
The object returned from a build step can be used to query the log like this:
pipeline {
agent any
stages {
stage('test') {
steps {
echo 'Building anotherJob and getting the log'
script {
def bRun = build 'anotherJob'
echo 'last 100 lines of BuildB'
for(String line : bRun.getRawBuild().getLog(100)){
echo line
}
}
}
}
}
}
The object returned from the build step is a RunWrapper class object. The getRawBuild() call is returning a Run object - there may be other options than reading the log line-by-line from the looks of this class. For this to work you need to either disable the pipeline sandbox or get script approvals for these methods:
method hudson.model.Run getLog int
method org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper getRawBuild
If you are doing this for many builds, it would be worth putting some code in a pipeline shared library to do what you need or define a function in the pipeline.
What is the difference between these two tasks. Only task with << in its definition is shown in the output of ./gradlew tasks.
task greet(type: GreetingToFileTask) {
destination = { project.greetingFile }
}
task sayGreeting(dependsOn: greet) << {
println file(greetingFile).text
}
The lines above are from gradle documentation Here
The << is a shortcut to the toLast configuration item of a task definition. I.e. the following two declarations are equivalent:
task hello << {
println 'Hello world!'
}
and:
task hello {
doLast {
println 'Hello world!'
}
}
(example taken from Gradle documentation here).
Now, in the first code snippet you just define a task and configuring its destination property. However, the task will only be executed if needed.
In the second code snippet, however, you are actually defining an action that will always be executed during the configuration phase, regardless of the tasks targeted for execution (cite from here):
A task has both configuration and actions. When using the <<, you are
simply using a shortcut to define an action. Code defined in the
configuration section of your task will get executed during the
configuration phase of the build regardless of what task was targeted.
I have a very simple build script like so
task hello{
println("hello World")
}
task bye {
println("bye")
}
On the command line I run
gradle hello and I get the following output:
hello World
bye
:hello UP-TO-DATE
Why is it executing the task "bye" (I'm assuming it gets executed since "bye" gets printed)? Thanks.
It's a common pitfall:
task hello {
println("Any code in here is about *configuring* the\
task. By default, all tasks always get configured.")
doLast {
println("Any code in here is about *executing* the task.\
This code only gets run if and when Gradle decides to execute the task.")
}
}
The distinction between configuration phase and execution phase is probably the single most important concept to understand in Gradle. It can be confusing at first, and may go away in the future. A kind of analogue in the Ant/Maven world is that these tools first parse XML build scripts and build an object model (perhaps resolving some properties along the way), and only then execute the build.
Adding to Peter answer, If you want to execute all task , you can specify the defaultTasks list.
defaultTasks 'clean', 'run'
task clean {
doLast {
println 'Default Cleaning!'
}
}
task run {
doLast {
println 'Default Running!'
}
}
task other {
doLast {
println "I'm not a default task!"
}
}
Output
Output of gradle -q
> gradle -q
Default Cleaning!
Default Running!
More details can be found here
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
I'm trying to write a task rule to create a series of tasks that checkout various svn repository locations. Here is my rule:
tasks.addRule("Pattern: svnCheckout<Classifier> - Checks out the indicated svn repo") { String taskName ->
if(taskName.startsWith('svnCheckout')) {
task(name: taskName, type: Exec) {
String classifier = taskName - 'svnCheckout'
String svnDir = svnRepoUrl //defined elsewhere
switch(classifier) {
case 'SourceTrunk':
svnDir += 'branches/CleanBuild/trunk'
break
case 'AutoInstaller':
svnDir += 'Tools/AutoInstaller'
break
case 'ContentAutomation':
svnDir += 'Tools/ContentAutomation'
break
case 'InternalTools':
svnDir += 'Tools/Internal'
break
default:
throw new GradleException("Invalid svnCheckout classifier '$classifier'")
}
String svnCommand = "svn co $svnDir --trust-server-cert"
//commandLine 'cmd', '/c', "$svnCommand"
commandLine 'cmd', '/c/', "echo 'Task created'"
workingDir = "$workspace"
}
}
}
I then try to run the task 'svnCheckoutSourceTrunk' with this command:
gradlew -Pworkspace="." svnCheckoutSourceTrunk
which fails with the error
FAILURE: Could not determine which tasks to execute.
* What went wrong:
Task 'svnCheckoutSourceTrunk' not found in root project 'GradleScripts'.
* Try:
Run gradlew tasks to get a list of available tasks.
BUILD FAILED
Anyone see what I'm doing wrong? I put some println statements around the first few lines, and the execution is getting past the if statement, but it's not getting inside the task declaration.
The syntax used for declaring the task(s) is incorrect. (Not sure why it's not giving an error.) The first positional argument always need to be the task name:
task(taskName, type: Exec) { ... }
In a build script, this will also work:
task "$taskName"(type: Exec) { ... }