Skip to content
This repository has been archived by the owner on Jun 13, 2021. It is now read-only.

Commit

Permalink
split image ls output to repo and tag
Browse files Browse the repository at this point in the history
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 <nick.adcock@docker.com>
  • Loading branch information
zappy-shu committed Oct 30, 2019
1 parent 7217a4a commit ea4d7d7
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 84 deletions.
103 changes: 54 additions & 49 deletions e2e/images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"path/filepath"
"regexp"
"strings"
"testing"

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

func assertImageListOutput(t *testing.T, cmd icmd.Cmd, expected string) {
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
match, _ := regexp.MatchString(expected, result.Stdout())
assert.Assert(t, match)
}

func expectImageListOutput(t *testing.T, cmd icmd.Cmd, output string) {
cmd.Command = dockerCli.Command("app", "image", "ls")
result := icmd.RunCmd(cmd).Assert(t, icmd.Success)
assert.Equal(t, result.Stdout(), output)
assertImageListOutput(t, cmd, output)
}

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

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

insertBundles(t, cmd, info)

expected := `APP IMAGE APP NAME
%s push-pull
a-simple-app:latest simple
b-simple-app:latest simple
expected := `REPOSITORY TAG APP IMAGE ID APP NAME
%s latest [a-f0-9]{12} push-pull
a-simple-app latest [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
`
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp:latest")
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp")
expectImageListOutput(t, cmd, expectedOutput)
})
}
Expand All @@ -78,12 +83,12 @@ func TestImageListDigests(t *testing.T) {
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
cmd := info.configuredCmd
insertBundles(t, cmd, info)
expected := `APP IMAGE DIGEST APP NAME
%s <none> push-pull
a-simple-app:latest <none> simple
b-simple-app:latest <none> simple
expected := `REPOSITORY TAG DIGEST APP IMAGE ID APP NAME
%s latest <none> [a-f0-9]{12} push-pull
a-simple-app latest <none> [a-f0-9]{12} simple
b-simple-app latest <none> [a-f0-9]{12} simple
`
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp:latest")
expectedOutput := fmt.Sprintf(expected, info.registryAddress+"/c-myapp")
expectImageListDigestsOutput(t, cmd, expectedOutput)
})
}
Expand Down Expand Up @@ -113,7 +118,7 @@ Deleted: b-simple-app:latest`,
Err: `Error: no such image b-simple-app:latest`,
})

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

singleImageExpectation := `APP IMAGE APP NAME
a-simple-app:latest simple
singleImageExpectation := `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app latest [a-f0-9]{12} simple
`
expectImageListOutput(t, cmd, singleImageExpectation)

