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

Commit 24ced43

Browse files
committed
split image ls output to repo and tag
Split the app image ls output up so that the REPOSITORY and TAG are separate columns, the same as the standard docker image ls. The APP IMAGE ID column is now a default column, same as the ID column in docker image ls. As this ID is randomly generated the e2e tests have been updated to use regexes when asserting the command output. Signed-off-by: Nick Adcock <[email protected]>
1 parent fd651ed commit 24ced43

File tree

3 files changed

+134
-84
lines changed

3 files changed

+134
-84
lines changed

e2e/images_test.go

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"fmt"
66
"path/filepath"
7+
"regexp"
78
"strings"
89
"testing"
910

@@ -21,16 +22,20 @@ func insertBundles(t *testing.T, cmd icmd.Cmd, info dindSwarmAndRegistryInfo) {
2122
icmd.RunCmd(cmd).Assert(t, icmd.Success)
2223
}
2324

25+
func assertImageListOutput(t *testing.T, cmd icmd.Cmd, expected string) {
26+
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
27+
match, _ := regexp.MatchString(expected, result.Stdout())
28+
assert.Assert(t, match)
29+
}
30+
2431
func expectImageListOutput(t *testing.T, cmd icmd.Cmd, output string) {
2532
cmd.Command = dockerCli.Command("app", "image", "ls")
26-
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
27-
assert.Equal(t, result.Stdout(), output)
33+
assertImageListOutput(t, cmd, output)
2834
}
2935

3036
func expectImageListDigestsOutput(t *testing.T, cmd icmd.Cmd, output string) {
3137
cmd.Command = dockerCli.Command("app", "image", "ls", "--digests")
32-
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
33-
assert.Equal(t, result.Stdout(), output)
38+
assertImageListOutput(t, cmd, output)
3439
}
3540

3641
func verifyImageIDListOutput(t *testing.T, cmd icmd.Cmd, count int, distinct int) {
@@ -56,12 +61,12 @@ func TestImageList(t *testing.T) {
5661

5762
insertBundles(t, cmd, info)
5863

59-
expected := `APP IMAGE APP NAME
60-
%s push-pull
61-
a-simple-app:latest simple
62-
b-simple-app:latest simple
64+
expected := `REPOSITORY TAG APP IMAGE ID APP NAME
65+
%s latest [a-f0-9]{12} push-pull
66+
a-simple-app latest [a-f0-9]{12} simple
67+
b-simple-app latest [a-f0-9]{12} simple
6368
`
64-
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp:latest")
69+
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp")
6570
expectImageListOutput(t, cmd, expectedOutput)
6671
})
6772
}
@@ -78,12 +83,12 @@ func TestImageListDigests(t *testing.T) {
7883
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
7984
cmd := info.configuredCmd
8085
insertBundles(t, cmd, info)
81-
expected := `APP IMAGE DIGEST APP NAME
82-
%s <none> push-pull
83-
a-simple-app:latest <none> simple
84-
b-simple-app:latest <none> simple
86+
expected := `REPOSITORY TAG DIGEST APP IMAGE ID APP NAME
87+
%s latest <none> [a-f0-9]{12} push-pull
88+
a-simple-app latest <none> [a-f0-9]{12} simple
89+
b-simple-app latest <none> [a-f0-9]{12} simple
8590
`
86-
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp:latest")
91+
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp")
8792
expectImageListDigestsOutput(t, cmd, expectedOutput)
8893
})
8994
}
@@ -113,7 +118,7 @@ Deleted: b-simple-app:latest`,
113118
Err: `b-simple-app:latest: reference not found`,
114119
})
115120

116-
expectedOutput := "APP IMAGE APP NAME\n"
121+
expectedOutput := "REPOSITORY TAG APP IMAGE ID APP NAME\n"
117122
expectImageListOutput(t, cmd, expectedOutput)
118123
})
119124
}
@@ -131,8 +136,8 @@ func TestImageTag(t *testing.T) {
131136
cmd.Command = dockerCli.Command("app", "build", "--tag", "a-simple-app", filepath.Join("testdata", "simple"))
132137
icmd.RunCmd(cmd).Assert(t, icmd.Success)
133138

134-
singleImageExpectation := `APP IMAGE APP NAME
135-
a-simple-app:latest simple
139+
singleImageExpectation := `REPOSITORY TAG APP IMAGE ID APP NAME
140+
a-simple-app latest [a-f0-9]{12} simple
136141
`
137142
expectImageListOutput(t, cmd, singleImageExpectation)
138143

