If you create a command with an option and its arity is ExactlyOne it will not be validated if the option isn't supplied in the arguments.
For example:
var command = new Command("team")
{
new Option("--sport", argument: new Argument<string> { Arity = ArgumentArity.ExactlyOne })
};
command.Handler = CommandHandler.Create(async (string sport) =>
{
// sport is null
...
}
If you call the application with myapp team there is no validation performed against --sport so it can slip through as null in the handler.
If supplied i.e. myapp team --sport then you get validation:
Required argument missing for option: --sport
Thanks, @watermelonpizza. This is the intended design, although it's a bit confusing. What the ExactlyOne arity means in your example (which by the way is the default for Argument<T> in all cases where T is neither bool nor IEnumerable) is that if --sport is specified, it must be provided exactly one argument. It does not mean that the --sport is required when invoking the team command. So:
> team #valid
> team --sport futbol #valid
> team --sport #invalid
I added arity examples to the wiki to help explain. Please let me know if this is helpful and whether there's a clearer way we can communicate the intention.
Ah ok thanks @jonsequitur .
If possible maybe also add some clarification of the automatic assumptions on Arity based on the argument type under perhaps here https://github.com/dotnet/command-line-api/wiki/How-To#argument-validation-and-binding (unless I missed it somewhere else) like what a standard value type like string sets as arity vs. a IEnumerable vs. bool etc.
Also, is there any way to specify an argument as required then? Sometimes like in my case it would be nice to force users to specify an argument for some command/option.
Thanks! :)
An argument with an arity of ExactlyOne is required when its parent command or option is specified.
If you're wondering if there's a way to require that an option be specified (e.g. make --sport required), there's currently a way to do this but it's awkward. We're planning to create a simpler API here, but this will work:
var command = new RootCommand { new Option("-x") };
command.Argument.AddValidator(symbolResult =>
{
聽聽聽聽if (symbolResult.Children["-x"] is null)
聽聽聽聽{
聽聽聽聽聽聽聽聽return "Option -x is required";
聽聽聽聽}
聽聽聽聽else
聽聽聽聽{
聽聽聽聽聽聽聽聽return null;
聽聽聽聽}
});
var result = command.Parse("");
result.Errors.Should().Contain(e => e.Message == "Option -x is required");
Oh, awesome!
Thanks mate. I'll use that in my app. :)
Should I close this issue then?
@jonsequitur It may be meaningful that System.CommandLine understands what Options are required, so no custom validation is needed.
When printing help, required options could be indicated:
For example:
Usage:
program command --required <REQUIRED> [options] <arg>
If we add an intrinsic concept for making an option required, that would make sense.
Another common use case that complicates this is when option A is required only when option B is provided. Thoughts?
Another common use case that complicates this is when option A is required only when option B is provided. Thoughts?
Can it be solved with a validator? :smile:
We also need to think, if the user can express this explicitly, how would we use it.
It can be solved with a validator but displaying the intention of the validator in help is beyond the scope of the validator interface.
Maybe the option/argument objects could have a list of required symbols as a property?
Agreed - a Required boolean property on the Option and then as @tmds mentioned having it auto put in the
@jonsequitur is this fixed or won't fix?
The original issue is closed as, in effect, "by design".
The later discussion around required options and help is potentially worth a separate issue. There have been some help improvements recently: #548.