Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: order by key when printing labels #960

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/hetznercloud/cli

go 1.22
go 1.23

toolchain go1.23.5

Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/certificate/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var DescribeCmd = base.DescribeCmd{
if len(cert.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range cert.Labels {
for key, value := range util.IterateInOrder(cert.Labels) {
cmd.Printf(" %s:\t%s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/firewall/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var DescribeCmd = base.DescribeCmd{
if len(firewall.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range firewall.Labels {
for key, value := range util.IterateInOrder(firewall.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/floatingip/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ var DescribeCmd = base.DescribeCmd{
if len(floatingIP.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range floatingIP.Labels {
for key, value := range util.IterateInOrder(floatingIP.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/image/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var DescribeCmd = base.DescribeCmd{
if len(image.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range image.Labels {
for key, value := range util.IterateInOrder(image.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/loadbalancer/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ var DescribeCmd = base.DescribeCmd{
if len(loadBalancer.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range loadBalancer.Labels {
for key, value := range util.IterateInOrder(loadBalancer.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/network/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var DescribeCmd = base.DescribeCmd{
if len(network.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range network.Labels {
for key, value := range util.IterateInOrder(network.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/placementgroup/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var DescribeCmd = base.DescribeCmd{
if len(placementGroup.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range placementGroup.Labels {
for key, value := range util.IterateInOrder(placementGroup.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/primaryip/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var DescribeCmd = base.DescribeCmd{
if len(primaryIP.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range primaryIP.Labels {
for key, value := range util.IterateInOrder(primaryIP.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/server/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ var DescribeCmd = base.DescribeCmd{
if len(server.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range server.Labels {
for key, value := range util.IterateInOrder(server.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/sshkey/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var DescribeCmd = base.DescribeCmd{
if len(sshKey.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range sshKey.Labels {
for key, value := range util.IterateInOrder(sshKey.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
24 changes: 16 additions & 8 deletions internal/cmd/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"encoding/json"
"fmt"
"io"
"iter"
"maps"
"reflect"
"sort"
"slices"
"strings"
"text/template"
"time"
Expand Down Expand Up @@ -148,13 +150,7 @@ func SplitLabelVars(label string) (string, string) {

func LabelsToString(labels map[string]string) string {
var labelsString []string
keys := make([]string, 0, len(labels))
for key := range labels {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
value := labels[key]
for key, value := range IterateInOrder(labels) {
if value == "" {
labelsString = append(labelsString, key)
} else {
Expand Down Expand Up @@ -369,3 +365,15 @@ func ToStringSliceDelimited(val any) []string {
return AnyToStringSlice(val)
}
}

// IterateInOrder returns an iterator that iterates over the map in order of the keys.
func IterateInOrder[M ~map[K]V, K cmp.Ordered, V any](m M) iter.Seq2[K, V] {
keys := slices.Sorted(maps.Keys(m))
return func(yield func(K, V) bool) {
for _, k := range keys {
if !yield(k, m[k]) {
return
}
}
}
}
25 changes: 25 additions & 0 deletions internal/cmd/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,3 +454,28 @@ func TestPrice(t *testing.T) {
})
}
}

func TestSortLabels(t *testing.T) {
labels := map[string]string{
"c": "baz",
"a": "foo",
"z": "qux",
"b": "bar",
}
expected := [][]string{
{"a", "foo"},
{"b", "bar"},
{"c", "baz"},
{"z", "qux"},
}

i := 0
for k, v := range util.IterateInOrder(labels) {
require.Less(t, i, 4)
exp := expected[i]
i++

assert.Equal(t, exp[0], k, "key not equal")
assert.Equal(t, exp[1], v, "value not equal")
}
}
2 changes: 1 addition & 1 deletion internal/cmd/volume/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var DescribeCmd = base.DescribeCmd{
if len(volume.Labels) == 0 {
cmd.Print(" No labels\n")
} else {
for key, value := range volume.Labels {
for key, value := range util.IterateInOrder(volume.Labels) {
cmd.Printf(" %s: %s\n", key, value)
}
}
Expand Down
Loading