Pass arguments to gradle task from command line - gradle

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)
}
}

Related

Gradle processResources expand on different projects modules

i'm trying to get a project.version so i wrote project2 gradle before codes
processResources {
def props = ['version': project.properties.get('version')]
filesMatching("**/MyConfiguration.kt") {
expand(props)
}
}
the MyConfiguration.kt file located project1 but the code return null
so i fixed codes like below
processResources {
def props = ['version': project.properties.get('version')]
expand(props)
}
then that codes return right value
maybe the problem is filesMatching input another module file?
i missed filesMatching input
need to setup .properties or .yaml (get project.properties this scope)

Set the properties in the configuration phase of a task in another task

I have spent the last few hours trying to find a solution for my requirement, without luck:
I have a task that has to run some logic in a certain path:
task run(type: MyPlugin) {
pathForPlugin = myPath //Defined as a property in another gradle file
}
I want to set the "pathForPlugin" property dynamically in another task because it has to be read from some configuration file.
task initPaths(type: PathFinder) {
configurationFile = 'C:\\myConfig.conf'
}
The myConfig.conf would look like this:
pathForPlugin = 'C:\\Correct\\Path'
The problem is that "initPaths" has to run before the configuration phase of "run".
I have tried several approaches for this (GradleBuild task, dependsOn, Using Properties in the Plugin for "Lazy Configuration") but every approach only takes effect in the Execution phase leading to the "pathForPlugin" always staying at its default value.
Is there some way i can realize this or should i look for another solution outside of the gradle build?
I found a solution for the problem:
Instead of defining a task "initPaths" i directly used the java class "Pathfinder" in the build script:
import mypackage.PathFinder;
new PathFinder(project).run()
You only have to make sure that this part is above the definition of the task where the properties are used.
I admit this is a bit of a "hacky" solution but it works fine for my requirement.
you can do like this:
ext {
myPath //use it as a global variable that you can set and get from different gradle tasks and files
}
task firstTask {
doLast {
ext.myPath = "your path"
}
}
task run(type: MyPlugin) {
doFirst { //executed on runtime not on task definition
pathForPlugin = ext.myPath //Defined as a property in another gradle file
}
}
//example 2 - create run task dynamic
task initPath {
doLast {
tasks.create(name: "run", type: MyPlugin) {
pathForPlugin = ext.myPath
}
}
}

Conditional logic in gradle build to only execute certain code when a specific task is running

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.

How do I define a gradle build script environment variable from a file in my src/main/resources directory?

I'm using Gradle 2.7 on Windows 7. I have a properties file, "src/main/resources/liquibase.properties", whose properties I would like to reference in my build.gradle script. So for instance in my properties file I have
url=jdbc:mysql://localhost:3306/my_db
username=myuser
password=mypass
I would like to reference these in my script like so ...
liquibase {
activities {
main {
changeLogFile 'src/main/resources/db.changelog-1.0.xml'
url '${url}'
username '${username}'
password '${password}'
}
}
}
Also I would like to do this by just runing "gradle build" without having to specify any additional parameters on teh command line. How can I do this?
Thanks, - Dave
You can load the properties file then get the values from that... Here is an example
liquibase {
activities {
main {
File propsFile = new File("${project.rootDir}/src/main/resources/liquibase.properties")
Properties properties = new Properties()
properties.load(new FileInputStream(propsFile))
changeLogFile 'src/main/resources/db.changelog-1.0.xml'
url properties['url']
username properties['username']
password properties['password']
}
}
}

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