Skip to content

Commit e3bc012

Browse files
authored
fix(Mandatory args error): Show missing cases (#236)
1 parent 5fb339f commit e3bc012

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

RELEASE_NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 6.2.3
2+
* Improve error message on missing cases on a subcommands (display all missing cases) [#236](https://github.com/fsprojects/Argu/pull/236) [@fpellet](https://github.com/fpellet)
3+
* Fix the regression of the [#127](https://github.com/fsprojects/Argu/pull/127) merged in 6.1.2 and fix usage display when there are missing case in subcommands. [#236](https://github.com/fsprojects/Argu/pull/236) [@fpellet](https://github.com/fpellet)
4+
15
### 6.2.2
26
* Fix default `programName` when invoking via a wrapper such as `dotnet.exe` [#233](https://github.com/fsprojects/Argu/pull/233)
37

src/Argu/Parsers/Cli.fs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ type CliParseResultAggregator internal (argInfo : UnionArgInfo, stack : CliParse
7979
let unrecognized = ResizeArray<string>()
8080
let unrecognizedParseResults = ResizeArray<obj>()
8181
let results = lazy(argInfo.Cases.Value |> Array.map (fun _ -> ResizeArray<UnionCaseParseResult>()))
82-
let missingMandatoryCasesOfNestedResults = ResizeArray<UnionCaseArgInfo>()
82+
let missingMandatoryCasesOfNestedResults = ResizeArray<UnionArgInfo * UnionCaseArgInfo list>()
8383

8484
member val IsUsageRequested = false with get,set
8585

@@ -135,7 +135,11 @@ type CliParseResultAggregator internal (argInfo : UnionArgInfo, stack : CliParse
135135
IsUsageRequested = x.IsUsageRequested
136136
MissingMandatoryCases = [
137137
yield! missingMandatoryCasesOfNestedResults
138-
yield! argInfo.Cases.Value |> Seq.filter (fun case -> case.IsMandatory.Value && results.Value[case.Tag].Count = 0)
138+
139+
match argInfo.Cases.Value |> Seq.filter (fun case -> case.IsMandatory.Value && results.Value[case.Tag].Count = 0) |> Seq.toList with
140+
| [] -> ()
141+
| missingCases ->
142+
yield argInfo, missingCases
139143
]
140144
}
141145

src/Argu/Parsers/Common.fs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ let postProcessResults (argInfo : UnionArgInfo) (ignoreMissingMandatory : bool)
7070
| _, ts' -> ts'
7171

7272
match combined, commandLineResults with
73-
| _, Some { MissingMandatoryCases = missingCase::_ } when not ignoreMissingMandatory ->
74-
error argInfo ErrorCode.PostProcess "missing parameter '%s'." missingCase.Name.Value
73+
| _, Some { MissingMandatoryCases = (caseArgInfo, missingCases)::_ } when not ignoreMissingMandatory ->
74+
let allCasesFormatted = missingCases |> Seq.map (fun c -> c.Name.Value) |> fun v -> System.String.Join("', '", v)
75+
error caseArgInfo ErrorCode.PostProcess "missing parameter '%s'." allCasesFormatted
7576

7677
| [||], _ when caseInfo.IsMandatory.Value && not ignoreMissingMandatory ->
7778
error argInfo ErrorCode.PostProcess "missing parameter '%s'." caseInfo.Name.Value

src/Argu/UnionArgInfo.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ type UnionParseResults =
204204
UnrecognizedCliParseResults : obj list
205205
/// Usage string requested by the caller
206206
IsUsageRequested : bool
207-
MissingMandatoryCases: UnionCaseArgInfo list
207+
MissingMandatoryCases: (UnionArgInfo * UnionCaseArgInfo list) list
208208
}
209209

210210
type UnionCaseArgInfo with

tests/Argu.Tests/Tests.fs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ module ``Argu Tests Main List`` =
8080
interface IArgParserTemplate with
8181
member this.Usage = "gus"
8282

83+
type MultipleMandatoriesSubCommand =
84+
| [<Mandatory>] ValueA of int
85+
| [<Mandatory>] ValueB of int
86+
| [<Mandatory>] ValueC of int
87+
| ValueD of int
88+
interface IArgParserTemplate with member this.Usage = "multiple mandatories subcommand arg"
89+
8390
type Argument =
8491
| [<AltCommandLine("-v"); Inherit>] Verbose
8592
| Working_Directory of string
@@ -116,6 +123,7 @@ module ``Argu Tests Main List`` =
116123
| [<CliPrefix(CliPrefix.None)>] Clean of ParseResults<CleanArgs>
117124
| [<CliPrefix(CliPrefix.None)>] Required of ParseResults<RequiredSubcommand>
118125
| [<CliPrefix(CliPrefix.None)>] Unrecognized of ParseResults<GatherUnrecognizedSubcommand>
126+
| [<CliPrefix(CliPrefix.None)>] Multiple_Mandatories of ParseResults<MultipleMandatoriesSubCommand>
119127
| [<SubCommand; CliPrefix(CliPrefix.None)>] Nullary_Sub
120128
interface IArgParserTemplate with
121129
member a.Usage =
@@ -150,6 +158,7 @@ module ``Argu Tests Main List`` =
150158
| Clean _ -> "clean state"
151159
| Required _ -> "required subcommand"
152160
| Unrecognized _ -> "unrecognized subcommand"
161+
| Multiple_Mandatories _ -> "multiple mandatories subcommand"
153162
| Nullary_Sub -> "nullary subcommand"
154163
| List _ -> "variadic params"
155164
| Optional _ -> "optional params"
@@ -474,6 +483,12 @@ module ``Argu Tests Main List`` =
474483
raisesWith<ArguParseException> <@ parser.ParseCommandLine args @>
475484
(fun e -> <@ e.FirstLine.Contains "--branch" @>)
476485

486+
[<Fact>]
487+
let ``Main command parsing should fail and display all missing mandatories sub command parameters`` () =
488+
let args = [|"--mandatory-arg" ; "true" ; "multiple-mandatories" ; "--valuea"; "5"|]
489+
raisesWith<ArguParseException> <@ parser.ParseCommandLine args @>
490+
(fun e -> <@ e.FirstLine.Contains "ERROR: missing parameter '--valueb', '--valuec'." @>)
491+
477492
[<Fact>]
478493
let ``Main command parsing should not fail on missing mandatory sub command parameter if ignoreMissing`` () =
479494
let args = [|"--mandatory-arg" ; "true" ; "checkout" |]
@@ -661,7 +676,7 @@ module ``Argu Tests Main List`` =
661676
[<Fact>]
662677
let ``Get all subcommand parsers`` () =
663678
let subcommands = parser.GetSubCommandParsers()
664-
test <@ subcommands.Length = 6 @>
679+
test <@ subcommands.Length = 7 @>
665680
test <@ subcommands |> List.forall (fun sc -> sc.IsSubCommandParser) @>
666681

667682
[<Fact>]
@@ -852,6 +867,12 @@ module ``Argu Tests Main List`` =
852867
let results = parser.ParseCommandLine (args, raiseOnUsage = false)
853868
test <@ results.IsUsageRequested @>
854869

870+
[<Fact>]
871+
let ``Should fail if mandatory case is missing on a subcommand and display usage of subcommand and not main command`` () =
872+
let args = [|"--mandatory-arg" ; "true" ; "multiple-mandatories" ; "--valuea"; "5"|]
873+
raisesWith<ArguParseException> <@ parser.ParseCommandLine args @>
874+
(fun e -> <@ e.FirstLine.Contains "ERROR: missing parameter '--valueb', '--valuec'"
875+
&& e.Message.Contains $"USAGE: {parser.ProgramName} multiple-mandatories [--help] --valuea <int>" @>)
855876

856877
[<HelpFlags("--my-help")>]
857878
[<HelpDescription("waka jawaka")>]

0 commit comments

Comments
 (0)