gradle get value from extension (pass as input to task) - plugins

I have following code in my plugin:
#Override
void apply(Project project) {
project.extensions.create(EXTENSION,TestExtension)
project.task("task1") << {
println "Task 1"
println(project.mmm.test)
def extension = project.extensions.findByName(EXTENSION)
println(extension.test)
}
project.task("task2",type: TestTask) {
println "Task 2 "
def extension = project.extensions.findByName(EXTENSION)
// conventionMapping.test = {extension.test}
// println(project.extensions.findByName(EXTENSION).test)
// test = "test"
}
}
In task 1 extension.test return correct value. However in task2 extension.test always return null. What I am doing wrong? Is there a better way to pass some of the extensions values as input for task? I am using gradle 1.12 with jdk 1.8 on Mac. Best Regards
Edit :correct version:
project.task("task2", type: TestTask) {
project.afterEvaluate {
def extension = project.extensions.findByName(EXTENSION)
println(project.extensions.findByName(EXTENSION).test)
test = project.extensions.findByName(EXTENSION).test
}
}

task1 prints the value at execution time (notice the <<), task2 at configuration time (before the rest of the build script after the apply plugin: ... has been evaluated). This explains why the println for task1 works as expected, and the println for task2 doesn't.
However, configuring a task at execution time is too late. Instead, a plugin needs to defer reading user-provided values until the end of the configuration phase (after build scripts have been evaluated, but before any task has been executed). There are several techniques for doing so. One of the simpler ones is to wrap any such read access with project.afterEvaluate { ... }.

Updated answer as some time has passed and Gradle evolved its concepts and its syntax in the meantime.
To use up-to-date and optimally configured task you should use following syntax:
tasks.register("task1") {
doLast {
def extension = project.extensions.findByName(EXTENSION)
println(project.extensions.findByName(EXTENSION).test)
test = project.extensions.findByName(EXTENSION).test
}
}
Task Action:
A task has both configuration and actions. When using the doLast, 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.
Deprecated << Operator
<< was deprecated in 4.x and removed in 5.0. See task action (doLast) on how to evaluate task logic at execution phase when all extensions and configurations should be evaluated.
Task Configuration Avoidance
To avoid the cost of creating a task if this won't be executed on your invoked Gradle command TaskContainer.register(String) method.
Avoid afterEvaluate
afterEvaluate should in most cases be avoided, see #sterling's comments from the link. You have now the possibility to evaluate task action part in execution phase, and additionally you can also rely on Task Inputs/Outputs with the combination of Lazy Configuration.

Related

Access tasks' properties via Gradle Tooling API

I'm using the gradle tooling API to run functional tests for my own build script.
I would like to access tasks' properties, e.g. the destinationDir of a JavaCompile task, and i don't know how to accomplish this.
Simple example:
Snippet in my buildScript (I defined a SourceSet 'openjpa'):
compileOpenjpaJava {
destinationDir = file(getOpenjpaClassesDir())
}
private String getOpenjpaClassesDir(){
return "build/classes_openjpa"
}
In my functional test I read about a way to access the tasks, but I cannot access the destinationDir-property.
GradleProject project = connection.getModel(GradleProject.class);
project.tasks.each { myTask ->
if ("compileOpenjpaJava" == myTask.name) {
return myTask.destinationDir.absolutePath // brings a runtime error like: unknown property 'destinationDir'
}
}
A similar question w/o answers is here: Gradle tooling api get task outputs
Is it possible at all to access tasks' properties?
Thanks
Jan

How to make sbt run another consecutive command regardless of previous command's result?

My tests are slow. Real slow. Like I can get another cup of coffee and reading some articles while waiting for them to finished slow. So I added this task to build.sbt just to alert me when my testing is finished.
lazy val alertMe = taskKey[Unit]("Alert me when testing is completed.")
alertMe in Test := {
"say \"testing is completed\""!
}
Noted that I use say command on OS X. I then used this task like this.
;test ;alertMe
Voila! This works great.... only for successful testing. In case that any test case failed, test task return result as error, and alertMe is not invoked.
This behavior is pretty understandable. but I want my task, alert me, to run regardless of test task result. How can I do this ?
Maybe you can add test task in alertMe task, like:
lazy val alertMe = taskKey[Unit]("Alert me when testing is completed.")
alertMe := {
Command.process("test", state.value)
"say \"testing is completed\""!
}
usage: sbt alertme, it will run the test task and the shell command.
Command.process will execute the test task and without causing current task fail. so the commands always will be executed.

