From 06d9fd51b2b7c05fe2788eec970511de8c4ebe8b Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Thu, 14 Jul 2022 16:31:14 +0100 Subject: [PATCH] Fix alias usage in help command - Add info about aliases into model structure used by help command templating. - Add some tests to models. - Change help commands list to group command and its aliases together. - Change help command to show aliases. - Fixes #458 - Fixes #426 --- .../shell/samples/standard/AliasCommands.java | 5 +- .../standard/commands/CommandInfoModel.java | 13 ++- .../standard/commands/GroupsInfoModel.java | 7 +- .../template/help-command-default.stg | 9 ++ .../template/help-commands-default.stg | 6 +- .../CommandAvailabilityInfoModelTests.java | 34 ++++++ .../commands/CommandInfoModelTests.java | 103 ++++++++++++++++++ .../commands/GroupsInfoModelTests.java | 89 +++++++++++++++ .../HelpTests-testCommandListDefault.txt | 6 +- .../HelpTests-testCommandListFlat.txt | 6 +- 10 files changed, 265 insertions(+), 13 deletions(-) create mode 100644 spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandAvailabilityInfoModelTests.java create mode 100644 spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandInfoModelTests.java create mode 100644 spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/GroupsInfoModelTests.java diff --git a/spring-shell-samples/src/main/java/org/springframework/shell/samples/standard/AliasCommands.java b/spring-shell-samples/src/main/java/org/springframework/shell/samples/standard/AliasCommands.java index 0bdedcda..368e1671 100644 --- a/spring-shell-samples/src/main/java/org/springframework/shell/samples/standard/AliasCommands.java +++ b/spring-shell-samples/src/main/java/org/springframework/shell/samples/standard/AliasCommands.java @@ -23,7 +23,9 @@ import org.springframework.shell.standard.ShellMethod; @ShellComponent public class AliasCommands { - @ShellMethod(key = { "alias anno main1", "alias anno main2" }, group = "Alias Commands") + private final static String DESCRIPTION = "main1 with main2 as alias"; + + @ShellMethod(key = { "alias anno main1", "alias anno main2" }, group = "Alias Commands", value = DESCRIPTION) public String annoMain1() { return "Hello annoMain1"; } @@ -33,6 +35,7 @@ public class AliasCommands { return CommandRegistration.builder() .command("alias", "reg", "main1") .group("Alias Commands") + .description(DESCRIPTION) .withAlias() .command("alias", "reg", "main2") .group("Alias Commands") diff --git a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java index a611eae1..2fa64083 100644 --- a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java +++ b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/CommandInfoModel.java @@ -33,13 +33,15 @@ import org.springframework.util.StringUtils; class CommandInfoModel { private String name; + private List aliases; private String description; private List parameters; private CommandAvailabilityInfoModel availability; - CommandInfoModel(String name, String description, List parameters, + CommandInfoModel(String name, List aliases, String description, List parameters, CommandAvailabilityInfoModel availability) { this.name = name; + this.aliases = aliases; this.description = description; this.parameters = parameters; this.availability = availability; @@ -68,6 +70,9 @@ class CommandInfoModel { }) .collect(Collectors.toList()); + List aliases = registration.getAliases().stream().map(ca -> ca.getCommand()) + .collect(Collectors.toList()); + String description = registration.getDescription(); boolean available = true; String availReason = ""; @@ -77,7 +82,7 @@ class CommandInfoModel { availReason = a.getReason(); } CommandAvailabilityInfoModel availModel = CommandAvailabilityInfoModel.of(available, availReason); - return new CommandInfoModel(name, description, parameters, availModel); + return new CommandInfoModel(name, aliases, description, parameters, availModel); } private static String commandOptionType(CommandOption o) { @@ -93,6 +98,10 @@ class CommandInfoModel { return name; } + public List getAliases() { + return this.aliases; + } + public String getDescription() { return description; } diff --git a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/GroupsInfoModel.java b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/GroupsInfoModel.java index 5af11b8e..4357aa8c 100644 --- a/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/GroupsInfoModel.java +++ b/spring-shell-standard-commands/src/main/java/org/springframework/shell/standard/commands/GroupsInfoModel.java @@ -15,6 +15,7 @@ */ package org.springframework.shell.standard.commands; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -54,14 +55,18 @@ class GroupsInfoModel { * @return a groups info model */ static GroupsInfoModel of(boolean showGroups, Map registrations) { + // throw away registrations aliases as those are then handled in a model // collect commands into groups with sorting - SortedMap> commandsByGroupAndName = registrations.entrySet().stream() + HashSet regsWithoutAliases = new HashSet<>(registrations.values()); + SortedMap> commandsByGroupAndName = regsWithoutAliases.stream() + .collect(Collectors.toMap(r -> r.getCommand(), r -> r)).entrySet().stream() .collect(Collectors.groupingBy( e -> StringUtils.hasText(e.getValue().getGroup()) ? e.getValue().getGroup() : "Default", TreeMap::new, Collectors.toMap(Entry::getKey, Entry::getValue) )); + // build model List gcims = commandsByGroupAndName.entrySet().stream() .map(e -> { diff --git a/spring-shell-standard-commands/src/main/resources/template/help-command-default.stg b/spring-shell-standard-commands/src/main/resources/template/help-command-default.stg index 245c972c..044633c2 100644 --- a/spring-shell-standard-commands/src/main/resources/template/help-command-default.stg +++ b/spring-shell-standard-commands/src/main/resources/template/help-command-default.stg @@ -66,6 +66,14 @@ availability(availability) ::= << >> +// ALIASES +aliases(aliases) ::= << + +<("ALSO KNOWN AS"); format="style-highlight"> + <(aliases); separator=", "> + +>> + // main main(model) ::= << @@ -74,4 +82,5 @@ main(model) ::= << + >> diff --git a/spring-shell-standard-commands/src/main/resources/template/help-commands-default.stg b/spring-shell-standard-commands/src/main/resources/template/help-commands-default.stg index 430a00f5..a64bdae4 100644 --- a/spring-shell-standard-commands/src/main/resources/template/help-commands-default.stg +++ b/spring-shell-standard-commands/src/main/resources/template/help-commands-default.stg @@ -16,8 +16,12 @@ availabilityDesc(hasUnavailableCommands) ::= << >> +commandName(command) ::= <% +<[command.name, command.aliases]; format="style-highlight", separator=", "> +%> + command(command) ::= << -<(command.name); format="style-highlight"><(":"); format="style-highlight"> +<(":"); format="style-highlight"> >> diff --git a/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandAvailabilityInfoModelTests.java b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandAvailabilityInfoModelTests.java new file mode 100644 index 00000000..0620f4e3 --- /dev/null +++ b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandAvailabilityInfoModelTests.java @@ -0,0 +1,34 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell.standard.commands; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CommandAvailabilityInfoModelTests { + + @Test + void hasDefaults() { + CommandAvailabilityInfoModel caim = CommandAvailabilityInfoModel.of(true, null); + assertThat(caim.getAvailable()).isTrue(); + assertThat(caim.getReason()).isNull(); + + caim = CommandAvailabilityInfoModel.of(false, "fakereason"); + assertThat(caim.getAvailable()).isFalse(); + assertThat(caim.getReason()).isEqualTo("fakereason"); + } +} diff --git a/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandInfoModelTests.java b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandInfoModelTests.java new file mode 100644 index 00000000..760e78de --- /dev/null +++ b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/CommandInfoModelTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell.standard.commands; + +import org.junit.jupiter.api.Test; + +import org.springframework.shell.command.CommandRegistration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CommandInfoModelTests { + + @Test + void hasGivenName() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getName()).isEqualTo("main1"); + } + + @Test + void hasGivenDescription() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .description("desc1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getDescription()).isEqualTo("desc1"); + } + + @Test + void hasNoParameters() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getParameters()).isEmpty(); + } + + @Test + void hasExpectedDefaultAvailability() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getAvailability()).isNotNull(); + assertThat(cim.getAvailability().getAvailable()).isTrue(); + assertThat(cim.getAvailability().getReason()).isNull(); + } + + @Test + void hasNoAliases() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getAliases()).isEmpty(); + } + + @Test + void hasAliases() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withAlias() + .command("alias1") + .and() + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandInfoModel cim = CommandInfoModel.of("main1", r1); + assertThat(cim.getAliases()).containsExactly("alias1"); + } +} diff --git a/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/GroupsInfoModelTests.java b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/GroupsInfoModelTests.java new file mode 100644 index 00000000..95a21e14 --- /dev/null +++ b/spring-shell-standard-commands/src/test/java/org/springframework/shell/standard/commands/GroupsInfoModelTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell.standard.commands; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.shell.command.CommandCatalog; +import org.springframework.shell.command.CommandRegistration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GroupsInfoModelTests { + + private CommandCatalog commandCatalog; + + @BeforeEach + void setup() { + this.commandCatalog = CommandCatalog.of(); + } + + @Test + void showGroupsIsSet() { + GroupsInfoModel gim = buildGIM(true); + assertThat(gim.getShowGroups()).isTrue(); + + gim = buildGIM(false); + assertThat(gim.getShowGroups()).isFalse(); + } + + @Test + void simpleCommandsAreSeparated() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + CommandRegistration r2 = CommandRegistration.builder() + .command("main2") + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + this.commandCatalog.register(r1, r2); + GroupsInfoModel gim = buildGIM(); + + assertThat(gim.getCommands()).hasSize(2); + assertThat(gim.getGroups()).hasSize(1); + } + + @Test + void aliasNotAddedToTopModel() { + CommandRegistration r1 = CommandRegistration.builder() + .command("main1") + .withAlias() + .command("alias1") + .and() + .withTarget() + .consumer(ctx -> {}) + .and() + .build(); + this.commandCatalog.register(r1); + GroupsInfoModel gim = buildGIM(); + + assertThat(gim.getCommands()).hasSize(1); + } + + private GroupsInfoModel buildGIM(boolean showGroups) { + return GroupsInfoModel.of(showGroups, this.commandCatalog.getRegistrations()); + } + + private GroupsInfoModel buildGIM() { + return buildGIM(true); + } +} diff --git a/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListDefault.txt b/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListDefault.txt index 007534cb..d63c9441 100644 --- a/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListDefault.txt +++ b/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListDefault.txt @@ -1,11 +1,9 @@ AVAILABLE COMMANDS Default - 1st-command: A rather extensive description of some command. - yet-another-command: The second command. This one is known under several aliases as well. third-command: The last command. - second-command: The second command. This one is known under several aliases as well. - first-command: A rather extensive description of some command. + second-command, yet-another-command: The second command. This one is known under several aliases as well. + first-command, 1st-command: A rather extensive description of some command. Example Group second-group-command: The second command in a separate group. diff --git a/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListFlat.txt b/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListFlat.txt index c7994a6e..3553a97b 100644 --- a/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListFlat.txt +++ b/spring-shell-standard-commands/src/test/resources/org/springframework/shell/standard/commands/HelpTests-testCommandListFlat.txt @@ -1,10 +1,8 @@ AVAILABLE COMMANDS -1st-command: A rather extensive description of some command. -yet-another-command: The second command. This one is known under several aliases as well. third-command: The last command. -second-command: The second command. This one is known under several aliases as well. -first-command: A rather extensive description of some command. +second-command, yet-another-command: The second command. This one is known under several aliases as well. +first-command, 1st-command: A rather extensive description of some command. second-group-command: The second command in a separate group. first-group-command: The first command in a separate group.