Skip to content

Commit f52814d

Browse files
authored
Merge pull request #6705 from vvoland/list-fix
image/list: Fix `dangling=false` handling
2 parents 4d6fc33 + 0f03c31 commit f52814d

7 files changed

+94
-3
lines changed

cli/command/image/list.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func runImages(ctx context.Context, dockerCLI command.Cli, options imagesOptions
109109

110110
images := res.Items
111111
if !options.all {
112-
if _, ok := filters["dangling"]; !ok {
112+
if dangling, ok := filters["dangling"]; !ok || dangling["false"] {
113113
images = slices.DeleteFunc(images, isDangling)
114114
}
115115
}
@@ -127,7 +127,6 @@ func runImages(ctx context.Context, dockerCLI command.Cli, options imagesOptions
127127
if useTree {
128128
return runTree(ctx, dockerCLI, treeOptions{
129129
images: images,
130-
all: options.all,
131130
filters: filters,
132131
expanded: options.tree,
133132
})

cli/command/image/list_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"errors"
55
"fmt"
66
"io"
7+
"slices"
78
"testing"
89

910
"github.com/docker/cli/cli/config/configfile"
1011
"github.com/docker/cli/internal/test"
12+
"github.com/moby/moby/api/types/image"
1113
"github.com/moby/moby/client"
1214
"gotest.tools/v3/assert"
1315
"gotest.tools/v3/golden"
@@ -116,6 +118,86 @@ func TestNewListCommandAmbiguous(t *testing.T) {
116118
golden.Assert(t, cli.ErrBuffer().String(), "list-command-ambiguous.golden")
117119
}
118120

121+
func TestImagesFilterDangling(t *testing.T) {
122+
// Create test images with different states
123+
items := []image.Summary{
124+
{
125+
ID: "sha256:87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7",
126+
RepoTags: []string{"myimage:latest"},
127+
RepoDigests: []string{"myimage@sha256:abc123"},
128+
},
129+
{
130+
ID: "sha256:0263829989b6fd954f72baaf2fc64bc2e2f01d692d4de72986ea808f6e99813f",
131+
RepoTags: []string{},
132+
RepoDigests: []string{},
133+
},
134+
{
135+
ID: "sha256:a3a5e715f0cc574a73c3f9bebb6bc24f32ffd5b67b387244c2c909da779a1478",
136+
RepoTags: []string{},
137+
RepoDigests: []string{"image@sha256:a3a5e715f0cc574a73c3f9bebb6bc24f32ffd5b67b387244c2c909da779a1478"},
138+
},
139+
}
140+
141+
testCases := []struct {
142+
name string
143+
args []string
144+
imageListFunc func(options client.ImageListOptions) (client.ImageListResult, error)
145+
}{
146+
{
147+
name: "dangling-true",
148+
args: []string{"-f", "dangling=true"},
149+
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
150+
// Verify the filter is passed to the API
151+
assert.Check(t, options.Filters["dangling"]["true"])
152+
// dangling=true is handled on the server side and returns only dangling images
153+
return client.ImageListResult{Items: []image.Summary{items[1], items[2]}}, nil
154+
},
155+
},
156+
{
157+
name: "dangling-false",
158+
args: []string{"-f", "dangling=false"},
159+
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
160+
// Verify the filter is passed to the API
161+
assert.Check(t, options.Filters["dangling"]["false"])
162+
// Return all images including dangling
163+
return client.ImageListResult{Items: slices.Clone(items)}, nil
164+
},
165+
},
166+
{
167+
name: "no-dangling-filter",
168+
args: []string{},
169+
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
170+
// Verify no dangling filter is passed to the API
171+
_, exists := options.Filters["dangling"]
172+
assert.Check(t, !exists)
173+
// Return all images including dangling
174+
return client.ImageListResult{Items: slices.Clone(items)}, nil
175+
},
176+
},
177+
{
178+
name: "all-flag",
179+
args: []string{"--all"},
180+
imageListFunc: func(options client.ImageListOptions) (client.ImageListResult, error) {
181+
// Verify the All flag is set
182+
assert.Check(t, options.All)
183+
// Return all images including dangling
184+
return client.ImageListResult{Items: slices.Clone(items)}, nil
185+
},
186+
},
187+
}
188+
189+
for _, tc := range testCases {
190+
t.Run(tc.name, func(t *testing.T) {
191+
cli := test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc})
192+
cmd := newImagesCommand(cli)
193+
cmd.SetArgs(tc.args)
194+
err := cmd.Execute()
195+
assert.NilError(t, err)
196+
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("list-command-filter-dangling.%s.golden", tc.name))
197+
})
198+
}
199+
}
200+
119201
func nilToEmptySlice[T any](s []T) []T {
120202
if s == nil {
121203
return []T{}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
2+
myimage:latest 87428fc52280 0B 0B
3+
<untagged> 0263829989b6 0B 0B
4+
<untagged> a3a5e715f0cc 0B 0B
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
2+
myimage:latest 87428fc52280 0B 0B
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
2+
<untagged> 0263829989b6 0B 0B
3+
<untagged> a3a5e715f0cc 0B 0B
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
2+
myimage:latest 87428fc52280 0B 0B

cli/command/image/tree.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const untaggedName = "<untagged>"
2626

2727
type treeOptions struct {
2828
images []imagetypes.Summary
29-
all bool
3029
filters client.Filters
3130
expanded bool
3231
}

0 commit comments

Comments
 (0)