From 191aab9fe8bfd149565a7ca6ac1dd60a69bcaba3 Mon Sep 17 00:00:00 2001 From: Drew Erny Date: Thu, 5 Nov 2026 08:53:09 -0600 Subject: [PATCH] cli/command/formatter: restore fallback for container names with slashes Since commit f7a909d56b, ContainerContext.Names returns an empty string when truncating and every name of the container contains a slash. Before that change, all names were printed in that case. Classic Swarm prefixes container names with the node-name ("//"), so `docker ps` against a classic Swarm API printed an empty NAMES column. Restore the fallback to printing all names when no name without slashes is found. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Drew Erny --- cli/command/formatter/container.go | 27 ++++++++++++++----------- cli/command/formatter/container_test.go | 19 +++++++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/cli/command/formatter/container.go b/cli/command/formatter/container.go index 7b77a8a753..02d8110ad2 100644 --- a/cli/command/formatter/container.go +++ b/cli/command/formatter/container.go @@ -146,24 +146,27 @@ func (c *ContainerContext) ID() string { // slash (/) prefix stripped. Additional names for the container (related to the // legacy `--link` feature) are omitted when formatting "truncated". func (c *ContainerContext) Names() string { - var b strings.Builder - for i, n := range c.c.Names { - name := strings.TrimPrefix(n, "/") - if c.trunc { - // When printing truncated, we only print a single name. - // - // Pick the first name that's not a legacy link (does not have - // slashes inside the name itself (e.g., "/other-container/link")). - // Normally this would be the first name found. - if strings.IndexByte(name, '/') == -1 { + if c.trunc { + // When printing truncated, we only print a single name. + // + // Pick the first name that's not a legacy link (does not have + // slashes inside the name itself (e.g., "/other-container/link")). + // Normally this would be the first name found. + for _, n := range c.c.Names { + if name := strings.TrimPrefix(n, "/"); strings.IndexByte(name, '/') == -1 { return name } - continue } + // No name without slashes was found; this can happen when connected + // to a classic Swarm API, which prefixes names with the node-name + // ("//"). Fall back to printing all names. + } + var b strings.Builder + for i, n := range c.c.Names { if i > 0 { b.WriteByte(',') } - b.WriteString(name) + b.WriteString(strings.TrimPrefix(n, "/")) } return b.String() } diff --git a/cli/command/formatter/container_test.go b/cli/command/formatter/container_test.go index 07df93d9ae..98e9be4c22 100644 --- a/cli/command/formatter/container_test.go +++ b/cli/command/formatter/container_test.go @@ -48,6 +48,25 @@ func TestContainerPsContext(t *testing.T) { expValue: "foobar_baz", call: ctx.Names, }, + { + container: container.Summary{Names: []string{"/other/link", "/foobar_baz"}}, + trunc: true, + expValue: "foobar_baz", + call: ctx.Names, + }, + { + container: container.Summary{Names: []string{"/foobar_baz", "/other/link"}}, + expValue: "foobar_baz,other/link", + call: ctx.Names, + }, + { + // Names returned by a classic Swarm API are prefixed with the + // node-name; see https://github.com/docker/cli/pull/6875 + container: container.Summary{Names: []string{"/node-1/foobar_baz"}}, + trunc: true, + expValue: "node-1/foobar_baz", + call: ctx.Names, + }, { container: container.Summary{Image: "ubuntu"}, trunc: true,