How to run a single task in in Eclipse with gradle buildship?

Currently I have in my gradle.build file the tasks:
task helloA {
println 'hello A!'
}
task helloB {
println 'hello B!'
}
However executing task helloA via Gradle Tasks/other/helloA prints on the console:
hello A!
hello B!
:helloA UP-TO-DATE
BUILD SUCCESSFUL
However I would expect it to just print: 'hello A!' instead of
hello A!
hello B!
together.
How do I change that? I read through the gradle docs, but coudln't find something about that apart from some extensive workaround.
No task is executed at all in your buildfile, they are just configured.
Be aware that there are three phases in a Gradle run. Initialization, configuration and execution. In initialization phase, you define which projects are part of the build and where they are on disc (basically settings.gradle execution). In configuration phase all tasks are configured. In execution phase the tasks that need to be executed (explicitly called tasks or default tasks, depended upon directly or transitively by explicitly called or default tasks).
Try this and you will see:
task helloA {
println 'configure A!'
doLast {
println 'execute A!'
}
}
task helloB {
println 'configure B!'
doLast {
println 'execute B!'
}
}

Stop the pipeline when stage is unstable

I have a Jenkins build pipeline created using workflow plugin. At the beginning the pipeline runs a gulp build inside of the docker container and then archives test results using the following code
step([$class: 'JUnitResultArchiver', testResults: 'build/test-results/*.xml'])
In the following steps I package up the artifacts and ship them to the binary repository.
When unit tests are not passing Jenkins understands the build is unstable and marks it yellow. However it still continues with subsequent steps in the pipeline. Is there any way make the pipeline stop when unit tests are failing?
the JUnitResultArchiver will cause this condition to be true when the build is unstable:
currentBuild.result != null.
If I remember correctly it sets it to UNSTABLE, but it is enough to check that is different than null.
So you could do something like
step([$class: 'JUnitResultArchiver', testResults: 'build/test-results/*.xml'])
if (currentBuild.result == null) {
//contintue with your pipeline
} else {
//notify that the build is unstable. //or just do nothing
}
There is nothing to do at Jenkins side but at Gulp side. The call to gulp CLI needs to return a proper error value to have the sh step failing correctly.
Jenkins just interprets what the shell is returning, so you juts need to make Gulp to return a fail when tests fail (see this blog post, it seems to achieve exactly that).

How to execute Scala script from Gradle?

I have a Scala script that looks something like:
#!/bin/sh
PATH=${SCALA_HOME}:${PATH}
exec scala "$0" "$#"
!#
Console.println("Hello, world!")
Is there some way in Gradle to set the version of Scala to be used, have it implicitly set SCALA_HOME, and execute the script?
There is no built-in feature for this. The way to tackle this is to declare two tasks: A Copy task that downloads the Scala distribution and unpacks it to a local directory, and an Exec task that sets the SCALA_HOME environment variable to the copy task's output directory and executes your script.
Here is an example of executing Scala from Gradle. It is a nascent attempt to build a plugin using Scalafmt. Of note is how nasty it is to use static values.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.geirsson:scalafmt-core_2.11:0.4.2'
}
}
task scalafmt << {
String target = "object FormatMe { List(Split(Space, 0).withPolicy(SingleLineBlock(close)), Split(Newline, 1).withPolicy{ case Decision(t#FormatToken(_, `close`, _), s) => Decision(t, List(Split(Newline, 0)))}.withIndent(2, close, Right)) }"
def config = org.scalafmt.config.ScalafmtConfig$.MODULE$.default
def range = scala.collection.immutable.Set$EmptySet$.MODULE$
println org.scalafmt.Scalafmt.format(target, config, range).formattedCode()
}
I know this is not quite on topic but I couldn't find anywhere else to put this and I hope it is of some value to people who ended up here for the same reason I did.
Gradle has an Exec task in which you can set the environment to be passed to the new process. You could pass SCALA_HOME through that.