diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 729a91a6..946e3d96 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,26 +1,126 @@ # Developing hcloud-cli ## Generated files + This repository contains generated files, mainly for testing purposes. These files are generated by running + ```sh go generate ./... ``` + in the root directory of this repository. Make sure to keep generated files up-to-date when making changes to the code. ## Unit tests -Unit tests are located in the `internal` directory. Run them with + +Unit tests are located in the `internal` directory. Run them with + ```sh go test ./... ``` ## Build -To build the binary, run + +To build the binary, run + ```sh go build -o hcloud-cli ./cmd/hcloud ``` -To include version information in the resulting binary and build for all targets, use GoReleaser: +To include version information in the resulting binary and build for all targets, use GoReleaser: + ```sh goreleaser --snapshot --skip-publish --rm-dist ``` + +## Conventions + +### Subcommand groups + +Cobra offers the functionality to group subcommands. The conventions on when and how to group commands are as follows: + +1. Use the following Categories: + - **General** (CRUD operations such as `create`, `delete`, `describe`, `list`, `update` + Label + commands `add-`/`remove-label`) + - Groups based on actions (e.g. `enable`, `disable`, `attach`, `detach`), for example `enable-`/`disable-protection` + or `poweron`/`poweroff`/`shutdown`/`reset`/`reboot` + - **Additional commands** that don't fit into the other categories (`Group.ID` is empty). These should be + utility commands, for example ones that perform client-side actions. +2. Groups are only needed if more than the "General" group commands are present. +3. `Group.ID` formatting: + 1. If the `ID` is a noun, it should be singular. + 2. If the `ID` is a verb, it should be in the infinitive form. + 3. The `ID` should be in kebab-case. +4. `Group.Title` formatting: + 1. Should be the `ID` but capitalized and with spaces instead of dashes. + 2. If a single resource is managed, the `Title` should be singular. Otherwise, it should be plural. + + Example: Multiple network can be attached to server -> `Networks`, but only one ISO can be attached to a server -> `ISO` + +Here is how to create a group: + +```go +cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) +// ... + +cmd.AddCommand( +util.WithGroup("general", ListCmd.CobraCommand(s)), +// ... +) +``` + +Example of the `hcloud server` command groups: + +``` +General + add-label Add a label to a server + change-type Change type of a server + create Create a server + create-image Create an image from a server + delete Delete a server + describe Describe a server + list List Servers + rebuild Rebuild a server + remove-label Remove a label from a server + update Update a Server + +Protection + disable-protection Disable resource protection for a server + enable-protection Enable resource protection for a server + +Rescue + disable-rescue Disable rescue for a server + enable-rescue Enable rescue for a server + +Power/Reboot + poweroff Poweroff a server + poweron Poweron a server + reboot Reboot a server + reset Reset a server + shutdown Shutdown a server + +Networks + attach-to-network Attach a server to a network + change-alias-ips Change a server's alias IPs in a network + detach-from-network Detach a server from a network + set-rdns Change reverse DNS of a Server + +ISO + attach-iso Attach an ISO to a server + detach-iso Detach an ISO from a server + +Placement Groups + add-to-placement-group Add a server to a placement group + remove-from-placement-group Removes a server from a placement group + +Backup + disable-backup Disable backup for a server + enable-backup Enable backup for a server + +Additional Commands: + ip Print a server's IP address + metrics [ALPHA] Metrics from a Server + request-console Request a WebSocket VNC console for a server + reset-password Reset the root password of a server + ssh Spawn an SSH connection for the server +``` diff --git a/internal/cmd/firewall/firewall.go b/internal/cmd/firewall/firewall.go index 45b6cd42..9217a286 100644 --- a/internal/cmd/firewall/firewall.go +++ b/internal/cmd/firewall/firewall.go @@ -3,6 +3,7 @@ package firewall import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,19 +15,25 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "rule", Title: "Rules"}) + cmd.AddGroup(&cobra.Group{ID: "resource", Title: "Resources"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - ReplaceRulesCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - AddRuleCmd.CobraCommand(s), - DeleteRuleCmd.CobraCommand(s), - ApplyToResourceCmd.CobraCommand(s), - RemoveFromResourceCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", CreateCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + + util.WithGroup("rule", ReplaceRulesCmd.CobraCommand(s)), + util.WithGroup("rule", AddRuleCmd.CobraCommand(s)), + util.WithGroup("rule", DeleteRuleCmd.CobraCommand(s)), + + util.WithGroup("resource", ApplyToResourceCmd.CobraCommand(s)), + util.WithGroup("resource", RemoveFromResourceCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/floatingip/floatingip.go b/internal/cmd/floatingip/floatingip.go index 1d0dd0b0..67a602b3 100644 --- a/internal/cmd/floatingip/floatingip.go +++ b/internal/cmd/floatingip/floatingip.go @@ -3,6 +3,7 @@ package floatingip import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,19 +15,26 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "assign", Title: "Assign"}) + cmd.AddCommand( - UpdateCmd.CobraCommand(s), - ListCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - AssignCmd.CobraCommand(s), - UnassignCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), - SetRDNSCmd.CobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", CreateCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("assign", AssignCmd.CobraCommand(s)), + util.WithGroup("assign", UnassignCmd.CobraCommand(s)), + + util.WithGroup("", SetRDNSCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/image/image.go b/internal/cmd/image/image.go index e4c0a3bd..03be7916 100644 --- a/internal/cmd/image/image.go +++ b/internal/cmd/image/image.go @@ -3,6 +3,7 @@ package image import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,15 +15,19 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/loadbalancer/load_balancer.go b/internal/cmd/loadbalancer/load_balancer.go index 2ed342a5..b4d697bf 100644 --- a/internal/cmd/loadbalancer/load_balancer.go +++ b/internal/cmd/loadbalancer/load_balancer.go @@ -3,6 +3,7 @@ package loadbalancer import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -15,29 +16,41 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "target", Title: "Targets"}) + cmd.AddGroup(&cobra.Group{ID: "service", Title: "Services"}) + cmd.AddGroup(&cobra.Group{ID: "network", Title: "Network"}) + cmd.AddGroup(&cobra.Group{ID: "public-interface", Title: "Public Interface"}) + cmd.AddCommand( - CreateCmd.CobraCommand(s), - ListCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), - AddTargetCmd.CobraCommand(s), - RemoveTargetCmd.CobraCommand(s), - ChangeAlgorithmCmd.CobraCommand(s), - UpdateServiceCmd.CobraCommand(s), - DeleteServiceCmd.CobraCommand(s), - AddServiceCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - AttachToNetworkCmd.CobraCommand(s), - DetachFromNetworkCmd.CobraCommand(s), - EnablePublicInterfaceCmd.CobraCommand(s), - DisablePublicInterfaceCmd.CobraCommand(s), - ChangeTypeCmd.CobraCommand(s), - MetricsCmd.CobraCommand(s), - SetRDNSCmd.CobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + util.WithGroup("general", ChangeAlgorithmCmd.CobraCommand(s)), + util.WithGroup("general", ChangeTypeCmd.CobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("target", AddTargetCmd.CobraCommand(s)), + util.WithGroup("target", RemoveTargetCmd.CobraCommand(s)), + + util.WithGroup("service", AddServiceCmd.CobraCommand(s)), + util.WithGroup("service", UpdateServiceCmd.CobraCommand(s)), + util.WithGroup("service", DeleteServiceCmd.CobraCommand(s)), + + util.WithGroup("network", AttachToNetworkCmd.CobraCommand(s)), + util.WithGroup("network", DetachFromNetworkCmd.CobraCommand(s)), + + util.WithGroup("public-interface", EnablePublicInterfaceCmd.CobraCommand(s)), + util.WithGroup("public-interface", DisablePublicInterfaceCmd.CobraCommand(s)), + + util.WithGroup("", MetricsCmd.CobraCommand(s)), + util.WithGroup("", SetRDNSCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/network/network.go b/internal/cmd/network/network.go index 014b227c..6cd11f8d 100644 --- a/internal/cmd/network/network.go +++ b/internal/cmd/network/network.go @@ -3,6 +3,7 @@ package network import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,22 +15,29 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "route", Title: "Routes"}) + cmd.AddGroup(&cobra.Group{ID: "subnet", Title: "Subnets"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - ChangeIPRangeCmd.CobraCommand(s), - AddRouteCmd.CobraCommand(s), - RemoveRouteCmd.CobraCommand(s), - AddSubnetCmd.CobraCommand(s), - RemoveSubnetCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - ExposeRoutesToVSwitchCmd.CobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + util.WithGroup("general", ChangeIPRangeCmd.CobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("route", AddRouteCmd.CobraCommand(s)), + util.WithGroup("route", RemoveRouteCmd.CobraCommand(s)), + util.WithGroup("route", ExposeRoutesToVSwitchCmd.CobraCommand(s)), + + util.WithGroup("subnet", AddSubnetCmd.CobraCommand(s)), + util.WithGroup("subnet", RemoveSubnetCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/primaryip/primaryip.go b/internal/cmd/primaryip/primaryip.go index ac2a29cf..f6e3233d 100644 --- a/internal/cmd/primaryip/primaryip.go +++ b/internal/cmd/primaryip/primaryip.go @@ -3,6 +3,7 @@ package primaryip import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,19 +15,24 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "assign", Title: "Assign"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - AssignCmd.CobraCommand(s), - UnAssignCmd.CobraCommand(s), - ChangeDNSCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + util.WithGroup("general", ChangeDNSCmd.CobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("assign", AssignCmd.CobraCommand(s)), + util.WithGroup("assign", UnAssignCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/server/server.go b/internal/cmd/server/server.go index a51cc13b..23a23e5d 100644 --- a/internal/cmd/server/server.go +++ b/internal/cmd/server/server.go @@ -3,6 +3,7 @@ package server import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,41 +15,58 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "rescue", Title: "Rescue"}) + cmd.AddGroup(&cobra.Group{ID: "power", Title: "Power/Reboot"}) + cmd.AddGroup(&cobra.Group{ID: "network", Title: "Networks"}) + cmd.AddGroup(&cobra.Group{ID: "iso", Title: "ISO"}) + cmd.AddGroup(&cobra.Group{ID: "placement-group", Title: "Placement Groups"}) + cmd.AddGroup(&cobra.Group{ID: "backup", Title: "Backup"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - RebootCmd.CobraCommand(s), - PoweronCmd.CobraCommand(s), - PoweroffCmd.CobraCommand(s), - ResetCmd.CobraCommand(s), - ShutdownCmd.CobraCommand(s), - CreateImageCmd.CobraCommand(s), - ResetPasswordCmd.CobraCommand(s), - EnableRescueCmd.CobraCommand(s), - DisableRescueCmd.CobraCommand(s), - AttachISOCmd.CobraCommand(s), - DetachISOCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - ChangeTypeCmd.CobraCommand(s), - RebuildCmd.CobraCommand(s), - EnableBackupCmd.CobraCommand(s), - DisableBackupCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - SSHCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), - SetRDNSCmd.CobraCommand(s), - AttachToNetworkCmd.CobraCommand(s), - DetachFromNetworkCmd.CobraCommand(s), - ChangeAliasIPsCmd.CobraCommand(s), - IPCmd.CobraCommand(s), - RequestConsoleCmd.CobraCommand(s), - MetricsCmd.CobraCommand(s), - AddToPlacementGroupCmd.CobraCommand(s), - RemoveFromPlacementGroupCmd.CobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", CreateCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", CreateImageCmd.CobraCommand(s)), + util.WithGroup("general", ChangeTypeCmd.CobraCommand(s)), + util.WithGroup("general", RebuildCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("rescue", EnableRescueCmd.CobraCommand(s)), + util.WithGroup("rescue", DisableRescueCmd.CobraCommand(s)), + + util.WithGroup("power", PoweronCmd.CobraCommand(s)), + util.WithGroup("power", PoweroffCmd.CobraCommand(s)), + util.WithGroup("power", RebootCmd.CobraCommand(s)), + util.WithGroup("power", ShutdownCmd.CobraCommand(s)), + util.WithGroup("power", ResetCmd.CobraCommand(s)), + + util.WithGroup("network", AttachToNetworkCmd.CobraCommand(s)), + util.WithGroup("network", DetachFromNetworkCmd.CobraCommand(s)), + util.WithGroup("network", ChangeAliasIPsCmd.CobraCommand(s)), + util.WithGroup("network", SetRDNSCmd.CobraCommand(s)), + + util.WithGroup("iso", AttachISOCmd.CobraCommand(s)), + util.WithGroup("iso", DetachISOCmd.CobraCommand(s)), + + util.WithGroup("placement-group", AddToPlacementGroupCmd.CobraCommand(s)), + util.WithGroup("placement-group", RemoveFromPlacementGroupCmd.CobraCommand(s)), + + util.WithGroup("backup", EnableBackupCmd.CobraCommand(s)), + util.WithGroup("backup", DisableBackupCmd.CobraCommand(s)), + + util.WithGroup("", SSHCmd.CobraCommand(s)), + util.WithGroup("", IPCmd.CobraCommand(s)), + util.WithGroup("", RequestConsoleCmd.CobraCommand(s)), + util.WithGroup("", ResetPasswordCmd.CobraCommand(s)), + util.WithGroup("", MetricsCmd.CobraCommand(s)), ) return cmd } diff --git a/internal/cmd/util/util.go b/internal/cmd/util/util.go index 08af39a4..a8c61bc8 100644 --- a/internal/cmd/util/util.go +++ b/internal/cmd/util/util.go @@ -192,3 +192,9 @@ func ValidateRequiredFlags(flags *pflag.FlagSet, names ...string) error { } return nil } + +// WithGroup sets the GroupID field on the passed command. +func WithGroup(groupId string, cmd *cobra.Command) *cobra.Command { + cmd.GroupID = groupId + return cmd +} diff --git a/internal/cmd/volume/volume.go b/internal/cmd/volume/volume.go index 7eb82909..e49c7625 100644 --- a/internal/cmd/volume/volume.go +++ b/internal/cmd/volume/volume.go @@ -3,6 +3,7 @@ package volume import ( "github.com/spf13/cobra" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/state" ) @@ -14,19 +15,24 @@ func NewCommand(s state.State) *cobra.Command { TraverseChildren: true, DisableFlagsInUseLine: true, } + cmd.AddGroup(&cobra.Group{ID: "general", Title: "General"}) + cmd.AddGroup(&cobra.Group{ID: "protection", Title: "Protection"}) + cmd.AddGroup(&cobra.Group{ID: "attach", Title: "Attach"}) + cmd.AddCommand( - ListCmd.CobraCommand(s), - CreateCmd.CobraCommand(s), - UpdateCmd.CobraCommand(s), - DeleteCmd.CobraCommand(s), - DescribeCmd.CobraCommand(s), - AttachCmd.CobraCommand(s), - DetachCmd.CobraCommand(s), - ResizeCmd.CobraCommand(s), - EnableProtectionCmd.CobraCommand(s), - DisableProtectionCmd.CobraCommand(s), - LabelCmds.AddCobraCommand(s), - LabelCmds.RemoveCobraCommand(s), + util.WithGroup("general", ListCmd.CobraCommand(s)), + util.WithGroup("general", DescribeCmd.CobraCommand(s)), + util.WithGroup("general", DeleteCmd.CobraCommand(s)), + util.WithGroup("general", UpdateCmd.CobraCommand(s)), + util.WithGroup("general", LabelCmds.AddCobraCommand(s)), + util.WithGroup("general", LabelCmds.RemoveCobraCommand(s)), + util.WithGroup("general", ResizeCmd.CobraCommand(s)), + + util.WithGroup("protection", EnableProtectionCmd.CobraCommand(s)), + util.WithGroup("protection", DisableProtectionCmd.CobraCommand(s)), + + util.WithGroup("attach", AttachCmd.CobraCommand(s)), + util.WithGroup("attach", DetachCmd.CobraCommand(s)), ) return cmd }