@@ -181,63 +186,63 @@ a-simple-app:latest simple
181186
// tag image with only names
182187
dockerAppImageTag("a-simple-app", "b-simple-app")
183188
icmd.RunCmd(cmd).Assert(t, icmd.Success)
184-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
185-
a-simple-app:latest simple
186-
b-simple-app:latest simple
189+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
190+
a-simple-app latest [a-f0-9]{12} simple
191+
b-simple-app latest [a-f0-9]{12} simple
187192
`)
188193

189194
// target tag
190195
dockerAppImageTag("a-simple-app", "a-simple-app:0.1")
191196
icmd.RunCmd(cmd).Assert(t, icmd.Success)
192-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
193-
a-simple-app:0.1 simple
194-
a-simple-app:latest simple
195-
b-simple-app:latest simple
197+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
198+
a-simple-app 0.1 [a-f0-9]{12} simple
199+
a-simple-app latest [a-f0-9]{12} simple
200+
b-simple-app latest [a-f0-9]{12} simple
196201
`)
197202

198203
// source tag
199204
dockerAppImageTag("a-simple-app:0.1", "c-simple-app")
200205
icmd.RunCmd(cmd).Assert(t, icmd.Success)
201-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
202-
a-simple-app:0.1 simple
203-
a-simple-app:latest simple
204-
b-simple-app:latest simple
205-
c-simple-app:latest simple
206+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
207+
a-simple-app 0.1 [a-f0-9]{12} simple
208+
a-simple-app latest [a-f0-9]{12} simple
209+
b-simple-app latest [a-f0-9]{12} simple
210+
c-simple-app latest [a-f0-9]{12} simple
206211
`)
207212

208213
// source and target tags
209214
dockerAppImageTag("a-simple-app:0.1", "b-simple-app:0.2")
210215
icmd.RunCmd(cmd).Assert(t, icmd.Success)
211-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
212-
a-simple-app:0.1 simple
213-
a-simple-app:latest simple
214-
b-simple-app:0.2 simple
215-
b-simple-app:latest simple
216-
c-simple-app:latest simple
216+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
217+
a-simple-app 0.1 [a-f0-9]{12} simple
218+
a-simple-app latest [a-f0-9]{12} simple
219+
b-simple-app 0.2 [a-f0-9]{12} simple
220+
b-simple-app latest [a-f0-9]{12} simple
221+
c-simple-app latest [a-f0-9]{12} simple
217222
`)
218223

219224
// given a new application
220225
cmd.Command = dockerCli.Command("app", "build", "--tag", "push-pull", filepath.Join("testdata", "push-pull"))
221226
icmd.RunCmd(cmd).Assert(t, icmd.Success)
222-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
223-
a-simple-app:0.1 simple
224-
a-simple-app:latest simple
225-
b-simple-app:0.2 simple
226-
b-simple-app:latest simple
227-
c-simple-app:latest simple
228-
push-pull:latest push-pull
227+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
228+
a-simple-app 0.1 [a-f0-9]{12} simple
229+
a-simple-app latest [a-f0-9]{12} simple
230+
b-simple-app 0.2 [a-f0-9]{12} simple
231+
b-simple-app latest [a-f0-9]{12} simple
232+
c-simple-app latest [a-f0-9]{12} simple
233+
push-pull latest [a-f0-9]{12} push-pull
229234
`)
230235

231236
// can be tagged to an existing tag
232237
dockerAppImageTag("push-pull", "b-simple-app:0.2")
233238
icmd.RunCmd(cmd).Assert(t, icmd.Success)
234-
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
235-
a-simple-app:0.1 simple
236-
a-simple-app:latest simple
237-
b-simple-app:0.2 push-pull
238-
b-simple-app:latest simple
239-
c-simple-app:latest simple
240-
push-pull:latest push-pull
239+
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
240+
a-simple-app 0.1 [a-f0-9]{12} simple
241+
a-simple-app latest [a-f0-9]{12} simple
242+
b-simple-app 0.2 [a-f0-9]{12} push-pull
243+
b-simple-app latest [a-f0-9]{12} simple
244+
c-simple-app latest [a-f0-9]{12} simple
245+
push-pull latest [a-f0-9]{12} push-pull
241246
`)
242247
})
243248
}