Expand Down Expand Up @@ -181,63 +186,63 @@ a-simple-app:latest simple
// tag image with only names
dockerAppImageTag("a-simple-app", "b-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:latest simple
b-simple-app:latest simple
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app latest [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
`)

// target tag
dockerAppImageTag("a-simple-app", "a-simple-app:0.1")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
a-simple-app:latest simple
b-simple-app:latest simple
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app 0.1 [a-f0-9]{12} simple
a-simple-app latest [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
`)

// source tag
dockerAppImageTag("a-simple-app:0.1", "c-simple-app")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
a-simple-app:latest simple
b-simple-app:latest simple
c-simple-app:latest simple
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app 0.1 [a-f0-9]{12} simple
a-simple-app latest [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
c-simple-app latest [a-f0-9]{12} simple
`)

// source and target tags
dockerAppImageTag("a-simple-app:0.1", "b-simple-app:0.2")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
a-simple-app:latest simple
b-simple-app:0.2 simple
b-simple-app:latest simple
c-simple-app:latest simple
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app 0.1 [a-f0-9]{12} simple
a-simple-app latest [a-f0-9]{12} simple
b-simple-app 0.2 [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
c-simple-app latest [a-f0-9]{12} simple
`)

// given a new application
cmd.Command = dockerCli.Command("app", "build", "--tag", "push-pull", filepath.Join("testdata", "push-pull"))
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
a-simple-app:latest simple
b-simple-app:0.2 simple
b-simple-app:latest simple
c-simple-app:latest simple
push-pull:latest push-pull
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app 0.1 [a-f0-9]{12} simple
a-simple-app latest [a-f0-9]{12} simple
b-simple-app 0.2 [a-f0-9]{12} simple
b-simple-app latest [a-f0-9]{12} simple
c-simple-app latest [a-f0-9]{12} simple
push-pull latest [a-f0-9]{12} push-pull
`)

// can be tagged to an existing tag
dockerAppImageTag("push-pull", "b-simple-app:0.2")
icmd.RunCmd(cmd).Assert(t, icmd.Success)
expectImageListOutput(t, cmd, `APP IMAGE APP NAME
a-simple-app:0.1 simple
a-simple-app:latest simple
b-simple-app:0.2 push-pull
b-simple-app:latest simple
c-simple-app:latest simple
push-pull:latest push-pull
expectImageListOutput(t, cmd, `REPOSITORY TAG APP IMAGE ID APP NAME
a-simple-app 0.1 [a-f0-9]{12} simple
a-simple-app latest [a-f0-9]{12} simple
b-simple-app 0.2 [a-f0-9]{12} push-pull
b-simple-app latest [a-f0-9]{12} simple
c-simple-app latest [a-f0-9]{12} simple
push-pull latest [a-f0-9]{12} push-pull
`)
})
}
50 changes: 38 additions & 12 deletions internal/commands/image/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,28 @@ func printImageIDs(dockerCli command.Cli, refs []pkg) error {
var buf bytes.Buffer

for _, ref := range refs {
id, ok := ref.ref.(store.ID)
if !ok {
var err error
id, err = store.FromBundle(ref.bundle)
if err != nil {
return err
}
id, err := getImageID(ref)
if err != nil {
return err
}
fmt.Fprintln(&buf, stringid.TruncateID(id.String()))
fmt.Fprintln(&buf, id)
}
fmt.Fprintf(dockerCli.Out(), buf.String())
return nil
}

func getImageID(p pkg) (string, error) {
id, ok := p.ref.(store.ID)
if !ok {
var err error
id, err = store.FromBundle(p.bundle)
if err != nil {
return "", err
}
}
return stringid.TruncateID(id.String()), nil
}

func printHeaders(w io.Writer, listColumns []imageListColumn) {
var headers []string
for _, column := range listColumns {
Expand All @@ -136,9 +144,18 @@ func printValues(w io.Writer, ref pkg, listColumns []imageListColumn) {

func getImageListColumns(options imageListOption) []imageListColumn {
columns := []imageListColumn{
{"APP IMAGE", func(p pkg) string {
{"REPOSITORY", func(p pkg) string {
if n, ok := p.ref.(reference.Named); ok {
return reference.FamiliarName(n)
}
return reference.FamiliarString(p.ref)
}},
{"TAG", func(p pkg) string {
if t, ok := p.ref.(reference.Tagged); ok {
return t.Tag()
}
return "<none>"
}},
}
if options.digests {
columns = append(columns, imageListColumn{"DIGEST", func(p pkg) string {
Expand All @@ -148,9 +165,18 @@ func getImageListColumns(options imageListOption) []imageListColumn {
return "<none>"
}})
}
columns = append(columns, imageListColumn{"APP NAME", func(p pkg) string {
return p.bundle.Name
}})
columns = append(columns,
imageListColumn{"APP IMAGE ID", func(p pkg) string {
id, err := getImageID(p)
if err != nil {
return ""
}
return id
}},
imageListColumn{"APP NAME", func(p pkg) string {
return p.bundle.Name
}},
)
return columns
}

Expand Down
65 changes: 42 additions & 23 deletions internal/commands/image/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,47 +48,66 @@ func (b *bundleStoreStubForListCmd) Remove(ref reference.Reference) error {
return nil
}

func TestListWithQuietFlag(t *testing.T) {
func TestListCmd(t *testing.T) {
ref, err := store.FromString("a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087")
assert.NilError(t, err)
refs := []reference.Reference{
ref,
parseReference(t, "foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865"),
parseReference(t, "foo/bar:1.0"),
ref,
}
bundles := []bundle.Bundle{
{},
{
Name: "Digested App",
},
{
Version: "1.0.0",
SchemaVersion: "1.0.0",
Name: "Foo App",
},
{
Name: "Quiet App",
},
}
expectedOutput := `a855ac937f2e
9aae408ee04f
`
testRunList(t, refs, bundles, imageListOption{quiet: true}, expectedOutput)
}

func TestListWithDigestsFlag(t *testing.T) {
refs := []reference.Reference{
parseReference(t, "foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865"),
parseReference(t, "foo/bar:1.0"),
}
bundles := []bundle.Bundle{
testCases := []struct {
name string
expectedOutput string
options imageListOption
}{
{
Name: "Digested App",
name: "TestList",
expectedOutput: `REPOSITORY TAG APP IMAGE ID APP NAME
foo/bar <none> 3f825b2d0657 Digested App
foo/bar 1.0 9aae408ee04f Foo App
a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 <none> a855ac937f2e Quiet App
`,
options: imageListOption{},
},
{
Version: "1.0.0",
SchemaVersion: "1.0.0",
Name: "Foo App",
name: "TestListWithDigests",
expectedOutput: `REPOSITORY TAG DIGEST APP IMAGE ID APP NAME
foo/bar <none> sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 3f825b2d0657 Digested App
foo/bar 1.0 <none> 9aae408ee04f Foo App
a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 <none> sha256:a855ac937f2ed375ba4396bbc49c4093e124da933acd2713fb9bc17d7562a087 a855ac937f2e Quiet App
`,
options: imageListOption{digests: true},
},
{
name: "TestListWithQuiet",
expectedOutput: `3f825b2d0657
9aae408ee04f
a855ac937f2e
`,
options: imageListOption{quiet: true},
},
}
expectedOutput := `APP IMAGE DIGEST APP NAME
foo/bar@sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 sha256:b59492bb814012ca3d2ce0b6728242d96b4af41687cc82166a4b5d7f2d9fb865 Digested App
foo/bar:1.0 <none> Foo App
`
testRunList(t, refs, bundles, imageListOption{digests: true}, expectedOutput)

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
testRunList(t, refs, bundles, tc.options, tc.expectedOutput)
})
}
}

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

0 comments on commit ea4d7d7

Please sign in to comment.