Skip to content

Commit 7059ef4

Browse files
committed
formatter: Sort labels for stable output
Several Labels() methods iterated over maps without sorting, producing non-deterministic output. In early versions of Go, map iteration order happened to be stable in practice, so the original code appeared to work correctly. Since Go 1.12, the runtime intentionally randomizes map iteration order, making the output unpredictable between runs. The API response produces sorted labels and the container formatter already sorted its labels (changed in 5ee17ee). Apply the same fix to the volume, network, config, and secret formatters, and update tests to assert exact ordering instead of using order-independent comparison. Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
1 parent 977ee83 commit 7059ef4

6 files changed

Lines changed: 22 additions & 6 deletions

File tree

cli/command/config/formatter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.25
3+
14
package config
25

36
import (
47
"fmt"
8+
"slices"
59
"strings"
610
"time"
711

@@ -102,6 +106,7 @@ func (c *configContext) Labels() string {
102106
for k, v := range mapLabels {
103107
joinLabels = append(joinLabels, k+"="+v)
104108
}
109+
slices.Sort(joinLabels)
105110
return strings.Join(joinLabels, ",")
106111
}
107112

cli/command/formatter/volume.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.25
3+
14
package formatter
25

36
import (
47
"fmt"
8+
"slices"
59
"strconv"
610
"strings"
711

@@ -104,6 +108,7 @@ func (c *volumeContext) Labels() string {
104108
for k, v := range c.v.Labels {
105109
joinLabels = append(joinLabels, k+"="+v)
106110
}
111+
slices.Sort(joinLabels)
107112
return strings.Join(joinLabels, ",")
108113
}
109114

cli/command/formatter/volume_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ func TestVolumeContext(t *testing.T) {
4848
for _, c := range cases {
4949
ctx = c.volumeCtx
5050
v := c.call()
51-
if strings.Contains(v, ",") {
52-
test.CompareMultipleValues(t, v, c.expValue)
53-
} else if v != c.expValue {
51+
if v != c.expValue {
5452
t.Fatalf("Expected %s, was %s\n", c.expValue, v)
5553
}
5654
}

cli/command/network/formatter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.25
3+
14
package network
25

36
import (
7+
"slices"
48
"strconv"
59
"strings"
610

@@ -115,6 +119,7 @@ func (c *networkContext) Labels() string {
115119
for k, v := range c.n.Labels {
116120
joinLabels = append(joinLabels, k+"="+v)
117121
}
122+
slices.Sort(joinLabels)
118123
return strings.Join(joinLabels, ",")
119124
}
120125

cli/command/network/formatter_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ func TestNetworkContext(t *testing.T) {
6868
for _, c := range cases {
6969
ctx = c.networkCtx
7070
v := c.call()
71-
if strings.Contains(v, ",") {
72-
test.CompareMultipleValues(t, v, c.expValue)
73-
} else if v != c.expValue {
71+
if v != c.expValue {
7472
t.Fatalf("Expected %s, was %s\n", c.expValue, v)
7573
}
7674
}

cli/command/secret/formatter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.25
3+
14
package secret
25

36
import (
47
"fmt"
8+
"slices"
59
"strings"
610
"time"
711

@@ -109,6 +113,7 @@ func (c *secretContext) Labels() string {
109113
for k, v := range mapLabels {
110114
joinLabels = append(joinLabels, k+"="+v)
111115
}
116+
slices.Sort(joinLabels)
112117
return strings.Join(joinLabels, ",")
113118
}
114119

0 commit comments

Comments
 (0)