Gradle custom task option without value - gradle

I'm developing a custom gradle task and i'd like to have an option which does act like a flag and doesn't require a value.
I just want to check if it is set
Basically : I can use plugin either gradle my-task or gradle my-task --flag and be able to check if --flag is present or not to define plugin processing.
I cannot find any thing in the official documentation

Custom command line options for tasks are available since Gradle 4.6 via #Option annotation on task property setters. Documentation link: Declaring and Using Command Line Options.
According to the documentation, value-less command line options are supported via boolean properties.
boolean, Boolean, Property<Boolean>
Describes an option with the value true or false. Passing the option on the command line treats the value as true. For example --enabled equates to true. The absence of the option uses the default value of the property.
(Untested) Example:
import org.gradle.api.tasks.options.Option;
public class MyTask extends DefaultTask {
private boolean flag;
#Option(option = "flag", description = "Sets the flag")
public void setFlag(boolean flag) {
this.flag = flag;
}
#Input
public boolean isFlag() {
return flag;
}
#TaskAction
public void doWork() {
if (flag) {
getLogger().quiet("Flag is present");
}
}
}

In Kotlin you can write the following:
open class TestTask: DefaultTask() {
#get: Input
#set: Option(
option = "flag",
description = "test option.")
var flag = false
#TaskAction
fun run() {
if (flag) println("FLAG IS ACTIVATED")
else println("FLAG IS NOT ACTIVATED")
}
}
Then you should register this TestTask, and then you can call it with Gradle.
user#laptop:~/test-project$ ./gradlew my_task --flag
> Task :my_task
FLAG ACTIVATED
BUILD SUCCESSFUL in 533ms
1 actionable task: 1 executed
user#laptop:~/test-project$ ./gradlew my_task
> Task :my_task
FLAG IS NOT ACTIVATED
BUILD SUCCESSFUL in 328ms
1 actionable task: 1 executed

Related

Gradle task's custom options

I want to add several options to my custom Gradle task. So I did it:
open class MyTask: DefaultTask() {
#get: Input
#set: Option(
option = "option1",
description = "option1 description.")
var option1 = false
#TaskAction
fun run() {
// proceeding options:
if (option1) println("OPTION 1 IS ACTIVATED")
}
}
If I register this task, I can use command like this and option1 will be equal true:
./gradlew my_task --option1
But I want to add more options in my task. Is there an opportunity not to copy-paste many-many times this code to produce many Boolean options?
I found some Property<Boolean> declaration in Gradle Docs, but I cannot understand how it works, because there is no example at all.

Jenkins Groovy Pipeline Get (Windows)User Folder Per Node

I have a distributed Jenkins build and the user under which the jenkins process runs on the slaves is not necessarily static, so I need a mechanism to get the user per node.
I am trying something like
#!/usr/bin/env groovy
class TestSettings {
public static String NuGetPackagesPath = "${env.USERPROFILE}\\.nuget\\packages"
}
node("master"){
println env.USERPROFILE // works as expected
println TestSettings.NuGetPackagesPath // throws exception
}
node("build"){
println env.USERPROFILE // works as expected
println TestSettings.NuGetPackagesPath // throws exception
}
env doesn't work in the static property, because the property is already initialized before you enter the node closure. So env just isn't available yet.
I see two ways around this:
Turn the property into a function and pass the env variable as parameter.
Make it a non-static function and pass env to the class constructor.
I would propably go with the latter as it will be easier to use when you have many test settings.
class TestSettings {
public static String getNuGetPackagesPath( def env ) { "${env.USERPROFILE}\\.nuget\\packages" }
}
class TestSettings2 {
def env = null
TestSettings2( def env ) {
this.env = env
}
public String getNuGetPackagesPath() { "${env.USERPROFILE}\\.nuget\\packages" }
}
node("master"){
println env.USERPROFILE
println TestSettings.getNuGetPackagesPath( env )
def testSettings = new TestSettings2( env )
// Note that we can use the method like a property!
println testSettings.nuGetPackagesPath
}

Pass variable back from Groovy class to Gradle task

