Skip to content

Commit 9ec5ffa

Browse files
committed
Make grouping configurable in build-in help
- New option spring.shell.command.help.grouping-mode which can be either flat/group. - Build-in help command can now choose if to group command or just show flat list. - Fixes #347
1 parent 0efd71a commit 9ec5ffa

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/SpringShellProperties.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ public void setName(String name) {
126126
public static class HelpCommand {
127127

128128
private boolean enabled = true;
129+
private GroupingMode groupingMode = GroupingMode.GROUP;
129130

130131
public boolean isEnabled() {
131132
return enabled;
@@ -134,6 +135,19 @@ public boolean isEnabled() {
134135
public void setEnabled(boolean enabled) {
135136
this.enabled = enabled;
136137
}
138+
139+
public GroupingMode getGroupingMode() {
140+
return groupingMode;
141+
}
142+
143+
public void setGroupingMode(GroupingMode groupingMode) {
144+
this.groupingMode = groupingMode;
145+
}
146+
147+
public enum GroupingMode {
148+
GROUP,
149+
FLAT
150+
}
137151
}
138152

139153
public static class ClearCommand {

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/StandardCommandsAutoConfiguration.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.context.annotation.Conditional;
3030
import org.springframework.context.annotation.Configuration;
3131
import org.springframework.shell.boot.SpringShellProperties.VersionCommand;
32+
import org.springframework.shell.boot.SpringShellProperties.HelpCommand.GroupingMode;
3233
import org.springframework.shell.boot.condition.OnCompletionCommandCondition;
3334
import org.springframework.shell.result.ThrowableResultHandler;
3435
import org.springframework.shell.standard.commands.Clear;
@@ -54,8 +55,12 @@ public class StandardCommandsAutoConfiguration {
5455
@Bean
5556
@ConditionalOnMissingBean(Help.Command.class)
5657
@ConditionalOnProperty(prefix = "spring.shell.command.help", value = "enabled", havingValue = "true", matchIfMissing = true)
57-
public Help help() {
58-
return new Help();
58+
public Help help(SpringShellProperties properties) {
59+
Help help = new Help();
60+
if (properties.getCommand().getHelp().getGroupingMode() == GroupingMode.FLAT) {
61+
help.setShowGroups(false);
62+
}
63+
return help;
5964
}
6065

6166
@Bean

spring-shell-autoconfigure/src/test/java/org/springframework/shell/boot/SpringShellPropertiesTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.springframework.boot.context.properties.EnableConfigurationProperties;
2121
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
22+
import org.springframework.shell.boot.SpringShellProperties.HelpCommand.GroupingMode;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
2425

@@ -38,6 +39,7 @@ public void defaultNoPropertiesSet() {
3839
assertThat(properties.getTheme().getName()).isEqualTo("default");
3940
assertThat(properties.getCommand().getClear().isEnabled()).isTrue();
4041
assertThat(properties.getCommand().getHelp().isEnabled()).isTrue();
42+
assertThat(properties.getCommand().getHelp().getGroupingMode()).isEqualTo(GroupingMode.GROUP);
4143
assertThat(properties.getCommand().getHistory().isEnabled()).isTrue();
4244
assertThat(properties.getCommand().getQuit().isEnabled()).isTrue();
4345
assertThat(properties.getCommand().getScript().isEnabled()).isTrue();
@@ -67,6 +69,7 @@ public void setProperties() {
6769
.withPropertyValues("spring.shell.theme.name=fake")
6870
.withPropertyValues("spring.shell.command.clear.enabled=false")
6971
.withPropertyValues("spring.shell.command.help.enabled=false")
72+
.withPropertyValues("spring.shell.command.help.grouping-mode=flat")
7073
.withPropertyValues("spring.shell.command.history.enabled=false")
7174
.withPropertyValues("spring.shell.command.quit.enabled=false")
7275
.withPropertyValues("spring.shell.command.script.enabled=false")
@@ -93,6 +96,7 @@ public void setProperties() {
9396
assertThat(properties.getTheme().getName()).isEqualTo("fake");
9497
assertThat(properties.getCommand().getClear().isEnabled()).isFalse();
9598
assertThat(properties.getCommand().getHelp().isEnabled()).isFalse();
99+
assertThat(properties.getCommand().getHelp().getGroupingMode()).isEqualTo(GroupingMode.FLAT);
96100
assertThat(properties.getCommand().getHistory().isEnabled()).isFalse();
97101
assertThat(properties.getCommand().getQuit().isEnabled()).isFalse();
98102
assertThat(properties.getCommand().getScript().isEnabled()).isFalse();

spring-shell-autoconfigure/src/test/java/org/springframework/shell/boot/StandardCommandsAutoConfigurationTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
*/
1616
package org.springframework.shell.boot;
1717

18+
import java.lang.reflect.Field;
1819
import java.util.function.Function;
1920

2021
import org.junit.jupiter.api.Test;
2122

2223
import org.springframework.boot.autoconfigure.AutoConfigurations;
2324
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2425
import org.springframework.shell.standard.commands.Completion;
26+
import org.springframework.shell.standard.commands.Help;
27+
import org.springframework.util.ReflectionUtils;
2528

2629
import static org.assertj.core.api.Assertions.assertThat;
2730

@@ -48,6 +51,21 @@ public void testCompletionCommand() {
4851
});
4952
}
5053

54+
@Test
55+
public void testHelpCommand() {
56+
this.contextRunner
57+
.with(disableCommands("clear", "quit", "stacktrace", "script", "history", "completion"))
58+
.withPropertyValues("spring.shell.command.help.grouping-mode=flat")
59+
.run(context -> {
60+
assertThat(context).hasSingleBean(Help.class);
61+
Help help = context.getBean(Help.class);
62+
Field showGroupsField = ReflectionUtils.findField(Help.class, "showGroups");
63+
ReflectionUtils.makeAccessible(showGroupsField);
64+
ReflectionUtils.getField(showGroupsField, help);
65+
assertThat(ReflectionUtils.getField(showGroupsField, help)).isEqualTo(false);
66+
});
67+
}
68+
5169
private static Function<ApplicationContextRunner, ApplicationContextRunner> disableCommands(String... commands) {
5270
return (cr) -> {
5371
for (String command : commands) {

spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/Help.java

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public interface Command {
7878
}
7979

8080
private MessageInterpolator messageInterpolator = Utils.defaultValidatorFactory().getMessageInterpolator();
81+
private boolean showGroups = true;
8182

8283
public Help() {
8384
}
@@ -101,6 +102,16 @@ public CharSequence help(
101102

102103
}
103104

105+
/**
106+
* Sets if groups should be shown in a listing, defaults to true. If not enabled
107+
* a simple list is shown without groups.
108+
*
109+
* @param showGroups the flag to show groups
110+
*/
111+
public void setShowGroups(boolean showGroups) {
112+
this.showGroups = showGroups;
113+
}
114+
104115
/**
105116
* Return a description of a specific command. Uses a layout inspired by *nix man pages.
106117
*/
@@ -263,32 +274,34 @@ private String first(List<String> keys) {
263274
private CharSequence listCommands() {
264275
Map<String, MethodTarget> commandsByName = getCommandRegistry().listCommands();
265276

266-
SortedMap<String, Map<String, MethodTarget>> commandsByGroupAndName = commandsByName.entrySet().stream()
267-
.collect(groupingBy(e -> e.getValue().getGroup(), TreeMap::new, // group by and sort by command group
268-
toMap(Entry::getKey, Entry::getValue)));
269-
270277
AttributedStringBuilder result = new AttributedStringBuilder();
271278
result.append("AVAILABLE COMMANDS\n\n", AttributedStyle.BOLD);
272279

280+
SortedMap<String, Map<String, MethodTarget>> commandsByGroupAndName = commandsByName.entrySet().stream()
281+
.collect(groupingBy(e -> e.getValue().getGroup(), TreeMap::new, // group by and sort by command group
282+
toMap(Entry::getKey, Entry::getValue)));
273283
// display groups, sorted alphabetically, "Default" first
274284
commandsByGroupAndName.forEach((group, commandsInGroup) -> {
275-
result.append("".equals(group) ? "Default" : group, AttributedStyle.BOLD).append('\n');
276-
285+
if (showGroups) {
286+
result.append("".equals(group) ? "Default" : group, AttributedStyle.BOLD).append('\n');
287+
}
277288
Map<MethodTarget, SortedSet<String>> commandNamesByMethod = commandsInGroup.entrySet().stream()
278289
.collect(groupingBy(Entry::getValue, // group by command method
279290
mapping(Entry::getKey, toCollection(TreeSet::new)))); // sort command names
280-
281291
// display commands, sorted alphabetically by their first alias
282292
commandNamesByMethod.entrySet().stream().sorted(sortByFirstCommandName()).forEach(e -> {
293+
String prefix = showGroups ? " " : "";
294+
prefix = prefix + (isAvailable(e.getKey()) ? " " : " *");
283295
result
284-
.append(isAvailable(e.getKey()) ? " " : " * ")
296+
.append(prefix)
285297
.append(String.join(", ", e.getValue()), AttributedStyle.BOLD)
286298
.append(": ")
287299
.append(e.getKey().getHelp())
288300
.append('\n');
289301
});
290-
291-
result.append('\n');
302+
if (showGroups) {
303+
result.append('\n');
304+
}
292305
});
293306

294307
if (commandsByName.values().stream().distinct().anyMatch(m -> !isAvailable(m))) {

0 commit comments

Comments
 (0)