From 5943edc0dbf10562c6dbb838ca8deb2c5e3de0a7 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Sun, 16 Jul 2023 19:43:22 +0900 Subject: [PATCH 1/8] add RemoveGroup method for Command --- command.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/command.go b/command.go index 01f7c6f1c..1f7ed92f2 100644 --- a/command.go +++ b/command.go @@ -1311,6 +1311,30 @@ func (c *Command) AddGroup(groups ...*Group) { c.commandgroups = append(c.commandgroups, groups...) } +// RemoveGroup removes one or more command groups to this parent command. +func (c *Command) RemoveGroup(groupIDs ...string) { + // remove groups from commandgroups + groups := []*Group{} +main: + for _, group := range c.commandgroups { + for _, groupID := range groupIDs { + if group.ID == groupID { + continue main + } + } + groups = append(groups, group) + } + c.commandgroups = groups + // remove the groupID from the target commands + for _, command := range c.commands { + for _, groupID := range groupIDs { + if command.GroupID == groupID { + command.GroupID = "" + } + } + } +} + // RemoveCommand removes one or more commands from a parent command. func (c *Command) RemoveCommand(cmds ...*Command) { commands := []*Command{} From 5bbc67713ec6b9e7a401842dc56bf7ff5f6061fd Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Sun, 16 Jul 2023 19:43:38 +0900 Subject: [PATCH 2/8] add unit tests for command.RemoveGroup --- command_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/command_test.go b/command_test.go index 0212f5ae9..b5be9654d 100644 --- a/command_test.go +++ b/command_test.go @@ -1862,6 +1862,61 @@ func TestAddGroup(t *testing.T) { checkStringContains(t, output, "\nTest group\n cmd") } +func TestRemoveSingleGroup(t *testing.T) { + var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun} + + rootCmd.AddGroup( + &Group{ID: "group", Title: "Test group"}, + &Group{ID: "help", Title: "help"}, + &Group{ID: "comp", Title: "comp"}, + ) + + rootCmd.AddCommand(&Command{Use: "sub", GroupID: "group", Run: emptyRun}) + + rootCmd.SetHelpCommandGroupID("help") + rootCmd.SetCompletionCommandGroupID("comp") + + rootCmd.RemoveGroup("group") + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringOmits(t, output, "\nTest group:\n sub") + checkStringContains(t, output, "\nAdditional Commands:\n sub") +} + +func TestRemoveMultipleGroups(t *testing.T) { + var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun} + + rootCmd.AddGroup( + &Group{ID: "group1", Title: "Test group1"}, + &Group{ID: "group2", Title: "Test group2"}, + &Group{ID: "help", Title: "help"}, + &Group{ID: "comp", Title: "comp"}, + ) + + rootCmd.AddCommand( + &Command{Use: "sub1", Short: "sub1", GroupID: "group1", Run: emptyRun}, + &Command{Use: "sub2", Short: "sub2", GroupID: "group2", Run: emptyRun}, + ) + + rootCmd.SetHelpCommandGroupID("help") + rootCmd.SetCompletionCommandGroupID("comp") + + rootCmd.RemoveGroup("group1", "group2") + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringOmits(t, output, "\nTest group1:\n sub1") + checkStringOmits(t, output, "\nTest group2:\n sub2") + checkStringContains(t, output, "\nAdditional Commands:\n sub1 sub1\n sub2 sub2") +} + func TestWrongGroupFirstLevel(t *testing.T) { var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun} From 186ab8dddad6aa51849012c6b3be19308c5f5565 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Mon, 17 Jul 2023 01:13:56 +0900 Subject: [PATCH 3/8] update user_guid --- site/content/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/user_guide.md b/site/content/user_guide.md index 049714310..28277bd6d 100644 --- a/site/content/user_guide.md +++ b/site/content/user_guide.md @@ -525,7 +525,7 @@ around it. In fact, you can provide your own if you want. Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly defined using `AddGroup()` on the parent command. Then a subcommand can be added to a group using the `GroupID` element -of that subcommand. The groups will appear in the help output in the same order as they are defined using different +of that subcommand. `RemoveGroup()` can be used to remove groups and initialize the GroupID of commands belonging to the removed group. The groups will appear in the help output in the same order as they are defined using different calls to `AddGroup()`. If you use the generated `help` or `completion` commands, you can set their group ids using `SetHelpCommandGroupId()` and `SetCompletionCommandGroupId()` on the root command, respectively. From a2edfa4d9ad8213bee1916c98331944fdc9852c8 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Thu, 27 Jul 2023 21:00:03 +0900 Subject: [PATCH 4/8] update user_guide initialize -^> reset --- site/content/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/user_guide.md b/site/content/user_guide.md index 93dc601fe..71ddddc42 100644 --- a/site/content/user_guide.md +++ b/site/content/user_guide.md @@ -534,7 +534,7 @@ around it. In fact, you can provide your own if you want. Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly defined using `AddGroup()` on the parent command. Then a subcommand can be added to a group using the `GroupID` element -of that subcommand. `RemoveGroup()` can be used to remove groups and initialize the GroupID of commands belonging to the removed group. The groups will appear in the help output in the same order as they are defined using different +of that subcommand. `RemoveGroup()` can be used to remove groups and reset the GroupID of commands belonging to the removed group. The groups will appear in the help output in the same order as they are defined using different calls to `AddGroup()`. If you use the generated `help` or `completion` commands, you can set their group ids using `SetHelpCommandGroupId()` and `SetCompletionCommandGroupId()` on the root command, respectively. From 8a2769858c365b8aee0eebf0ad4a934bdb4d19e1 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Thu, 27 Jul 2023 23:51:46 +0900 Subject: [PATCH 5/8] remove group id of the help command and completion command --- command.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/command.go b/command.go index 1f7ed92f2..cee744787 100644 --- a/command.go +++ b/command.go @@ -330,12 +330,25 @@ func (c *Command) SetHelpCommandGroupID(groupID string) { c.helpCommandGroupID = groupID } +// resetHelpCommandGroupID resets the group id of the help command. +func (c *Command) resetHelpCommandGroupID() { + if c.helpCommand != nil { + c.helpCommand.GroupID = "" + } + c.helpCommandGroupID = "" +} + // SetCompletionCommandGroupID sets the group id of the completion command. func (c *Command) SetCompletionCommandGroupID(groupID string) { // completionCommandGroupID is used if no completion command is defined by the user c.Root().completionCommandGroupID = groupID } +// resetCompletionCommandGroupID resets the group id of the completion command. +func (c *Command) resetCompletionCommandGroupID() { + c.Root().completionCommandGroupID = "" +} + // SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s @@ -1331,6 +1344,17 @@ main: if command.GroupID == groupID { command.GroupID = "" } + if command.helpCommandGroupID == groupID { + command.resetHelpCommandGroupID() + } + } + } + for _, groupID := range groupIDs { + if c.helpCommandGroupID == groupID { + c.resetHelpCommandGroupID() + } + if c.Root().completionCommandGroupID == groupID { + c.resetCompletionCommandGroupID() } } } From 08be2cb98199b82b112f0fe7aaa86ab5fd8b3286 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Thu, 27 Jul 2023 23:52:11 +0900 Subject: [PATCH 6/8] add unit tests --- command_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/command_test.go b/command_test.go index 5c070ee84..540e2176a 100644 --- a/command_test.go +++ b/command_test.go @@ -1887,6 +1887,47 @@ func TestRemoveSingleGroup(t *testing.T) { checkStringContains(t, output, "\nAdditional Commands:\n sub") } +func TestRemoveHelpCommandGroup(t *testing.T) { + rootCmd := &Command{Use: "root", Short: "test", Run: emptyRun} + rootCmd.CompletionOptions.DisableDefaultCmd = true + + rootCmd.AddGroup(&Group{ID: "group", Title: "group"}) + rootCmd.AddCommand(&Command{Use: "child", Short: "c", GroupID: "group", Run: emptyRun}) + rootCmd.SetHelpCommandGroupID("group") + + rootCmd.RemoveGroup("group") + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringOmits(t, output, "\ngroup\n child\n help") + checkStringContains(t, output, "\nAvailable Commands:\n child c\n help") +} + +func TestRemoveCompletionCommandGroup(t *testing.T) { + rootCmd := &Command{Use: "root", Short: "test", Run: emptyRun} + + rootCmd.AddGroup( + &Group{ID: "group", Title: "group"}, + &Group{ID: "help", Title: "help"}, + ) + rootCmd.AddCommand(&Command{Use: "child", Short: "c", GroupID: "group", Run: emptyRun}) + rootCmd.SetHelpCommandGroupID("help") + rootCmd.SetCompletionCommandGroupID("group") + + rootCmd.RemoveGroup("group") + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringOmits(t, output, "\ngroup\n child\n completion") + checkStringContains(t, output, "\nAdditional Commands:\n child c\n completion") +} + func TestRemoveMultipleGroups(t *testing.T) { var rootCmd = &Command{Use: "root", Short: "test", Run: emptyRun} From 02094ac5c550a0e94012e1321e2cee07101c56e4 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Fri, 1 Sep 2023 23:53:31 +0900 Subject: [PATCH 7/8] add error check to RemoveGroup command --- command.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/command.go b/command.go index cee744787..00853c9b4 100644 --- a/command.go +++ b/command.go @@ -1325,18 +1325,23 @@ func (c *Command) AddGroup(groups ...*Group) { } // RemoveGroup removes one or more command groups to this parent command. -func (c *Command) RemoveGroup(groupIDs ...string) { +func (c *Command) RemoveGroup(groupIDs ...string) error { // remove groups from commandgroups groups := []*Group{} + hasRemoved := false main: for _, group := range c.commandgroups { for _, groupID := range groupIDs { if group.ID == groupID { + hasRemoved = true continue main } } groups = append(groups, group) } + if !hasRemoved { + return fmt.Errorf("following group ID does not exist; %s", strings.Join(groupIDs, ", ")) + } c.commandgroups = groups // remove the groupID from the target commands for _, command := range c.commands { @@ -1357,6 +1362,7 @@ main: c.resetCompletionCommandGroupID() } } + return nil } // RemoveCommand removes one or more commands from a parent command. From 33524ebc1af630fb0a9057c35629e4b9acebfbe7 Mon Sep 17 00:00:00 2001 From: Jun Nishimura Date: Fri, 1 Sep 2023 23:53:40 +0900 Subject: [PATCH 8/8] fix unit tests --- command_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/command_test.go b/command_test.go index 540e2176a..624d738a3 100644 --- a/command_test.go +++ b/command_test.go @@ -1876,7 +1876,9 @@ func TestRemoveSingleGroup(t *testing.T) { rootCmd.SetHelpCommandGroupID("help") rootCmd.SetCompletionCommandGroupID("comp") - rootCmd.RemoveGroup("group") + if err := rootCmd.RemoveGroup("group"); err != nil { + t.Errorf("Unexpected error: %v", err) + } output, err := executeCommand(rootCmd, "--help") if err != nil { @@ -1895,7 +1897,9 @@ func TestRemoveHelpCommandGroup(t *testing.T) { rootCmd.AddCommand(&Command{Use: "child", Short: "c", GroupID: "group", Run: emptyRun}) rootCmd.SetHelpCommandGroupID("group") - rootCmd.RemoveGroup("group") + if err := rootCmd.RemoveGroup("group"); err != nil { + t.Errorf("Unexpected error: %v", err) + } output, err := executeCommand(rootCmd, "--help") if err != nil { @@ -1917,7 +1921,9 @@ func TestRemoveCompletionCommandGroup(t *testing.T) { rootCmd.SetHelpCommandGroupID("help") rootCmd.SetCompletionCommandGroupID("group") - rootCmd.RemoveGroup("group") + if err := rootCmd.RemoveGroup("group"); err != nil { + t.Errorf("Unexpected error: %v", err) + } output, err := executeCommand(rootCmd, "--help") if err != nil { @@ -1946,7 +1952,9 @@ func TestRemoveMultipleGroups(t *testing.T) { rootCmd.SetHelpCommandGroupID("help") rootCmd.SetCompletionCommandGroupID("comp") - rootCmd.RemoveGroup("group1", "group2") + if err := rootCmd.RemoveGroup("group1", "group2"); err != nil { + t.Errorf("Unexpected error: %v", err) + } output, err := executeCommand(rootCmd, "--help") if err != nil {