I might not have set the right title for this question and that's because i'm not that advanced in Gradle, so apologies for that.
I have the below Gradle tasks in my build.gradle:
// buildSrc/src/main/groovy/envs/actions - This where all the groovy classes which I use are located
import envs.actions.*
tasks.create("createEnvironment", CreateApplicationEnvironmentTask) {
println "executing creation"
}
return tasks.create("createRecord", CreateRecordTask) {
dependsOn "createEnvironment"
varEbCname = tasks["createEnvironment"].ebCname
}
The first task is of type "CreateApplicationEnvironmentTask", which is a class in a .groovy file where i do some actions and set some variables.
One of these variables that i set in the "CreateApplicationEnvironmentTask" class is also one called "ebCname", as seen below:
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
class CreateApplicationEnvironmentTask extends DefaultTask {
String ebCname
#TaskAction
def create() {
ebCname = "some_value"
}
}
What I'm looking to do is to be able to get the value of the variable "ebCname"(which is set inside the class) from the second task "createRecord" by calling the "createEnvironment" task. I'm doing the below from within the second task, but it's not working:
varEbCname = tasks["createEnvironment"].ebCname
"varEbCname" ends up being null.
I also tried "return"-ing the "ebCname" variable from the class, but that didn't work either.
The "ebCname" variable is set in the "CreateApplicationEnvironmentTask" class which is used by the "createEnvironment" task, so I need a way get the value of that variable from the second task "createRecord".
Any idea why this isn't working and how would I go about doing this?
Thanks,
I think the main confusion here is between the gradle task life cycle phases. This is quite common when starting out with gradle. I would recommend reading through the above link to get a feel for the phases.
To illustrate here is a complete build.gradle which more or less mirrors your code:
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
task createEnvironment(type: CreateApplicationEnvironmentTask) {
println "configuring CreateApplicationEnvironmentTask"
doLast {
println "execution phase (doLast) CreateApplicationEnvironmentTask"
}
}
task createRecord(type: CreateRecordTask, dependsOn: ['createEnvironment']) {
println "configuration phase value: ${tasks["createEnvironment"].ebCname}"
doLast {
println "execution phase (doLast) value: ${tasks["createEnvironment"].ebCname}"
}
}
class CreateApplicationEnvironmentTask extends DefaultTask {
String ebCname
#TaskAction
def create() {
println "execution phase (class) CreateApplicationEnvironmentTask"
ebCname = "some_value"
}
}
class CreateRecordTask extends DefaultTask {
#TaskAction
def doit() {
println "executin phase (class) CreateRecordTask"
}
}
executing:
~> gradle createRecord
prints:
configuring CreateApplicationEnvironmentTask
configuration phase value: null
:createEnvironment
execution phase (class) CreateApplicationEnvironmentTask
execution phase (doLast) CreateApplicationEnvironmentTask
:createRecord
executin phase (class) CreateRecordTask
execution phase (doLast) value: some_value
BUILD SUCCESSFUL
when you execute any gradle task on a build.gradle file (or even just execute gradle tasks to print the available tasks), the build file is evaluated and the configuration phase code is run. This includes the code inside the curlies of any task foo { ... } definition, even if that task is not executed.
In contrast, the code inside the doLast block task foo { doLast { ... }} is executed in the execution phase.
The reason you were seeing a null value is that you set the property ebCname in your task action method (execution phase), but you are printing it in the configuration phase. Thus it has not been set yet. Either setting the value in the configuration phase (in the constructor of the class, directly when you declare the field, of inside the task declaration
task createRecord(type: CreateRecordTask...) {
ebCname = "foo"
}
) or referring to the value in the execution phase will give you a non-null value.

How to use gradle extension correctly in plugins using GradleBuild task?

