I have a PicocliScript2 annoatated groovy script. I have been trying hard to figure out how to handle exceptions and haven't exeprienced luck thus far.
PicocliScript2 swallows all exceptions.
Going by the documentaion it seems simple to implement with java/groovy classes. There are tons of usecases/customizations be it parsing errors or execution error, but it gets trickier everytime I try to implement in a script.
This is such a versatile cli tool, but I believe I am being limited by the choice of implementation here/or perhaps my lack of knowledge thereof. Currently I would want to implement it via script only.
EDIT 1 : START
Background : When a picocli script is executed by passing incomplete set of arguments or no arguments at all, the script does not throw error. It nicely tells the user that the script is missing arguments, like
args: []
Missing required options: '--first-name=firstName', '--last-name=lastName'
This is quite helpful to the human user.
But not so much when some other program(like script, service, tool like Jenkins) calls it, unless there is a way to return some exit codes/throw some exception. This is possible in the class based implementations(both java/groovy/kotlin) using rich apis of picoli but not as much help is available when it comes to implementing via a groovy script.
Trying to call the script with wrong commandline arguments from a Jenkins job will still make the job green because Jenkins does not see any exception being thrown by the script.
There has to be a way to deal with this in groovy script based implementation too.
The picocli documentation is so rich, and I blame my own lacking for not being able extract the required info.
Link to mcve : SAMPLE-PICOCLI
The script on the master branch can be used to recreate this issue.
Picocli : 4.7.5
Groovy : 3.0.19
EDIT 1 : END
The picocli user manual has a section on Groovy Scripts: https://picocli.info/#_groovy_scripts
I believe the information you are looking for is in the "Comparison of PicocliBaseScript2
and PicocliBaseScript
script base classes" table:
For PicocliBaseScript2
, Custom handling of invalid user input can be accomplished as follows:
Scripts can override
beforeParseArgs(CommandLine)
to install a customIParameterExceptionHandler
.
See the manual's section on Invalid User Input for what such a handler looks like.
Putting it all together:
// example custom handler
class ShortErrorMessageHandler implements IParameterExceptionHandler {
public int handleParseException(ParameterException ex, String[] args) {
CommandLine cmd = ex.getCommandLine();
PrintWriter err = cmd.getErr();
// if tracing at DEBUG level, show the location of the issue
if ("DEBUG".equalsIgnoreCase(System.getProperty("picocli.trace"))) {
err.println(cmd.getColorScheme().stackTraceText(ex));
}
err.println(cmd.getColorScheme().errorText(ex.getMessage())); // bold red
UnmatchedArgumentException.printSuggestions(ex, err);
err.print(cmd.getHelp().fullSynopsis());
CommandSpec spec = cmd.getCommandSpec();
err.printf("Try '%s --help' for more information.%n", spec.qualifiedName());
return cmd.getExitCodeExceptionMapper() != null
? cmd.getExitCodeExceptionMapper().getExitCode(ex)
: spec.exitCodeOnInvalidInput();
}
}
// in your script, add this to install this custom handler:
@Override
protected CommandLine beforeParseArgs(CommandLine customizable) {
customizable.setParameterExceptionHandler(new ShortErrorMessageHandler());
return super.beforeParseArgs(customizable)
}
(For custom handling of errors that occur during your script's execution, override beforeParseArgs(CommandLine)
to install a custom IExecutionExceptionHandler
.)
This test has some examples.