I have dynamic defined a task in build.gradle, that inherits from another task.
In the following I'm using kotlin-DSL, but I'm happy with solutions for groovy dsl as well.
task.register<GenerateTask>("generateCode") {
// stuff
outputDir.set("$rootDir")
}
As you can see I had to define the output as rootDir.
However I'm setting options to only create part of the output.
All the generated code is in a specificPackage meaning it will all end up in:
$rootDir/src/main/my/generated/package/name
$rootDir/src/test/my/generated/package/name
However due to outputDir being set it assumes the whole rootdir is an output and warns me accordingly.
Now I would like to tell gradle, that this task only produces those two packages.
I tried overwriting outputs but it is readonly.
I tried overwriting outputs.files but it is readonly.
I tried using outputs.files.setFrom() as described here, but this seems no longer to be valid.
Is there a way to set outputDir, but not add the value it to outputs or a way to clear the outputs list?
Related
I would like to execute a gradle luqibase plugin diffChangelog task with my custom arguments from command line.
I DO NOT want to add/modify any of the project files, no modifications of build.gradle, no gradle.properties or such i just want to run a task and pass its parameters from command line and i am so far unable to do so i would like to distribute my script that executes this task in one bash file.
I have a problem even figuring out how to pass parameters to a gradle task, moreover even the format of the arguments is confusing - there are documentation snippets pointing that i should use camelCase or hyphenated version also zero/one/two hyphens are possible in the beginning . Additionally can either use -P or -D to pass arguments to gradle so far none of it seem to work it looks like the arguments are not being passed at all.
I would like to execute something like:
./gradlew diffChangelog --url=AA --username=BB --password=CC --reference-username=DD --reference-password=EE --reference-url=FF --changelog-gile=GG
Of course proper values will be provided by inline.
Is there a concise way to do so? So far googling up for the solution results in multiple complex explanations requiring modification of existing files and then passing arguments, is there really no way of just running a gradle task with arguments or am i missing something?
Update:
The error i am alyways getting is:
liquibase.exception.CommandValidationException: Invalid argument '--reference-url': missing required argument
You should check what end of line you have. This can sometimes be resolved by changing the end of line from from windows eol to linux.
Reference:
Unexpected error running Liquibase: Unexpected value [...] (options must start with a '--') && howTo? diff w/ properties file
I have a build.gradle with the following contents:
task myTask {
inputs.file("input.txt").optional()
doLast { println "input.txt exists = " + file("input.txt").exists() }
}
If input.txt doesn't exist, it fails with:
File '/Users/skissane/testgradle/input.txt' specified for property '$1' does not exist.
What I am trying to do, is run a custom script–which is written in Groovy, and runs inside the Gradle build under doLast, not as an external process–which takes the input.txt file as input, and the script's behaviour and output will change based on what is in that input file. But it is an optional input file – the script will still generate output (albeit different output) even if the input file doesn't exist.
Things I have tried so far:
Remove .optional(), change it to .optional(true): no difference in results
Instead of .optional(), wrap it in if (file("input.txt").exists()) {: this works, but seems ugly. Why doesn't .optional() work?
Have I misunderstood what .optional() is meant to do? Because another answer suggests it is the right way to solve my problem, but it isn't working.
(I am using Gradle 6.8.3. I tried upgrading to the latest Gradle 7.2, the same problem occurs, although 7.2 has more detailed error messages.)
optional() can't be used to mark the file itself as optional. optional() just means that the input property is optional, and the task is still valid if no files at all are specified; but if a file is specified, it must exist.
As such, optional() isn't really useful in this kind of custom task declared directly in build.gradle. It is really intended for defining new task types in plugins, when one defines a new task input property other than inputs, and wants to make it optional to declare files for that property. It is the property itself which is made optional, not the files in it. On a custom task, declaring inputs as optional is pointless because it is already optional to begin with.
Right now (as of version 7.2), Gradle doesn't have any way to mark a file as an optional input, other than through if (file("input.txt").exists()) {. Hopefully they might add that feature in some future Gradle version.
(Thanks to James Justinic who answered my post about this on Gradle forums.)
I've been struggling with this for a day and a half or so. I'm trying to replicate the following Ant concept in Gradle:
<target name="test">
...
<runexe name="<filename> params="<params>" />
...
</target>
where runexe is declared elsewhere as
<macrodef name="runexe" >
...
</macrodef>
and might also be a taskdef or a scriptdef i.e. I'd like to be able to call a reusable, pre-defined block of code and pass it the necessary parameters from within Gradle tasks. I've tried many things. I can create a task that runs the exe without any trouble:
task runexe(type: Exec){
commandLine 'cmd', '/c', 'dir', '/B'
}
task test(dependsOn: 'runexe') {
runexe {
commandLine 'cmd', '/c', 'dir', '/N', 'e:\\utilities\\'
}
}
test << {
println "Testing..."
// I want to call runexe here.
...
}
and use dependsOn to have it run. However this doesn't allow me to run runexe precisely when I need to. I've experimented extensively with executable, args and commandLine. I've played around with exec and tried several different variations found here and around the 'net. I've also been working with the free books available from the Gradle site.
What I need to do is read a list of files from a directory and pass each file to the application with some other arguments. The list of files won't be known until execution time i.e. until the script reads them, the list can vary and the call needs to be made repeatedly.
My best option currently appears to be what I found here, which may be fine, but it just seems that there should be a better way. I understand that tasks are meant to be called once and that you can't call a task from within another task or pass one parameters but I'd dearly like to know what the correct approach to this is in Gradle. I'm hoping that one of the Gradle designers might be kind enough to enlighten me as this is a question asked frequently all over the web and I'm yet to find a clear answer or a solution that I can make work.
If your task needs to read file names, then I suggest to use the provided API instead of executing commands. Also using exec will make it OS specific, therefore not necessarily portable on different OS.
Here's how to do it:
task hello {
doLast {
def tree = fileTree(dir: '/tmp/test/txt')
def array = []
tree.each {
array << it
print "${it.getName()} added to array!\n"
}
}
}
I ultimately went with this, mentioned above. I have exec {} working well in several places and it seems to be the best option for this use case.
To please an overzealous moderator, that means this:
def doMyThing(String target) {
exec {
executable "something.sh"
args "-t", target
}
}
as mentioned above. This provides the same ultimate functionality.
I wrote a custom gradle task class (say PrintNameTask) that accepts some input parameter (say name).
Then if I define a printName task of type PrintNameTask like below:
task printName(type: PrintNameTask) {
name = project.name
}
and invoke it from command prompt like below I can see the passed name printed out
$gradle printName -Pname=myName
myName
However if I invoke any other task like clean or build the build fails because there is no property called name passed. This is fair enough as my printName is a configure closure and is evaluated all the times.
To address this I tried to change the configure closure into a task action closure like below:
task printName(type: PrintNameTask) << {
// What should I put on here?
name = ???
// or
name ???
}
But it was no way to make it work. I tried project.name, getProperty("name") and a few more other combinations but nothing worked. All I get back is:
* What went wrong:
A problem was found with the configuration of task ':printName'.
No value has been specified for property 'name'.
This kind of requirement looks to me quite basic and it is a bit frustrating that tons of books and documentation are published but they only shows trivial examples. Maybe is just me but at the point of asking this question my initial gradle enthusiasm is more than half gone. Anyway thank you in advance for your inputs.
Configure the task in the following way:
task printName(type: PrintNameTask) {
name = project.hasProperty('name') ? project.name : '' // or null
}
Since this closure is evaluated at configuration phase it's executed every time the script is processed. You just need to check if the property is present.
It is convenient to debug some of external libraries and even internal code while writing unit tests by reviewing the logging on stdout.
While I can add test.testLogging.showStandardStreams = true to the build.graddle file, I'd rather do something less permanent, such as setting this flag from the command line execution of gradle.
I've tried several approaches, none seem to work:
gradle test -Dtest.testLogging.showStandardStreams=true
gradle test -Ptest.testLogging.showStandardStreams=true
And other variations of those options by changing the property string. Nothing seems to do the trick.
How do I set test.testLogging.showStandardStreams=true from the command line?
There is no built-in way to set build model properties from the command line. You'll have to make the build script query a system or project property that gets passed in via -D or -P, respectively.
Just use environment variables:
test {
testLogging.showStandardStreams = (System.getenv('PRINTF_DEBUG') != null)
}
Now run your test case like this:
PRINTF_DEBUG=1 ./gradlew test --tests=com.yourspace.yourtest
This will run enable console output and just run one single test case. You often not want to enable console output for the entire test suite because of the noise generated.
You can override it like this
gradle -Doverride.test.testLogging.info.showStandardStreams=true test
or you can add this to your gradle.properties either in the project or in ~/.gradle/gradle.properties
systemProp.override.test.testLogging.info.showStandardStreams=true