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
Related
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
}
How do I access the value of an argument from the command line in a gradle task? I know that this can be done by -P but I have the same property in my properties file and gradle picks the argument from the properties file rather than the command line. How do I prioritize accepting arguments from the command line over the properties file?
build.gradle
Properties props = new Properties()
props.load(new FileInputStream("./local.properties"))
props.each { prop ->
project.ext.set(prop.key, prop.value)
}
task print {
println("Gets = ${remote}");
}
local.properties
remote=from_properties
Command from cmd
gradle print -Premote=from_commandline
Output
Gets = from_properties
You shouldn't use your own local.properties file if you intend to use a properties file for Gradle properties.
Just use gradle.properties instead.
Also notice that you shouldn't declare task code inside its configuration block, you need to use doFirst or doLast:
gradle.properties
remote = properties
build.gradle
task print {
doLast { println "Gets = ${remote}" }
}
If you run ./gradlew print you will see Gets = properties.
If you run ./gradlew print -Premote=foo you should see Gets = foo.
That said.... if you really want your own properties file, you need to implement the order of priority yourself, Gradle cannot guess what you prefer.
For example, you could check if a property is already set before setting it:
def props = new Properties()
props.load(new FileInputStream("./local.properties"))
props.each { key, value ->
if (!project.hasProperty(key)) {
project.ext.set(key, value)
}
}
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
So, I am using a plugin in my gradle build (the plugin is org.flywaydb.flyway but that is not really relevant). I want to validate the caller has passed in a runtime parameter when tasks from this plugin are executing but not when other tasks are executing.
I pass options to the flyway plugin based on a supplied parameter. I want an error to be returned when a flywayTask is being executed and no parameter is supplied. When a non-flyway task is being run, I do not want to validate if the parameter is supplied.
gradle -PmyParam=myValue flywayMigration
=> should run code and there should be no error
gradle flywayMigration
=> should run code and should produce error (as no parameter supplied)
gradle jar
=> should not run code and no error should be produced
I have been reading about gradle configuration and execution which is fine but I still can't find a way to only run the code when the flyway plugin is bveing executed OR specific flyway tasks are being executed.
This is my current code:
if(gradle.taskGraph.hasTask("flywayMigrate")) {
flyway {
def dbCode, dbUser, dbPassword, dbUrl
if (!project.hasProperty("db_env")) {
throw new GradleException("Expected db_env property to be supplied for migration task. Can be passed" +
" at command line e.g. [gradle -Pdb_env=ex1 flywayMigrate]")
} else {
// do stuff
}
user = balh
password = blah
url = blah
driver = 'oracle.jdbc.OracleDriver'
cleanDisabled = true
baselineOnMigrate = true
baselineVersion = '1.0.0'
}
}
To be clear, I only want this code:
if (!project.hasProperty("db_env")
to run for flyway tasks.
The code above throws this error:
Task information is not available, as this task execution graph has not been populated.
I've tried a few things here, any advice would be appreciated.
It's not really clear to me, what exactly do you want to do in case if this property is provided, but I think, you can do it without accesing task graph, just try to use doFirst Closure of the flywayMigrate task. Just something like this:
flywayMigrate.doFirst {
if(!project.hasProperty("db_env")) {
throw ...
} else {
//Do something
}
}
And leave your plugin configuration free of any additional logic.
As for exception, have you tried to wait until graph is ready? It's usualy done as follows:
gradle.taskGraph.whenReady {taskGraph ->
if(gradle.taskGraph.hasTask("flywayMigrate")) {
...
}
}
Update: to answer the question from the comments
if I can attach doFirst to multiple tasks?
Yes, you can use somthing like:
//declare task names
def names = ["taskA", "taskB", "taskC"]
tasks.findAll {it ->
//filter tasks with names
if (it.name in names)
return it
}.each { it ->
//add some extra logic to it's doFirst closure
it.doFirst {
println 'hello'
}
}
Just check, that all the tasks are exists before this configuration.
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]
}
}