Follow-up from #6349 / #8664.
The CommandLineConfigurationSource flattens CLI options into IConfiguration with two shapes:
- Zero-arity flags →
commandLineOptions:<name> = ""true"" (presence marker)
- Arg-bearing options →
commandLineOptions:<name>:0, :1, … (one entry per arg)
In testconfig.json users naturally write scalars:
{
""commandLineOptions"": {
""timeout"": ""30s""
}
}
Today this is parsed as a presence marker (commandLineOptions:timeout = ""30s""), not as the first arg of --timeout. So TryGetCommandLineOptionArguments(""timeout"") returns no args and the option silently misbehaves. The workaround documented in #8664 is to always use the array form (""timeout"": [""30s""]), but nothing enforces or guides this today.
Proposal
The new CommandLineOptionsValidator JSON pass already knows each option's registered arity. Extend it so the scalar/array shape is reconciled against arity:
- Arg-bearing option + scalar value → auto-promote to single-element array (
""timeout"": ""30s"" ⇒ ""timeout"": [""30s""]). Transparent to the user, best UX.
- Zero-arity option + array value → fail with a clear error (
""--no-banner takes no arguments"").
- Arg-bearing option + array with wrong cardinality → already covered by the existing arity pass.
Option (1) is the high-leverage one — it removes the foot-gun entirely without breaking anything.
Alternative if we prefer strict-mode: fail-fast on scalars for arg-bearing options with an error pointing to the array form. Less friendly but unambiguous.
cc related: #8829
Follow-up from #6349 / #8664.
The
CommandLineConfigurationSourceflattens CLI options intoIConfigurationwith two shapes:commandLineOptions:<name>=""true""(presence marker)commandLineOptions:<name>:0,:1, … (one entry per arg)In
testconfig.jsonusers naturally write scalars:{ ""commandLineOptions"": { ""timeout"": ""30s"" } }Today this is parsed as a presence marker (
commandLineOptions:timeout=""30s""), not as the first arg of--timeout. SoTryGetCommandLineOptionArguments(""timeout"")returns no args and the option silently misbehaves. The workaround documented in #8664 is to always use the array form (""timeout"": [""30s""]), but nothing enforces or guides this today.Proposal
The new
CommandLineOptionsValidatorJSON pass already knows each option's registered arity. Extend it so the scalar/array shape is reconciled against arity:""timeout"": ""30s""⇒""timeout"": [""30s""]). Transparent to the user, best UX.""--no-banner takes no arguments"").Option (1) is the high-leverage one — it removes the foot-gun entirely without breaking anything.
Alternative if we prefer strict-mode: fail-fast on scalars for arg-bearing options with an error pointing to the array form. Less friendly but unambiguous.
cc related: #8829