EDIT : I rephrased my question in taken the propositon of David M. Karr into account.
I am writing a gradle plugin. This plugin is launching a task extending GradleBuild. The external gradle build file needs some info as parameters. These parameters are given in project extension.
Plugin code
class MyPlugin implements Plugin<Project> {
def mExt
void apply(Project project) {
mExt = project.extensions.create('myext',MyExt)
project.task('myTask', type:GradleBuild){
def param = new StartParameter()
param.setProjectProperties([target:getTarget()])
// Problem here
startParameter = param
buildFile = getMyBuildPath()
tasks = [
'build',
'generateDebugJavadocJar'
]
}
}
def getMyBuildPath(){
...
}
// Problem here
def getTarget(){
return {mExt.target}
}
}
class MyExt {
def String target = "uninitialised"
}
Gradle build file :
apply plugin : 'com.example.myplugin'
ext{
target = "myTarget"
}
External Gradle build file :
task build(){
println project.target
}
If I put a closure in getTarget(), println project.target shows the closure and not the string.
If I don't put the closure :
// Problem here
def getTarget(){
return mExt.target
}
Then I got "uninitialised" instead of "myTarget".
How can I get the value of myext.target here ?
I am using gradle 2.3
Try this:
Define an instance variable called "myext", of type "MyExt".
In the "apply" method, do this:
myext = project.extensions.create('myext',MyExt)
In the "getTarget" method, return "myext.target".
I have succeeded in getting what I wanted to in using project.afterEvaluate method. Thanks to this question
1) In gradle build task, startParameter.projectProperties is waiting for a map, not a closure. So the idea to put a closure for a lazy definition cannot work.
2) If I put directly in my plugin a reference to mExt.target or project.myext.target, then the initial value is set. The value put in my build.gradle file is not used because the plugin is already evaluated.
3) project.afterEvaluate() solve my problem. The closure ends configuring myTask in using the project's extension.
void apply(Project project) {
project.extensions.create('myext',MyExt)
project.task('myTask', type:GradleBuild){
buildFile = getMyBuildPath()
tasks = [
'build',
'generateDebugJavadocJar'
]
}
project.afterEvaluate { proj ->
proj.myTask.startParameter.projectProperties = [target:proj.myext.target]
}
}

How to pass arguments from command line to Gradle

