Skip to content

Commit

Permalink
feat: group subcommands in command help
Browse files Browse the repository at this point in the history
  • Loading branch information
phm07 committed Jan 31, 2024
1 parent f31bb6e commit c5ffb64
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 732 deletions.
602 changes: 0 additions & 602 deletions CHANGELOG.md

This file was deleted.

106 changes: 103 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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
```
31 changes: 19 additions & 12 deletions internal/cmd/firewall/firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package firewall
import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
)

Expand All @@ -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
}
32 changes: 20 additions & 12 deletions internal/cmd/floatingip/floatingip.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package floatingip
import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
)

Expand All @@ -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
}
21 changes: 13 additions & 8 deletions internal/cmd/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package image
import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
)

Expand All @@ -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
}
57 changes: 35 additions & 22 deletions internal/cmd/loadbalancer/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package loadbalancer
import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
)

Expand All @@ -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
}
38 changes: 23 additions & 15 deletions internal/cmd/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package network
import (
"github.com/spf13/cobra"

"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/state"
)

Expand All @@ -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
}
Loading

0 comments on commit c5ffb64

Please sign in to comment.