From 9dbf32025a361389da1788ec44b13362a5075da2 Mon Sep 17 00:00:00 2001 From: David Pilar Date: Sat, 22 Aug 2026 19:14:08 +0200 Subject: [PATCH] Fix implicit --help option for sub-commands Signed-off-by: David Pilar --- .../core/command/DefaultCommandParser.java | 12 ++++++++++-- .../command/DefaultCommandParserTests.java | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/spring-shell-core/src/main/java/org/springframework/shell/core/command/DefaultCommandParser.java b/spring-shell-core/src/main/java/org/springframework/shell/core/command/DefaultCommandParser.java index dd1a63ce7..6452efa07 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/core/command/DefaultCommandParser.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/core/command/DefaultCommandParser.java @@ -195,12 +195,20 @@ private String unquoteAndUnescapeQuoted(String s) { } private boolean isBooleanOption(String commandName, String currentWord) { - return Optional.ofNullable(commandRegistry.getCommandByName(commandName)) + List declaredOptions = Optional.ofNullable(commandRegistry.getCommandByName(commandName)) .map(Command::getOptions) .orElse(List.of()) .stream() .filter(o -> o.isOptionEqual(currentWord)) - .anyMatch(o -> o.type() == boolean.class || o.type() == Boolean.class); + .toList(); + if (declaredOptions.isEmpty()) { + return isHelpOption(currentWord); + } + return declaredOptions.stream().anyMatch(o -> o.type() == boolean.class || o.type() == Boolean.class); + } + + private boolean isHelpOption(String word) { + return word.equals("--help") || word.equals("-h"); } private boolean isBooleanValue(String rawValue) { diff --git a/spring-shell-core/src/test/java/org/springframework/shell/core/command/DefaultCommandParserTests.java b/spring-shell-core/src/test/java/org/springframework/shell/core/command/DefaultCommandParserTests.java index 4a64eba36..fba1cdd91 100644 --- a/spring-shell-core/src/test/java/org/springframework/shell/core/command/DefaultCommandParserTests.java +++ b/spring-shell-core/src/test/java/org/springframework/shell/core/command/DefaultCommandParserTests.java @@ -482,6 +482,25 @@ void testParseWithHelpOption(String input) { assertEquals("true", parsedInput.options().get(0).value()); } + @ParameterizedTest + @ValueSource(strings = { "mycommand mysubcommand --help", "mycommand mysubcommand -h", + "mycommand --help arg1 --option value1", "mycommand -h arg1" }) + void testParseWithImplicitHelpOption(String input) { + // given + Command command = createCommand("mycommand", "My test command"); + command.getOptions().add(CommandOption.with().longName("option").shortName('o').build()); + commandRegistry.registerCommand(command); + Command subCommand = createCommand("mycommand mysubcommand", "My test sub command"); + subCommand.getOptions().add(CommandOption.with().longName("option").shortName('o').build()); + commandRegistry.registerCommand(subCommand); + + // when + ParsedInput parsedInput = parser.parse(input); + + // then + assertEquals("true", parsedInput.options().get(0).value()); + } + private static Command createCommand(String name, String description) { return new AbstractCommand(name, description) { @Override