internal/commands/image/list.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,28 @@ func printImageIDs(dockerCli command.Cli, refs []pkg) error {
104104
var buf bytes.Buffer
105105

106106
for _, ref := range refs {
107-
id, ok := ref.ref.(store.ID)
108-
if !ok {
109-
var err error
110-
id, err = store.FromBundle(ref.bundle)
111-
if err != nil {
112-
return err
113-
}
107+
id, err := getImageID(ref)
108+
if err != nil {
109+
return err
114110
}
115-
fmt.Fprintln(&buf, stringid.TruncateID(id.String()))
111+
fmt.Fprintln(&buf, id)
116112
}
117113
fmt.Fprint(dockerCli.Out(), buf.String())
118114
return nil
119115
}
120116

117+
func getImageID(p pkg) (string, error) {
118+
id, ok := p.ref.(store.ID)
119+
if !ok {
120+
var err error
121+
id, err = store.FromBundle(p.bundle)
122+
if err != nil {
123+
return "", err
124+
}
125+
}
126+
return stringid.TruncateID(id.String()), nil
127+
}
128+
121129
func printHeaders(w io.Writer, listColumns []imageListColumn) {
122130
var headers []string
123131
for _, column := range listColumns {
@@ -136,9 +144,18 @@ func printValues(w io.Writer, ref pkg, listColumns []imageListColumn) {
136144

137145
func getImageListColumns(options imageListOption) []imageListColumn {
138146
columns := []imageListColumn{
139-
{"APP IMAGE", func(p pkg) string {
147+
{"REPOSITORY", func(p pkg) string {
148+
if n, ok := p.ref.(reference.Named); ok {
149+
return reference.FamiliarName(n)
150+
}
140151
return reference.FamiliarString(p.ref)
141152
}},
153+
{"TAG", func(p pkg) string {
154+
if t, ok := p.ref.(reference.Tagged); ok {
155+
return t.Tag()
156+
}
157+
return "<none>"
158+
}},
142159
}
143160
if options.digests {
144161
columns = append(columns, imageListColumn{"DIGEST", func(p pkg) string {
@@ -148,9 +165,18 @@ func getImageListColumns(options imageListOption) []imageListColumn {
148165
return "<none>"
149166
}})
150167
}
151-
columns = append(columns, imageListColumn{"APP NAME", func(p pkg) string {
152-
return p.bundle.Name
153-
}})
168+
columns = append(columns,
169+
imageListColumn{"APP IMAGE ID", func(p pkg) string {
170+
id, err := getImageID(p)
171+
if err != nil {
172+
return ""
173+
}
174+
return id
175+
}},
176+
imageListColumn{"APP NAME", func(p pkg) string {
177+
return p.bundle.Name
178+
}},
179+
)
154180
return columns
155181
}
156182

internal/commands/image/list_test.go

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,47 +46,66 @@ func (b *bundleStoreStubForListCmd) LookUp(refOrID string) (reference.Reference,
4646
return nil, nil
4747
}
4848

49-
func TestListWithQuietFlag(t *testing.T) {
49+
func TestListCmd(t *testing.T) {
5050
ref, err := store.FromString("a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087")
5151
assert.NilError(t, err)
5252
refs := []reference.Reference{
53-
ref,
53+
parseReference(t, "foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865"),
5454
parseReference(t, "foo/bar:1.0"),
55+
ref,
5556
}
5657
bundles := []bundle.Bundle{
57-
{},
58+
{
59+
Name: "Digested App",
60+
},
5861
{
5962
Version: "1.0.0",
6063
SchemaVersion: "1.0.0",
6164
Name: "Foo App",
6265
},
66+
{
67+
Name: "Quiet App",
68+
},
6369
}
64-
expectedOutput := `a855ac937f2e
65-
9aae408ee04f
66-
`
67-
testRunList(t, refs, bundles, imageListOption{quiet: true}, expectedOutput)
68-
}
6970

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{
71+
testCases := []struct {
72+
name string
73+
expectedOutput string
74+
options imageListOption
75+
}{
7676
{
77-
Name: "Digested App",
77+
name: "TestList",
78+
expectedOutput: `REPOSITORY TAG APP IMAGE ID APP NAME
79+
foo/bar <none> 3f825b2d0657 Digested App
80+
foo/bar 1.0 9aae408ee04f Foo App
81+
a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 <none> a855ac937f2e Quiet App
82+
`,
83+
options: imageListOption{},
7884
},
7985
{
80-
Version: "1.0.0",
81-
SchemaVersion: "1.0.0",
82-
Name: "Foo App",
86+
name: "TestListWithDigests",
87+
expectedOutput: `REPOSITORY TAG DIGEST APP IMAGE ID APP NAME
88+
foo/bar <none> sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 3f825b2d0657 Digested App
89+
foo/bar 1.0 <none> 9aae408ee04f Foo App
90+
a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 <none> sha256:a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 a855ac937f2e Quiet App
91+
`,
92+
options: imageListOption{digests: true},
93+
},
94+
{
95+
name: "TestListWithQuiet",
96+
expectedOutput: `3f825b2d0657
97+
9aae408ee04f
98+
a855ac937f2e
99+
`,
100+
options: imageListOption{quiet: true},
83101
},
84102
}
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)
103+
104+
for _, tc := range testCases {
105+
t.Run(tc.name, func(t *testing.T) {
106+
testRunList(t, refs, bundles, tc.options, tc.expectedOutput)
107+
})
108+
}
90109
}
91110

92111
func parseReference(t *testing.T, s string) reference.Reference {

0 commit comments

Comments
 (0)