I am trying to integrate the generation of REST-API client code via the openapi-generator through Gradle. Using the openapi-generator-gradle-plugin at first, I found some bugs that make it impossible to achieve what I want, so I thought I might just download the JAR of the openapi-generator-cli in order to define a Gradle task with javaExec that will execute the generator for me.
The task looks is defined as:
build.gradle.kts
task("generate") {
javaexec {
main = "-jar"
args = listOf(
"$rootDir\\openapi-generator-cli.jar",
"generate",
"--skip-validate-spec",
"-g kotlin",
"-i $rootDir\\spec\\api.yml",
"-o $rootDir\\lib",
"-c $rootDir\\generate-kotlin.json"
)
}
}
However, when running the generate task, execution fails with
C:\work\kotlin\myapi\generate-kotlin.json (The filename, directory name, or volume label syntax is incorrect)
This is where things get strange, as I can see no issue with the path to the file in question.
I then activated debugging output for the task to see the actual command executed by Gradle. It is (formatted for readability):
C:\Program Files\Java\jdk1.8.0_202\bin\java.exe ^
-Dfile.encoding=windows-1252 ^
-Duser.country=DE ^
-Duser.language=de ^
-Duser.variant ^
-jar C:\work\kotlin\myapi\openapi-generator-cli.jar generate ^
--skip-validate-spec ^
-g kotlin ^
-i C:\work\kotlin\myapi\spec\api.yml ^
-o C:\work\kotlin\myapi\lib ^
-c C:\work\kotlin\myapi\generate-kotlin.json
To me, everything looks perfectly fine in that command. To test, I copy-pasted it to a CMD and it ran right away without any errors.
Despite the question being a bit centered around openapi-generator, as I can run the command perfectly fine manually, I assume this to be a problem with Gradle and would really like to know why it is receiving this error when the command it runs has no issues whatsoever?
I really don't want to write command-line scripts for people to execute when I could let Gradle do what I want to do.
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 basically try to run the example 3.11 in Odersky's book (Programming in Scala). I am using Intellij IDE. While runing the code, the "else" branch got executed.
The screen capture is here:
The source is here in case you need it to try:
package ch3
import scala.io.Source
object l3p11 extends App{
def widthOfLength(s: String) = s.length.toString.length
if (args.length > 0){
val lines = Source.fromFile(args(0)).getLines().toList
val longestLine = lines.reduceLeft(
(a, b) => if (a.length > b.length) a else b
)
val maxWidth = widthOfLength(longestLine)
for (line <- lines){
val numSpaces = maxWidth - widthOfLength(line)
val padding = " " * numSpaces
println(padding + line.length + "|" + line)
}
}
else
Console.err.println("Please enter filename")
}
The reason, I think, is becuase I did not pass args correctly (say here I want to pass the source file l3p11.scala as the args). I tried several option, but have not find a way to pass the args correctly for the code to be executed in the "if" branch. There are two directions in my mind to resolve this problem:
1. Find the right way to pass args in Intellij IDE
Run Scala in commond line, a similar command such as
$ scala l3p11.scala l3p11.scala
should be able to pass the args correctly. But my current setting gives "bash: scala: command not found". I currently use scala REPL to run scala code following the set up given in Odersky's Coursera course on Scala. I think I need to change the set up in orde run scala directly, instead of using "sbt->console" to invoke the scala interpreter like what I am doing now.
Any suggestion on either direction (or other directions that I have not thought of) to resolve the problem is welcome.
Update 1:
Direction 2 works after I reinstall scala. (My to be corrected understanding is that the installation of sbt does not provide an executable binary of scala to be included in the environment list for Windows. Therefore, scala command cannot be found before). After installation of scala directly:
$ scala l3p11.scala l3p11.scala
gives the expected results. But I still have not figured out how to get this result with Intellij IDEA.
Update 2:
I revisited the "Program arguments" option after Joe's confirmation. The reason I was not be able to get it work before was that I only add "l3p11.scala". Adding the complete path from working directory "src/main/scala/ch3/l3p11.scala" solved the problem. The result is as following:
To pass command-line arguments when running a program in IntelliJ IDEA, use the "Edit Configurations …" menu item under "Run". Choose the entry for your main program. There's a "Program arguments" text field where you specify the arguments to pass to the program.
I'm not super familiar on how it will run on windows but if you are able to run it directly from the command line then I think you'll need to compile first, that's the scalac command. So:
$ scalac l3p11.scala
then you can run just with the class name, not sure if you would need quotes on the arg:
$ scala l3p11 l3p11.scala
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.
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