Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit fe99fda

Browse files
committed
Add --digests flag to image ls
Added the --digests flag to image ls. This makes the image ls command print the image digests (if present) along with the app name and image. Signed-off-by: Nick Adcock <[email protected]>
1 parent 9042ab2 commit fe99fda

File tree

3 files changed

+106
-33
lines changed

3 files changed

+106
-33
lines changed

e2e/images_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ func expectImageListOutput(t *testing.T, cmd icmd.Cmd, output string) {
2828
assert.Equal(t, result.Stdout(), output)
2929
}
3030

31+
func expectImageListDigestsOutput(t *testing.T, cmd icmd.Cmd, output string) {
32+
cmd.Command = dockerCli.Command("app", "image", "ls", "--digests")
33+
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
34+
assert.Equal(t, result.Stdout(), output)
35+
}
36+
3137
func verifyImageIDListOutput(t *testing.T, cmd icmd.Cmd, count int, distinct int) {
3238
cmd.Command = dockerCli.Command("app", "image", "ls", "-q")
3339
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
@@ -73,6 +79,22 @@ func TestImageListQuiet(t *testing.T) {
7379
})
7480
}
7581

82+
func TestImageListDigests(t *testing.T) {
83+
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
84+
cmd := info.configuredCmd
85+
dir := fs.NewDir(t, "")
86+
defer dir.Remove()
87+
insertBundles(t, cmd, info)
88+
expected := `APP IMAGE DIGEST APP NAME
89+
%s <none> push-pull
90+
a-simple-app:latest <none> simple
91+
b-simple-app:latest <none> simple
92+
`
93+
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp:latest")
94+
expectImageListDigestsOutput(t, cmd, expectedOutput)
95+
})
96+
}
97+
7698
func TestImageRm(t *testing.T) {
7799
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
78100
cmd := info.configuredCmd

internal/commands/image/list.go

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ import (
1717
)
1818

1919
type imageListOption struct {
20-
quiet bool
20+
quiet bool
21+
digests bool
22+
}
23+
24+
type imageListColumn struct {
25+
header string
26+
value func(p pkg) string
2127
}
2228

2329
func listCmd(dockerCli command.Cli) *cobra.Command {
@@ -42,6 +48,7 @@ func listCmd(dockerCli command.Cli) *cobra.Command {
4248
}
4349
flags := cmd.Flags()
4450
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only show numeric IDs")
51+
flags.BoolVarP(&options.digests, "digests", "", false, "Show image digests")
4552

4653
return cmd
4754
}
@@ -60,7 +67,7 @@ func runList(dockerCli command.Cli, options imageListOption, bundleStore store.B
6067
if options.quiet {
6168
return printImageIDs(dockerCli, pkgs)
6269
}
63-
return printImages(dockerCli, pkgs)
70+
return printImages(dockerCli, pkgs, options)
6471
}
6572

6673
func getPackages(bundleStore store.BundleStore, references []reference.Reference) ([]pkg, error) {
@@ -82,12 +89,12 @@ func getPackages(bundleStore store.BundleStore, references []reference.Reference
8289
return packages, nil
8390
}
8491

85-
func printImages(dockerCli command.Cli, refs []pkg) error {
92+
func printImages(dockerCli command.Cli, refs []pkg, options imageListOption) error {
8693
w := tabwriter.NewWriter(dockerCli.Out(), 0, 0, 1, ' ', 0)
87-
88-
printHeaders(w)
94+
listColumns := getImageListColumns(options)
95+
printHeaders(w, listColumns)
8996
for _, ref := range refs {
90-
printValues(w, ref)
97+
printValues(w, ref, listColumns)
9198
}
9299

93100
return w.Flush()
@@ -111,35 +118,41 @@ func printImageIDs(dockerCli command.Cli, refs []pkg) error {
111118
return nil
112119
}
113120

114-
func printHeaders(w io.Writer) {
121+
func printHeaders(w io.Writer, listColumns []imageListColumn) {
115122
var headers []string
116123
for _, column := range listColumns {
117124
headers = append(headers, column.header)
118125
}
119126
fmt.Fprintln(w, strings.Join(headers, "\t"))
120127
}
121128

122-
func printValues(w io.Writer, ref pkg) {
129+
func printValues(w io.Writer, ref pkg, listColumns []imageListColumn) {
123130
var values []string
124131
for _, column := range listColumns {
125132
values = append(values, column.value(ref))
126133
}
127134
fmt.Fprintln(w, strings.Join(values, "\t"))
128135
}
129136

130-
var (
131-
listColumns = []struct {
132-
header string
133-
value func(p pkg) string
134-
}{
137+
func getImageListColumns(options imageListOption) []imageListColumn {
138+
columns := []imageListColumn{
135139
{"APP IMAGE", func(p pkg) string {
136140
return reference.FamiliarString(p.ref)
137141
}},
138-
{"APP NAME", func(p pkg) string {
139-
return p.bundle.Name
140-
}},
141142
}
142-
)
143+
if options.digests {
144+
columns = append(columns, imageListColumn{"DIGEST", func(p pkg) string {
145+
if t, ok := p.ref.(reference.Digested); ok {
146+
return t.Digest().String()
147+
}
148+
return "<none>"
149+
}})
150+
}
151+
columns = append(columns, imageListColumn{"APP NAME", func(p pkg) string {
152+
return p.bundle.Name
153+
}})
154+
return columns
155+
}
143156

144157
type pkg struct {
145158
ref reference.Reference

internal/commands/image/list_test.go

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,55 @@ func (b *bundleStoreStubForListCmd) LookUp(refOrID string) (reference.Reference,
4747
}
4848

4949
func TestListWithQuietFlag(t *testing.T) {
50+
ref, err := store.FromString("a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087")
51+
assert.NilError(t, err)
52+
refs := []reference.Reference{
53+
ref,
54+
parseReference(t, "foo/bar:1.0"),
55+
}
56+
bundles := []bundle.Bundle{
57+
{},
58+
{
59+
Version: "1.0.0",
60+
SchemaVersion: "1.0.0",
61+
Name: "Foo App",
62+
},
63+
}
64+
expectedOutput := `a855ac937f2e
65+
9aae408ee04f
66+
`
67+
testRunList(t, refs, bundles, imageListOption{quiet: true}, expectedOutput)
68+
}
69+
70+
func TestListWithDigestsFlag(t *testing.T) {
71+
refs := []reference.Reference{
72+
parseReference(t, "foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865"),
73+
parseReference(t, "foo/bar:1.0"),
74+
}
75+
bundles := []bundle.Bundle{
76+
{
77+
Name: "Digested App",
78+
},
79+
{
80+
Version: "1.0.0",
81+
SchemaVersion: "1.0.0",
82+
Name: "Foo App",
83+
},
84+
}
85+
expectedOutput := `APP IMAGE DIGEST APP NAME
86+
foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 Digested App
87+
foo/bar:1.0 <none> Foo App
88+
`
89+
testRunList(t, refs, bundles, imageListOption{digests: true}, expectedOutput)
90+
}
91+
92+
func parseReference(t *testing.T, s string) reference.Reference {
93+
ref, err := reference.Parse(s)
94+
assert.NilError(t, err)
95+
return ref
96+
}
97+
98+
func testRunList(t *testing.T, refs []reference.Reference, bundles []bundle.Bundle, options imageListOption, expectedOutput string) {
5099
var buf bytes.Buffer
51100
w := bufio.NewWriter(&buf)
52101
dockerCli, err := command.NewDockerCli(command.WithOutputStream(w))
@@ -55,23 +104,12 @@ func TestListWithQuietFlag(t *testing.T) {
55104
refMap: make(map[reference.Reference]*bundle.Bundle),
56105
refList: []reference.Reference{},
57106
}
58-
ref1, err := store.FromString("a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087")
59-
assert.NilError(t, err)
60-
ref2, err := reference.Parse("foo/bar:1.0")
61-
assert.NilError(t, err)
62-
_, err = bundleStore.Store(ref1, &bundle.Bundle{})
63-
assert.NilError(t, err)
64-
_, err = bundleStore.Store(ref2, &bundle.Bundle{
65-
Version: "1.0.0",
66-
SchemaVersion: "1.0.0",
67-
Name: "Foo App",
68-
})
69-
assert.NilError(t, err)
70-
err = runList(dockerCli, imageListOption{quiet: true}, bundleStore)
107+
for i, ref := range refs {
108+
_, err = bundleStore.Store(ref, &bundles[i])
109+
assert.NilError(t, err)
110+
}
111+
err = runList(dockerCli, options, bundleStore)
71112
assert.NilError(t, err)
72-
expectedOutput := `a855ac937f2e
73-
9aae408ee04f
74-
`
75113
w.Flush()
76114
assert.Equal(t, buf.String(), expectedOutput)
77115
}

0 commit comments

Comments
 (0)