diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 10c0c14..64b8aae 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -18,11 +18,14 @@ jobs: with: go-version: 1.18 + - name: Lint + uses: golangci/golangci-lint-action@v2 + - name: Build run: make build - - name: Test - run: make test + - name: Run coverage + run: go test -race -coverprofile=coverage.out -covermode=atomic -tags test ./... - - name: Lint - uses: golangci/golangci-lint-action@v2 + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v2 diff --git a/Makefile b/Makefile index ae12b6a..571755b 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ build: $(GO) build -o $(BIN)/$(APP) ./cmd/cli test: - go test -v ./... + go test ./... clean: rm -f $(BIN)/$(APP)* diff --git a/README.md b/README.md index f9c95e5..6fb5fa6 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@

+ Coverage Downloads Release License diff --git a/cmd/cli/main.go b/cmd/cli/main.go index dd7ea5e..73ac4fe 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -1,10 +1,9 @@ +//go:build !test + package main import ( "docker-color-output/internal/cli" - "docker-color-output/internal/cmd" - "docker-color-output/internal/lines" - "docker-color-output/internal/lines/fmt" "docker-color-output/internal/stdin" "docker-color-output/internal/stdout" ) @@ -15,21 +14,12 @@ func main() { cli.Exit(err) } - c, err := cmd.ParseCmd(in) + vals, err := cli.Execute(in) if err != nil { cli.Exit(err) } - res := make([]*lines.Line, len(in)) - - cols, values := cmd.ParseFirstLine(in[0]) - res[0] = lines.NewLine(values, cols, fmt.NewFirstLineFmt()) - - for i, values := range cmd.ParseLines(in[1:], cols) { - res[i+1] = lines.NewLine(values, cols, c.GetFmt()) - } - - for _, v := range res { + for _, v := range vals { stdout.Println(v) } } diff --git a/internal/cli/app.go b/internal/cli/app.go new file mode 100644 index 0000000..f309fd7 --- /dev/null +++ b/internal/cli/app.go @@ -0,0 +1,31 @@ +package cli + +import ( + "docker-color-output/internal/cmd" + "docker-color-output/internal/lines" + "docker-color-output/internal/lines/fmt" +) + +func Execute(in []string) ([]*lines.Line, error) { + c, err := cmd.ParseCmd(in) + if err != nil { + return nil, err + } + + res := make([]*lines.Line, len(in)) + + cols, vals := cmd.ParseFirstLine(in[0]) + + res[0] = lines.NewLine(vals, cols, fmt.NewFirstLineFmt()) + + pl, err := cmd.ParseLines(in[1:], cols) + if err != nil { + return nil, err + } + + for i, vals := range pl { + res[i+1] = lines.NewLine(vals, cols, c.GetFmt()) + } + + return res, nil +} diff --git a/internal/cli/app_test.go b/internal/cli/app_test.go new file mode 100644 index 0000000..17a2b24 --- /dev/null +++ b/internal/cli/app_test.go @@ -0,0 +1,58 @@ +package cli + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "docker-color-output/internal/lines" + "docker-color-output/pkg/utils/assert" +) + +func TestExecute(t *testing.T) { + read := func(filename string) []string { + _, b, _, _ := runtime.Caller(0) + path := filepath.Dir(b) + bytes, _ := os.ReadFile(path + "/../../test/data/" + filename) + vals := strings.Split(string(bytes), "\n") + vals = vals[:len(vals)-1] + if len(vals) == 0 { + return nil + } + return vals + } + + build := func(in []*lines.Line) []string { + var vals []string + for _, v := range in { + vals = append(vals, v.Build()) + } + return vals + } + + tests := map[string]struct { + in string + want string + wantErr bool + }{ + "no_stdin": {wantErr: true}, + "no_first_line": {in: "in/no_first_line.out", wantErr: true}, + "invalid_cols": {in: "in/invalid_cols.out", wantErr: true}, + "docker_ps": {in: "in/docker_ps.out", want: "out/docker_ps.out"}, + "docker_ps:custom_cols": {in: "in/docker_ps_custom_cols.out", want: "out/docker_ps_custom_cols.out"}, + "docker_ps:nullable_col": {in: "in/docker_ps_nullable_col.out", want: "out/docker_ps_nullable_col.out"}, + "docker_ps:nullable_cols": {in: "in/docker_ps_nullable_cols.out", wantErr: true}, + "docker_images": {in: "in/docker_images.out", want: "out/docker_images.out"}, + "docker_compose_ps": {in: "in/docker_compose_ps.out", want: "out/docker_compose_ps.out"}, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + vals, err := Execute(read(tt.in)) + assert.Equal(t, tt.wantErr, err != nil) + assert.Equal(t, read(tt.want), build(vals)) + }) + } +} diff --git a/internal/cli/constants.go b/internal/cli/constants.go index bab79af..7cfa6b7 100644 --- a/internal/cli/constants.go +++ b/internal/cli/constants.go @@ -1,6 +1,6 @@ package cli const ( - Ver = "2.2.0" + Ver = "2.2.0-rc.1" App = "docker-color-output" ) diff --git a/internal/cli/cli.go b/internal/cli/shutdown.go similarity index 85% rename from internal/cli/cli.go rename to internal/cli/shutdown.go index d3807cb..d1d040a 100644 --- a/internal/cli/cli.go +++ b/internal/cli/shutdown.go @@ -1,3 +1,5 @@ +//go:build !test + package cli import ( @@ -12,8 +14,8 @@ func Exit(err error) { fmt.Println(color.LightRed("💡 Error: " + err.Error())) fmt.Println("💥 Docker color output " + color.Green(Ver)) fmt.Println("⚡️ Usage:") - fmt.Println(" " + color.Green(cmd.DockerImages.String()) + " | " + color.Brown(App)) - fmt.Println(" " + color.Green(cmd.DockerPs.String()) + " [-a] | " + color.Brown(App)) fmt.Println(" " + color.Green(cmd.DockerComposePs.String()) + " [-a] | " + color.Brown(App)) + fmt.Println(" " + color.Green(cmd.DockerImages.String()) + " [--format] | " + color.Brown(App)) + fmt.Println(" " + color.Green(cmd.DockerPs.String()) + " [-a] [--format] | " + color.Brown(App)) os.Exit(1) } diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 812664e..7f4b08d 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -2,24 +2,19 @@ package cmd import ( "errors" - "log" "strings" "docker-color-output/internal/lines" "docker-color-output/internal/utils" "docker-color-output/internal/utils/pointer" - "docker-color-output/pkg/color" ) func ParseCmd(in []string) (Cmd, error) { - if len(in) == 0 { + if len(in) == 0 || len(in[0]) == 0 { return "", errors.New("no first line") } parts := utils.Split(in[0]) - if len(parts) == 0 { - return "", errors.New("no first line") - } if utils.Intersect(parts, DockerPs.Columns()) { return DockerPs, nil @@ -36,11 +31,11 @@ func ParseCmd(in []string) (Cmd, error) { return "", errors.New("invalid first line") } -func ParseFirstLine(in string) ([]lines.Column, []string) { +func ParseFirstLine(in string) ([]lines.Column, lines.Values) { parts := utils.Split(in) cols := make([]lines.Column, len(parts)) - values := make([]string, len(parts)) + vals := make(lines.Values, len(parts)) for i, part := range parts { cols[i] = lines.Column{ @@ -48,29 +43,30 @@ func ParseFirstLine(in string) ([]lines.Column, []string) { Len: pointer.ToInt(len(part)), } - values[i] = part + vals[part] = part } - return cols, values + return cols, vals } -func ParseLines(ins []string, cols []lines.Column) [][]string { - rows := make([][]string, len(ins)) +func ParseLines(ins []string, cols []lines.Column) ([]lines.Values, error) { + if calculateNullableCols(cols) > 1 { + return nil, errors.New("nullable columns more than one") + } + + rows := make([]lines.Values, len(ins)) for i, in := range ins { - rows[i] = make([]string, len(cols)) + rows[i] = make(lines.Values, len(cols)) parts := utils.Split(in) offset := 0 - mismatches := len(cols) - len(parts) - if mismatches > 1 { - log.Fatal(color.Red("nullable columns more than two")) // panic - } + mismatch := len(parts) < len(cols) for j, col := range cols { - if mismatches > 0 && (col.Name == "PORTS" || col.Name == "MOUNTS") { - offset += 1 + if mismatch && col.IsNullable() { + offset++ continue } @@ -85,9 +81,20 @@ func ParseLines(ins []string, cols []lines.Column) [][]string { *col.Len = l } - rows[i][j] = v + rows[i][col.Name] = v + } + } + + return rows, nil +} + +func calculateNullableCols(cols []lines.Column) byte { + var total byte = 0 + for _, col := range cols { + if col.IsNullable() { + total++ } } - return rows + return total } diff --git a/internal/cmd/constants.go b/internal/cmd/constants.go index 81b89a1..ab19170 100644 --- a/internal/cmd/constants.go +++ b/internal/cmd/constants.go @@ -24,17 +24,17 @@ func (c Cmd) Columns() []string { "NAMES", // "LABELS", // opt "MOUNTS", // opt | nullable - "NETWORKS", // opt + "NETWORKS", // opt | nullable } case DockerImages: return []string{ - "IMAGE ID", - "REPOSITORY", - "TAG", - "DIGEST", - "CREATED", - "CREATED AT", - "SIZE", + "IMAGE ID", // + "REPOSITORY", // + "TAG", // + "DIGEST", // opt + "CREATED", // + "CREATED AT", // opt + "SIZE", // } case DockerComposePs: return []string{ diff --git a/internal/lines/contracts.go b/internal/lines/contracts.go index e41892b..218c99a 100644 --- a/internal/lines/contracts.go +++ b/internal/lines/contracts.go @@ -3,3 +3,14 @@ package lines type Buildable interface { Build() string } + +type Values map[string]string + +type Column struct { + Name string + Len *int +} + +func (c *Column) IsNullable() bool { + return c.Name == "PORTS" || c.Name == "MOUNTS" || c.Name == "NETWORKS" +} diff --git a/internal/lines/fmt/contracts.go b/internal/lines/fmt/contracts.go index 45136e0..293691a 100644 --- a/internal/lines/fmt/contracts.go +++ b/internal/lines/fmt/contracts.go @@ -1,5 +1,5 @@ package fmt type Formatable interface { - Format(col string, v string) string + Format(vals map[string]string, col string) string } diff --git a/internal/lines/fmt/docker_compose_ps_line_fmt.go b/internal/lines/fmt/docker_compose_ps_line_fmt.go index 1710002..78a1663 100644 --- a/internal/lines/fmt/docker_compose_ps_line_fmt.go +++ b/internal/lines/fmt/docker_compose_ps_line_fmt.go @@ -12,8 +12,8 @@ func NewDockerComposePsLineFmt() *DockerComposePsLineFmt { return &DockerComposePsLineFmt{} } -func (*DockerComposePsLineFmt) Name(v string) string { - if strings.Contains(v, "exited") { // @fixme status +func (*DockerComposePsLineFmt) Name(v, status string) string { + if strings.Contains(status, "exited") { return color.DarkGray(v) } return color.White(v) @@ -23,8 +23,8 @@ func (*DockerComposePsLineFmt) Command(v string) string { return color.DarkGray(v) } -func (*DockerComposePsLineFmt) Service(v string) string { - if strings.Contains(v, "exited") { // @fixme status +func (*DockerComposePsLineFmt) Service(v, status string) string { + if strings.Contains(status, "exited") { return color.DarkGray(v) } return color.Yellow(v) @@ -49,14 +49,15 @@ func (*DockerComposePsLineFmt) Ports(v string) string { return strings.Join(ports, ", ") } -func (f *DockerComposePsLineFmt) Format(col string, v string) string { +func (f *DockerComposePsLineFmt) Format(vals map[string]string, col string) string { + v := vals[col] switch col { case "NAME": - return f.Name(v) + return f.Name(v, vals["STATUS"]) case "COMMAND": return f.Command(v) case "SERVICE": - return f.Service(v) + return f.Service(v, vals["STATUS"]) case "STATUS": return f.Status(v) case "PORTS": diff --git a/internal/lines/fmt/docker_images_line_fmt.go b/internal/lines/fmt/docker_images_line_fmt.go index f7e7197..15d27a6 100644 --- a/internal/lines/fmt/docker_images_line_fmt.go +++ b/internal/lines/fmt/docker_images_line_fmt.go @@ -27,7 +27,7 @@ func (*DockerImagesLineFmt) Tag(v string) string { return v } -func (*DockerImagesLineFmt) ImageId(v string) string { +func (*DockerImagesLineFmt) ImageID(v string) string { return color.DarkGray(v) } @@ -60,14 +60,15 @@ func (*DockerImagesLineFmt) Size(v string) string { return v } -func (f *DockerImagesLineFmt) Format(col string, v string) string { +func (f *DockerImagesLineFmt) Format(vals map[string]string, col string) string { + v := vals[col] switch col { case "REPOSITORY": return f.Repository(v) case "TAG": return f.Tag(v) case "IMAGE ID": - return f.ImageId(v) + return f.ImageID(v) case "CREATED": return f.Created(v) case "SIZE": diff --git a/internal/lines/fmt/docker_ps_line_fmt.go b/internal/lines/fmt/docker_ps_line_fmt.go index 10f390c..15e20d9 100644 --- a/internal/lines/fmt/docker_ps_line_fmt.go +++ b/internal/lines/fmt/docker_ps_line_fmt.go @@ -61,7 +61,8 @@ func (*DockerPsLineFmt) Names(v string) string { return color.White(v) } -func (f *DockerPsLineFmt) Format(col string, v string) string { +func (f *DockerPsLineFmt) Format(vals map[string]string, col string) string { + v := vals[col] switch col { case "CONTAINER ID": return f.ContainerID(v) diff --git a/internal/lines/fmt/first_line_fmt.go b/internal/lines/fmt/first_line_fmt.go index 1801ff9..ebd451b 100644 --- a/internal/lines/fmt/first_line_fmt.go +++ b/internal/lines/fmt/first_line_fmt.go @@ -8,6 +8,6 @@ func NewFirstLineFmt() *FirstLineFmt { return &FirstLineFmt{} } -func (f *FirstLineFmt) Format(_ string, v string) string { - return color.LightBlue(v) +func (f *FirstLineFmt) Format(_ map[string]string, col string) string { + return color.LightBlue(col) } diff --git a/internal/lines/line.go b/internal/lines/line.go index a9c063b..4b20f1e 100644 --- a/internal/lines/line.go +++ b/internal/lines/line.go @@ -8,27 +8,23 @@ import ( ) type Line struct { - values []string - cols []Column - fmt fmt.Formatable + vals Values + cols []Column + fmt fmt.Formatable } -func NewLine(values []string, cols []Column, fmt fmt.Formatable) *Line { +func NewLine(vals Values, cols []Column, fmt fmt.Formatable) *Line { return &Line{ - values: values, - cols: cols, - fmt: fmt, + vals: vals, + cols: cols, + fmt: fmt, } } func (l *Line) Build() string { var sb strings.Builder - - for i, col := range l.cols { - v := l.values[i] - v = l.fmt.Format(col.Name, v) - v = utils.Pad(v, *col.Len) - sb.WriteString(v) + for _, col := range l.cols { + sb.WriteString(utils.Pad(l.fmt.Format(l.vals, col.Name), *col.Len)) } return sb.String() diff --git a/internal/lines/types.go b/internal/lines/types.go deleted file mode 100644 index aa8936c..0000000 --- a/internal/lines/types.go +++ /dev/null @@ -1,6 +0,0 @@ -package lines - -type Column struct { - Name string - Len *int -} diff --git a/internal/utils/pointer/pointer_test.go b/internal/utils/pointer/pointer_test.go new file mode 100644 index 0000000..5b7e30f --- /dev/null +++ b/internal/utils/pointer/pointer_test.go @@ -0,0 +1,24 @@ +package pointer + +import ( + "testing" + + "docker-color-output/pkg/utils/assert" +) + +func TestToInt(t *testing.T) { + v := 0 + + tests := map[string]struct { + in int + want *int + }{ + "success": {v, &v}, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tt.want, ToInt(tt.in)) + }) + } +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 05f64e7..47d756c 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -2,7 +2,6 @@ package utils import ( "fmt" - "os" "regexp" "strconv" "strings" @@ -19,6 +18,7 @@ func Split(v string) []string { func Pad(value string, length int) string { length += NonPrintableCharactersLength * strings.Count(value, "\033[0m") + return fmt.Sprintf("%-"+strconv.Itoa(length+SpaceLength)+"s", value) } @@ -36,8 +36,3 @@ func Intersect(needle, haystack []string) bool { return true } - -func Debug(value any) { // @fixme - fmt.Printf("\n---\n%#v\n---\n\n", value) - os.Exit(0) -} diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go new file mode 100644 index 0000000..14db0a1 --- /dev/null +++ b/internal/utils/utils_test.go @@ -0,0 +1,70 @@ +package utils + +import ( + "testing" + + "docker-color-output/pkg/color" + "docker-color-output/pkg/utils/assert" +) + +func TestSplit(t *testing.T) { + tests := map[string]struct { + in string + want []string + }{ + "success": { + in: "CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES", + want: []string{"CONTAINER ID", "IMAGE", "COMMAND", "CREATED", "STATUS", "PORTS", "NAMES"}, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tt.want, Split(tt.in)) + }) + } +} + +func TestPad(t *testing.T) { + tests := map[string]struct { + value string + length int + want string + }{ + "colored": { + value: color.Red("IMAGE"), + length: 10, + want: "\u001B[0;31mIMAGE\u001B[0m ", + }, + "plain": { + value: "CONTAINER ID", + length: 15, + want: "CONTAINER ID ", + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tt.want, Pad(tt.value, tt.length)) + }) + } +} + +func TestIntersect(t *testing.T) { + tests := map[string]struct { + needle []string + haystack []string + want bool + }{ + "empty": {[]string{}, []string{}, true}, + "contains": {[]string{"1", "10"}, []string{"100", "1", "10"}, true}, + "does_not_contain": {[]string{"1", "10"}, []string{"0", "1", "5"}, false}, + "empty_value": {[]string{"", "1"}, []string{"1", "100", ""}, true}, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tt.want, Intersect(tt.needle, tt.haystack)) + }) + } +} diff --git a/pkg/utils/assert/assertions.go b/pkg/utils/assert/assertions.go index 580cad6..bde83a0 100644 --- a/pkg/utils/assert/assertions.go +++ b/pkg/utils/assert/assertions.go @@ -1,9 +1,12 @@ package assert -import "testing" +import ( + "reflect" + "testing" +) func Equal(t *testing.T, expected, actual interface{}) { - if expected != actual { + if !reflect.DeepEqual(expected, actual) { t.Errorf("Not equal:\nexpected: %s\nactual : %s", expected, actual) } } diff --git a/test/data/in/docker_compose_ps.out b/test/data/in/docker_compose_ps.out new file mode 100644 index 0000000..3f86f04 --- /dev/null +++ b/test/data/in/docker_compose_ps.out @@ -0,0 +1,3 @@ +NAME COMMAND SERVICE STATUS PORTS +cluster "docker-entrypoint.s…" cluster exited (0) +redis "docker-entrypoint.s…" redis running 6379/tcp diff --git a/test/data/in/docker_images.out b/test/data/in/docker_images.out new file mode 100644 index 0000000..ff6093a --- /dev/null +++ b/test/data/in/docker_images.out @@ -0,0 +1,4 @@ +REPOSITORY TAG IMAGE ID CREATED SIZE +dldash/home latest b310e6b0fb4d 15 hours ago 23.5MB +redis latest bba24acba395 11 days ago 113MB +golangci/golangci-lint latest 94f49b27b197 2 weeks ago 987MB diff --git a/test/data/in/docker_ps.out b/test/data/in/docker_ps.out new file mode 100644 index 0000000..7d88f2a --- /dev/null +++ b/test/data/in/docker_ps.out @@ -0,0 +1,3 @@ +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +24c5774ef118 dldash/home "/docker-entrypoint.…" 25 seconds ago Up 24 seconds 0.0.0.0:3000->80/tcp dldash.home +10f3c0ac6560 redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp redis diff --git a/test/data/in/docker_ps_custom_cols.out b/test/data/in/docker_ps_custom_cols.out new file mode 100644 index 0000000..fb7e56c --- /dev/null +++ b/test/data/in/docker_ps_custom_cols.out @@ -0,0 +1,3 @@ +NAMES CREATED STATUS NETWORKS +dldash.home About an hour ago Up About an hour bridge +redis About an hour ago Up About an hour bridge diff --git a/test/data/in/docker_ps_nullable_col.out b/test/data/in/docker_ps_nullable_col.out new file mode 100644 index 0000000..c910afb --- /dev/null +++ b/test/data/in/docker_ps_nullable_col.out @@ -0,0 +1,3 @@ +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +fe47cddd7ede dldash/home "/docker-entrypoint.…" 42 seconds ago Exited (0) 40 seconds ago dldash.home +10f3c0ac6560 redis "docker-entrypoint.s…" 3 hours ago Up 3 hours 6379/tcp redis diff --git a/test/data/in/docker_ps_nullable_cols.out b/test/data/in/docker_ps_nullable_cols.out new file mode 100644 index 0000000..6967f89 --- /dev/null +++ b/test/data/in/docker_ps_nullable_cols.out @@ -0,0 +1,3 @@ +NAMES MOUNTS NAMES PORTS CREATED +dldash.home dldash.home 0.0.0.0:3000->80/tcp 2 hours ago +redis c06a7bd7d2af50… redis 6379/tcp 2 hours ago diff --git a/test/data/in/invalid_cols.out b/test/data/in/invalid_cols.out new file mode 100644 index 0000000..8e17584 --- /dev/null +++ b/test/data/in/invalid_cols.out @@ -0,0 +1,3 @@ +NAME CREATED +dldash.home About an hour ago +redis About an hour ago diff --git a/test/data/in/no_first_line.out b/test/data/in/no_first_line.out new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/test/data/in/no_first_line.out @@ -0,0 +1 @@ + diff --git a/test/data/out/docker_compose_ps.out b/test/data/out/docker_compose_ps.out new file mode 100644 index 0000000..8b77754 --- /dev/null +++ b/test/data/out/docker_compose_ps.out @@ -0,0 +1,3 @@ +NAME COMMAND SERVICE STATUS PORTS +cluster "docker-entrypoint.s…" cluster exited (0) +redis "docker-entrypoint.s…" redis running 6379/tcp diff --git a/test/data/out/docker_images.out b/test/data/out/docker_images.out new file mode 100644 index 0000000..c0a0813 --- /dev/null +++ b/test/data/out/docker_images.out @@ -0,0 +1,4 @@ +REPOSITORY TAG IMAGE ID CREATED SIZE +dldash/home latest b310e6b0fb4d 15 hours ago 23.5MB +redis latest bba24acba395 11 days ago 113MB +golangci/golangci-lint latest 94f49b27b197 2 weeks ago 987MB diff --git a/test/data/out/docker_ps.out b/test/data/out/docker_ps.out new file mode 100644 index 0000000..e5aa80b --- /dev/null +++ b/test/data/out/docker_ps.out @@ -0,0 +1,3 @@ +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +24c5774ef118 dldash/home "/docker-entrypoint.…" 25 seconds ago Up 24 seconds 0.0.0.0:3000->80/tcp dldash.home +10f3c0ac6560 redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp redis diff --git a/test/data/out/docker_ps_custom_cols.out b/test/data/out/docker_ps_custom_cols.out new file mode 100644 index 0000000..8e12e05 --- /dev/null +++ b/test/data/out/docker_ps_custom_cols.out @@ -0,0 +1,3 @@ +NAMES CREATED STATUS NETWORKS +dldash.home About an hour ago Up About an hour bridge +redis About an hour ago Up About an hour bridge diff --git a/test/data/out/docker_ps_nullable_col.out b/test/data/out/docker_ps_nullable_col.out new file mode 100644 index 0000000..1d589a6 --- /dev/null +++ b/test/data/out/docker_ps_nullable_col.out @@ -0,0 +1,3 @@ +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +fe47cddd7ede dldash/home "/docker-entrypoint.…" 42 seconds ago Exited (0) 40 seconds ago dldash.home +10f3c0ac6560 redis "docker-entrypoint.s…" 3 hours ago Up 3 hours 6379/tcp redis