I'm trying to pass an argument from command line to a Java class. I followed this post: http://gradle.1045684.n5.nabble.com/Gradle-application-plugin-question-td5539555.html but the code does not work for me (perhaps it is not meant for JavaExec?). Here is what I tried:
task listTests(type:JavaExec){
main = "util.TestGroupScanner"
classpath = sourceSets.util.runtimeClasspath
// this works...
args 'demo'
/*
// this does not work!
if (project.hasProperty("group")){
args group
}
*/
}
The output from the above hard coded args value is:
C:\ws\svn\sqe\sandbox\selenium2forbg\testgradle>g listTests
:compileUtilJava UP-TO-DATE
:processUtilResources UP-TO-DATE
:utilClasses UP-TO-DATE
:listTests
Received argument: demo
BUILD SUCCESSFUL
Total time: 13.422 secs
However, once I change the code to use the hasProperty section and pass "demo" as an argument on the command line, I get a NullPointerException:
C:\ws\svn\sqe\sandbox\selenium2forbg\testgradle>g listTests -Pgroup=demo -s
FAILURE: Build failed with an exception.
* Where:
Build file 'C:\ws\svn\sqe\sandbox\selenium2forbg\testgradle\build.gradle' line:25
* What went wrong:
A problem occurred evaluating root project 'testgradle'.
> java.lang.NullPointerException (no error message)
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating root project
'testgradle'.
at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:127)
at org.gradle.configuration.BuildScriptProcessor.evaluate(BuildScriptProcessor.java:38)
There is a simple test project available at http://gradle.1045684.n5.nabble.com/file/n5709919/testgradle.zip that illustrates the problem.
This is using Gradle 1.0-rc-3. The NullPointer is from this line of code:
args group
I added the following assignment before the task definition, but it didn't change the outcome:
group = hasProperty('group') ? group : 'nosuchgroup'
Any pointers on how to pass command line arguments to Gradle appreciated.
project.group is a predefined property. With -P, you can only set project properties that are not predefined. Alternatively, you can set Java system properties (-D).
As noted in a comment, my solution is superceded by the newer built-in --args option in gradle. See this answer from #madhead or this similar question.
Building on Peter N's answer, this is an example of how to add (optional) user-specified arguments to pass to Java main for a JavaExec task (since you can't set the 'args' property manually for the reason he cites.)
Add this to the task:
task(runProgram, type: JavaExec) {
[...]
if (project.hasProperty('myargs')) {
args(myargs.split(','))
}
... and run at the command line like this
% ./gradlew runProgram '-Pmyargs=-x,7,--no-kidding,/Users/rogers/tests/file.txt'
My program with two arguments, args[0] and args[1]:
public static void main(String[] args) throws Exception {
System.out.println(args);
String host = args[0];
System.out.println(host);
int port = Integer.parseInt(args[1]);
my build.gradle
run {
if ( project.hasProperty("appArgsWhatEverIWant") ) {
args Eval.me(appArgsWhatEverIWant)
}
}
my terminal prompt:
gradle run -PappArgsWhatEverIWant="['localhost','8080']"
As of Gradle 4.9 Application plugin understands --args option, so passing the arguments is as simple as:
build.gradle
plugins {
id 'application'
}
mainClassName = "my.App"
src/main/java/my/App.java
public class App {
public static void main(String[] args) {
System.out.println(args);
}
}
bash
./gradlew run --args='This string will be passed into my.App#main arguments'
or in Windows, use double quotes:
gradlew run --args="This string will be passed into my.App#main arguments"
You can use custom command line options in Gradle:
./gradlew printPet --pet="Puppies!"
Custom command line options were an incubating feature in Gradle 5.0 but became public in Gradle 6.0.
Java solution
Follow the instructions here:
import org.gradle.api.tasks.options.Option;
public class PrintPet extends DefaultTask {
private String pet;
#Option(option = "pet", description = "Name of the cute pet you would like to print out!")
public void setPet(String pet) {
this.pet = pet;
}
#Input
public String getPet() {
return pet;
}
#TaskAction
public void print() {
getLogger().quiet("'{}' are awesome!", pet);
}
}
Then register it:
task printPet(type: PrintPet)
Now you can do:
./gradlew printPet --pet="Puppies!"
output:
Puppies! are awesome!
Kotlin solution
open class PrintPet : DefaultTask() {
#Suppress("UnstableApiUsage")
#set:Option(option = "pet", description = "The cute pet you would like to print out")
#get:Input
var pet: String = ""
#TaskAction
fun print() {
println("$pet are awesome!")
}
}
then register the task with:
tasks.register<PrintPet>("printPet")
If you need to check and set one argument, your build.gradle file would be like this:
....
def coverageThreshold = 0.15
if (project.hasProperty('threshold')) {
coverageThreshold = project.property('threshold').toString().toBigDecimal()
}
//print the value of variable
println("Coverage Threshold: $coverageThreshold")
...
And the Sample command in windows:
gradlew clean test -Pthreshold=0.25
I have written a piece of code that puts the command line arguments in the format that gradle expects.
// this method creates a command line arguments
def setCommandLineArguments(commandLineArgs) {
// remove spaces
def arguments = commandLineArgs.tokenize()
// create a string that can be used by Eval
def cla = "["
// go through the list to get each argument
arguments.each {
cla += "'" + "${it}" + "',"
}
// remove last "," add "]" and set the args
return cla.substring(0, cla.lastIndexOf(',')) + "]"
}
my task looks like this:
task runProgram(type: JavaExec) {
if ( project.hasProperty("commandLineArgs") ) {
args Eval.me( setCommandLineArguments(commandLineArgs) )
}
}
To pass the arguments from the command line you run this:
gradle runProgram -PcommandLineArgs="arg1 arg2 arg3 arg4"
There's a great example here:
https://kb.novaordis.com/index.php/Gradle_Pass_Configuration_on_Command_Line
Which details that you can pass parameters and then provide a default in an ext variable like so:
gradle -Dmy_app.color=blue
and then reference in Gradle as:
ext {
color = System.getProperty("my_app.color", "red");
}
And then anywhere in your build script you can reference it as course anywhere you can reference it as project.ext.color
More tips here: https://kb.novaordis.com/index.php/Gradle_Variables_and_Properties
Here is a solution for Kotlin DSL (build.gradle.kts).
I first try to get the variable as a property and if it was null try to get it from OS environment variables (can be useful in CIs like GitHub Actions).
tasks.create("MyCustomTask") {
val songName = properties["songName"]
?: System.getenv("SONG_NAME")
?: error("""Property "songName" or environment variable "SONG_NAME" not found""")
// OR getting the property with 'by'. Did not work for me!
// For this approach, name of the variable should be the same as the property name
// val songName: String? by properties
println("The song name: $songName")
}
We can then pass a value for the property from command line:
./gradlew MyCustomTask -PsongName="Black Forest"
Or create a file named local.properties at the root of the project and set the property:
songName=Black Forest
We can also add an env variable named SONG_NAME with our desired value and then run the task:
./gradlew MyCustomTask
pass a url from command line keep your url in app gradle file as follows
resValue "string", "url", CommonUrl
and give a parameter in gradle.properties files as follows
CommonUrl="put your url here or may be empty"
and pass a command to from command line as follows
gradle assembleRelease -Pcommanurl=put your URL here

Resources