Merge pull request #689 from ulyssessouza/json-out

Add json output format to several commands
This commit is contained in:
Guillaume Tardif 2020-10-05 10:30:30 +02:00 committed by GitHub
commit 97576db803
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 665 additions and 174 deletions

View file

@ -33,6 +33,7 @@ type composeOptions struct {
WorkingDir string
ConfigPaths []string
Environment []string
Format string
}
func (o *composeOptions) toProjectName() (string, error) {

View file

@ -23,8 +23,11 @@ import (
"os"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/formatter"
)
func listCommand() *cobra.Command {
@ -35,10 +38,15 @@ func listCommand() *cobra.Command {
return runList(cmd.Context(), opts)
},
}
lsCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name")
addComposeCommonFlags(lsCmd.Flags(), &opts)
return lsCmd
}
func addComposeCommonFlags(f *pflag.FlagSet, opts *composeOptions) {
f.StringVarP(&opts.Name, "project-name", "p", "", "Project name")
f.StringVar(&opts.Format, "format", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
}
func runList(ctx context.Context, opts composeOptions) error {
c, err := client.New(ctx)
if err != nil {
@ -49,10 +57,26 @@ func runList(ctx context.Context, opts composeOptions) error {
return err
}
err = printSection(os.Stdout, func(w io.Writer) {
for _, stack := range stackList {
fmt.Fprintf(w, "%s\t%s\n", stack.Name, stack.Status)
view := viewFromStackList(stackList)
return formatter.Print(view, opts.Format, os.Stdout, func(w io.Writer) {
for _, stack := range view {
_, _ = fmt.Fprintf(w, "%s\t%s\n", stack.Name, stack.Status)
}
}, "NAME", "STATUS")
return err
}
type stackView struct {
Name string
Status string
}
func viewFromStackList(stackList []compose.Stack) []stackView {
retList := make([]stackView, len(stackList))
for i, s := range stackList {
retList[i] = stackView{
Name: s.Name,
Status: s.Status,
}
}
return retList
}

View file

@ -22,11 +22,12 @@ import (
"io"
"os"
"strings"
"text/tabwriter"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/formatter"
)
func psCommand() *cobra.Command {
@ -37,10 +38,9 @@ func psCommand() *cobra.Command {
return runPs(cmd.Context(), opts)
},
}
psCmd.Flags().StringVarP(&opts.Name, "project-name", "p", "", "Project name")
psCmd.Flags().StringVar(&opts.WorkingDir, "workdir", "", "Work dir")
psCmd.Flags().StringArrayVarP(&opts.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
addComposeCommonFlags(psCmd.Flags(), &opts)
return psCmd
}
@ -59,17 +59,34 @@ func runPs(ctx context.Context, opts composeOptions) error {
return err
}
err = printSection(os.Stdout, func(w io.Writer) {
for _, service := range serviceList {
fmt.Fprintf(w, "%s\t%s\t%d/%d\t%s\n", service.ID, service.Name, service.Replicas, service.Desired, strings.Join(service.Ports, ", "))
}
}, "ID", "NAME", "REPLICAS", "PORTS")
return err
view := viewFromServiceStatusList(serviceList)
return formatter.Print(view, opts.Format, os.Stdout,
func(w io.Writer) {
for _, service := range view {
_, _ = fmt.Fprintf(w, "%s\t%s\t%d/%d\t%s\n", service.ID, service.Name, service.Replicas, service.Desired, strings.Join(service.Ports, ", "))
}
},
"ID", "NAME", "REPLICAS", "PORTS")
}
func printSection(out io.Writer, printer func(io.Writer), headers ...string) error {
w := tabwriter.NewWriter(out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, strings.Join(headers, "\t"))
printer(w)
return w.Flush()
type serviceStatusView struct {
ID string
Name string
Replicas int
Desired int
Ports []string
}
func viewFromServiceStatusList(serviceStatusList []compose.ServiceStatus) []serviceStatusView {
retList := make([]serviceStatusView, len(serviceStatusList))
for i, s := range serviceStatusList {
retList[i] = serviceStatusView{
ID: s.ID,
Name: s.Name,
Replicas: s.Replicas,
Desired: s.Desired,
Ports: s.Ports,
}
}
return retList
}

View file

@ -17,13 +17,13 @@
package context
import (
"errors"
"fmt"
"io"
"os"
"sort"
"strings"
"text/tabwriter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/cli/mobycli"
@ -58,7 +58,8 @@ func listCommand() *cobra.Command {
}
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Only show context names")
cmd.Flags().BoolVar(&opts.json, "json", false, "Format output as JSON")
cmd.Flags().StringVar(&opts.format, "format", "", "Format output as JSON")
cmd.Flags().StringVar(&opts.format, "format", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
_ = cmd.Flags().MarkHidden("json")
return cmd
}
@ -68,7 +69,7 @@ func runList(cmd *cobra.Command, opts lsOpts) error {
if err != nil {
return err
}
if opts.format != "" {
if opts.format != "" && opts.format != formatter.JSON && opts.format != formatter.PRETTY {
mobycli.Exec(cmd.Root())
return nil
}
@ -93,35 +94,27 @@ func runList(cmd *cobra.Command, opts lsOpts) error {
}
if opts.json {
j, err := formatter.ToStandardJSON(contexts)
if err != nil {
return err
}
fmt.Println(j)
return nil
opts.format = formatter.JSON
}
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, "NAME\tTYPE\tDESCRIPTION\tDOCKER ENDPOINT\tKUBERNETES ENDPOINT\tORCHESTRATOR")
format := "%s\t%s\t%s\t%s\t%s\t%s\n"
for _, c := range contexts {
contextName := c.Name
if c.Name == currentContext {
contextName += " *"
}
fmt.Fprintf(w,
format,
contextName,
c.Type(),
c.Metadata.Description,
getEndpoint("docker", c.Endpoints),
getEndpoint("kubernetes", c.Endpoints),
c.Metadata.StackOrchestrator)
}
return w.Flush()
view := viewFromContextList(contexts, currentContext)
return formatter.Print(view, opts.format, os.Stdout,
func(w io.Writer) {
for _, c := range view {
contextName := c.Name
if c.Current {
contextName += " *"
}
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n",
contextName,
c.Type,
c.Description,
c.DockerEndpoint,
c.KubernetesEndpoint,
c.StackOrchestrator)
}
},
"NAME", "TYPE", "DESCRIPTION", "DOCKER ENDPOINT", "KUBERNETES ENDPOINT", "ORCHESTRATOR")
}
func getEndpoint(name string, meta map[string]interface{}) string {
@ -141,3 +134,29 @@ func getEndpoint(name string, meta map[string]interface{}) string {
return result
}
type contextView struct {
Current bool
Description string
DockerEndpoint string
KubernetesEndpoint string
Type string
Name string
StackOrchestrator string
}
func viewFromContextList(contextList []*store.DockerContext, currentContext string) []contextView {
retList := make([]contextView, len(contextList))
for i, c := range contextList {
retList[i] = contextView{
Current: c.Name == currentContext,
Description: c.Metadata.Description,
DockerEndpoint: getEndpoint("docker", c.Endpoints),
KubernetesEndpoint: getEndpoint("kubernetes", c.Endpoints),
Name: c.Name,
Type: c.Type(),
StackOrchestrator: c.Metadata.StackOrchestrator,
}
}
return retList
}

View file

@ -56,7 +56,7 @@ func runInspect(ctx context.Context, id string) error {
if err != nil {
return err
}
fmt.Println(j)
fmt.Print(j)
return nil
}

View file

@ -19,9 +19,9 @@ package cmd
import (
"context"
"fmt"
"io"
"os"
"strings"
"text/tabwriter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -33,16 +33,10 @@ import (
)
type psOpts struct {
all bool
quiet bool
json bool
}
func (o psOpts) validate() error {
if o.quiet && o.json {
return errors.New(`cannot combine "quiet" and "json" options`)
}
return nil
all bool
quiet bool
json bool
format string
}
// PsCommand lists containers
@ -59,50 +53,52 @@ func PsCommand() *cobra.Command {
cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Only display IDs")
cmd.Flags().BoolVarP(&opts.all, "all", "a", false, "Show all containers (default shows just running)")
cmd.Flags().BoolVar(&opts.json, "json", false, "Format output as JSON")
cmd.Flags().StringVar(&opts.format, "format", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
_ = cmd.Flags().MarkHidden("json") // Legacy. This is used by VSCode Docker extension
return cmd
}
func (o psOpts) validate() error {
if o.quiet && o.json {
return errors.New(`cannot combine "quiet" and "json" options`)
}
return nil
}
func runPs(ctx context.Context, opts psOpts) error {
err := opts.validate()
if err != nil {
return err
}
c, err := client.New(ctx)
if err != nil {
return errors.Wrap(err, "cannot connect to backend")
}
containers, err := c.ContainerService().List(ctx, opts.all)
containerList, err := c.ContainerService().List(ctx, opts.all)
if err != nil {
return errors.Wrap(err, "fetch containers")
}
if opts.quiet {
for _, c := range containers {
for _, c := range containerList {
fmt.Println(c.ID)
}
return nil
}
if opts.json {
j, err := formatter2.ToStandardJSON(containers)
if err != nil {
return err
opts.format = formatter2.JSON
}
view := viewFromContainerList(containerList)
return formatter2.Print(view, opts.format, os.Stdout, func(w io.Writer) {
for _, c := range view {
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", c.ID, c.Image, c.Command, c.Status,
strings.Join(c.Ports, ", "))
}
fmt.Println(j)
return nil
}
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
fmt.Fprintf(w, "CONTAINER ID\tIMAGE\tCOMMAND\tSTATUS\tPORTS\n")
format := "%s\t%s\t%s\t%s\t%s\n"
for _, container := range containers {
fmt.Fprintf(w, format, container.ID, container.Image, container.Command, container.Status, strings.Join(formatter.PortsToStrings(container.Ports, fqdn(container)), ", "))
}
return w.Flush()
}, "CONTAINER ID", "IMAGE", "COMMAND", "STATUS", "PORTS")
}
func fqdn(container containers.Container) string {
@ -112,3 +108,25 @@ func fqdn(container containers.Container) string {
}
return fqdn
}
type containerView struct {
ID string
Image string
Status string
Command string
Ports []string
}
func viewFromContainerList(containerList []containers.Container) []containerView {
retList := make([]containerView, len(containerList))
for i, c := range containerList {
retList[i] = containerView{
ID: c.ID,
Image: c.Image,
Status: c.Status,
Command: c.Command,
Ports: formatter.PortsToStrings(c.Ports, fqdn(c)),
}
}
return retList
}

View file

@ -20,13 +20,12 @@ import (
"fmt"
"io"
"os"
"strings"
"text/tabwriter"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/secrets"
"github.com/docker/compose-cli/formatter"
)
type createSecretOptions struct {
@ -105,7 +104,12 @@ func inspectSecret() *cobra.Command {
return cmd
}
type listSecretsOpts struct {
format string
}
func listSecrets() *cobra.Command {
var opts listSecretsOpts
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
@ -115,17 +119,40 @@ func listSecrets() *cobra.Command {
if err != nil {
return err
}
list, err := c.SecretsService().ListSecrets(cmd.Context())
secretsList, err := c.SecretsService().ListSecrets(cmd.Context())
if err != nil {
return err
}
printList(os.Stdout, list)
return nil
view := viewFromSecretList(secretsList)
return formatter.Print(view, opts.format, os.Stdout, func(w io.Writer) {
for _, secret := range view {
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", secret.ID, secret.Name, secret.Description)
}
}, "ID", "NAME", "DESCRIPTION")
},
}
cmd.Flags().StringVar(&opts.format, "format", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
return cmd
}
type secretView struct {
ID string
Name string
Description string
}
func viewFromSecretList(secretList []secrets.Secret) []secretView {
retList := make([]secretView, len(secretList))
for i, s := range secretList {
retList[i] = secretView{
ID: s.ID,
Name: s.Name,
Description: s.Description,
}
}
return retList
}
type deleteSecretOptions struct {
recover bool
}
@ -148,18 +175,3 @@ func deleteSecret() *cobra.Command {
cmd.Flags().BoolVar(&opts.recover, "recover", false, "Enable recovery.")
return cmd
}
func printList(out io.Writer, secrets []secrets.Secret) {
printSection(out, func(w io.Writer) {
for _, secret := range secrets {
fmt.Fprintf(w, "%s\t%s\t%s\n", secret.ID, secret.Name, secret.Description) // nolint:errcheck
}
}, "ID", "NAME", "DESCRIPTION")
}
func printSection(out io.Writer, printer func(io.Writer), headers ...string) {
w := tabwriter.NewWriter(out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, strings.Join(headers, "\t")) // nolint:errcheck
printer(w)
w.Flush() // nolint:errcheck
}

View file

@ -1,39 +0,0 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"bytes"
"testing"
"gotest.tools/v3/golden"
"github.com/docker/compose-cli/api/secrets"
)
func TestPrintList(t *testing.T) {
secrets := []secrets.Secret{
{
ID: "123",
Name: "secret123",
Description: "secret 1,2,3",
},
}
out := &bytes.Buffer{}
printList(out, secrets)
golden.Assert(t, out.String(), "secrets-out.golden")
}

View file

@ -18,43 +18,96 @@ package cmd
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/cli/cmd/mobyflags"
"github.com/docker/compose-cli/cli/mobycli"
"github.com/docker/compose-cli/formatter"
)
const formatOpt = "format"
// VersionCommand command to display version
func VersionCommand(version string) *cobra.Command {
cmd := &cobra.Command{
Use: "version",
Short: "Show the Docker version information",
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, _ []string) error {
return runVersion(cmd, version)
Run: func(cmd *cobra.Command, _ []string) {
runVersion(cmd, version)
},
}
// define flags for backward compatibility with com.docker.cli
flags := cmd.Flags()
flags.StringP("format", "f", "", "Format the output using the given Go template")
flags.StringP(formatOpt, "f", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
flags.String("kubeconfig", "", "Kubernetes config file")
mobyflags.AddMobyFlagsForRetrocompatibility(flags)
return cmd
}
func runVersion(cmd *cobra.Command, version string) error {
func runVersion(cmd *cobra.Command, version string) {
var versionString string
format := strings.ToLower(strings.ReplaceAll(cmd.Flag(formatOpt).Value.String(), " ", ""))
displayedVersion := strings.TrimPrefix(version, "v")
versionResult, _ := mobycli.ExecSilent(cmd.Context())
// Replace is preferred in this case to keep the order.
switch format {
case formatter.PRETTY, "":
versionString = strings.Replace(getOutFromMoby(cmd, fixedPrettyArgs(os.Args[1:])...),
"\n Version:", "\n Cloud integration: "+displayedVersion+"\n Version:", 1)
case formatter.JSON, "{{json.}}": // Try to catch full JSON formats
versionString = strings.Replace(getOutFromMoby(cmd, fixedJSONArgs(os.Args[1:])...),
`"Version":`, fmt.Sprintf(`"CloudIntegration":%q,"Version":`, displayedVersion), 1)
default:
versionString = getOutFromMoby(cmd)
}
fmt.Print(versionString)
}
func getOutFromMoby(cmd *cobra.Command, args ...string) string {
versionResult, _ := mobycli.ExecSilent(cmd.Context(), args...)
// we don't want to fail on error, there is an error if the engine is not available but it displays client version info
// Still, technically the [] byte versionResult could be nil, just let the original command display what it has to display
if versionResult == nil {
mobycli.Exec(cmd.Root())
return nil
return ""
}
var s string = string(versionResult)
fmt.Print(strings.Replace(s, "\n Version:", "\n Cloud integration "+displayedVersion+"\n Version:", 1))
return nil
return string(versionResult)
}
func fixedPrettyArgs(oArgs []string) []string {
args := make([]string, 0)
for i := 0; i < len(oArgs); i++ {
if isFormatOpt(oArgs[i]) &&
len(oArgs) > i &&
(strings.ToLower(oArgs[i+1]) == formatter.PRETTY || oArgs[i+1] == "") {
i++
continue
}
args = append(args, oArgs[i])
}
return args
}
func fixedJSONArgs(oArgs []string) []string {
args := make([]string, 0)
for i := 0; i < len(oArgs); i++ {
if isFormatOpt(oArgs[i]) &&
len(oArgs) > i &&
strings.ToLower(oArgs[i+1]) == formatter.JSON {
args = append(args, oArgs[i], "{{json .}}")
i++
continue
}
args = append(args, oArgs[i])
}
return args
}
func isFormatOpt(o string) bool {
return o == "--format" || o == "-f"
}

190
cli/cmd/version_test.go Normal file
View file

@ -0,0 +1,190 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"testing"
"gotest.tools/assert"
)
type caze struct {
Actual []string
Expected []string
}
func TestVersionFormat(t *testing.T) {
jsonCases := []caze{
{
Actual: fixedJSONArgs([]string{}),
Expected: []string{},
},
{
Actual: fixedJSONArgs([]string{
"docker",
"version",
}),
Expected: []string{
"docker",
"version",
},
},
{
Actual: fixedJSONArgs([]string{
"docker",
"version",
"--format",
"json",
}),
Expected: []string{
"docker",
"version",
"--format",
"{{json .}}",
},
},
{
Actual: fixedJSONArgs([]string{
"docker",
"version",
"--format",
"jSoN",
}),
Expected: []string{
"docker",
"version",
"--format",
"{{json .}}",
},
},
{
Actual: fixedJSONArgs([]string{
"docker",
"version",
"--format",
"json",
"--kubeconfig",
"myKubeConfig",
}),
Expected: []string{
"docker",
"version",
"--format",
"{{json .}}",
"--kubeconfig",
"myKubeConfig",
},
},
{
Actual: fixedJSONArgs([]string{
"--format",
"json",
}),
Expected: []string{
"--format",
"{{json .}}",
},
},
}
prettyCases := []caze{
{
Actual: fixedPrettyArgs([]string{}),
Expected: []string{},
},
{
Actual: fixedPrettyArgs([]string{
"docker",
"version",
}),
Expected: []string{
"docker",
"version",
},
},
{
Actual: fixedPrettyArgs([]string{
"docker",
"version",
"--format",
"pretty",
}),
Expected: []string{
"docker",
"version",
},
},
{
Actual: fixedPrettyArgs([]string{
"docker",
"version",
"--format",
"pRettY",
}),
Expected: []string{
"docker",
"version",
},
},
{
Actual: fixedPrettyArgs([]string{
"docker",
"version",
"--format",
"",
}),
Expected: []string{
"docker",
"version",
},
},
{
Actual: fixedPrettyArgs([]string{
"docker",
"version",
"--format",
"pretty",
"--kubeconfig",
"myKubeConfig",
}),
Expected: []string{
"docker",
"version",
"--kubeconfig",
"myKubeConfig",
},
},
{
Actual: fixedPrettyArgs([]string{
"--format",
"pretty",
}),
Expected: []string{},
},
}
t.Run("json", func(t *testing.T) {
for _, c := range jsonCases {
assert.DeepEqual(t, c.Actual, c.Expected)
}
})
t.Run("pretty", func(t *testing.T) {
for _, c := range prettyCases {
assert.DeepEqual(t, c.Actual, c.Expected)
}
})
}

View file

@ -20,16 +20,20 @@ import (
"fmt"
"io"
"os"
"strings"
"text/tabwriter"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/volumes"
"github.com/docker/compose-cli/formatter"
)
type listVolumeOpts struct {
format string
}
func listVolume() *cobra.Command {
var opts listVolumeOpts
cmd := &cobra.Command{
Use: "ls",
Short: "list available volumes in context.",
@ -43,24 +47,30 @@ func listVolume() *cobra.Command {
if err != nil {
return err
}
printList(os.Stdout, vols)
return nil
view := viewFromVolumeList(vols)
return formatter.Print(view, opts.format, os.Stdout, func(w io.Writer) {
for _, vol := range view {
_, _ = fmt.Fprintf(w, "%s\t%s\n", vol.ID, vol.Description)
}
}, "ID", "DESCRIPTION")
},
}
cmd.Flags().StringVar(&opts.format, "format", formatter.PRETTY, "Format the output. Values: [pretty | json]. (Default: pretty)")
return cmd
}
func printList(out io.Writer, volumes []volumes.Volume) {
printSection(out, func(w io.Writer) {
for _, vol := range volumes {
_, _ = fmt.Fprintf(w, "%s\t%s\n", vol.ID, vol.Description)
}
}, "ID", "DESCRIPTION")
type volumeView struct {
ID string
Description string
}
func printSection(out io.Writer, printer func(io.Writer), headers ...string) {
w := tabwriter.NewWriter(out, 20, 1, 3, ' ', 0)
_, _ = fmt.Fprintln(w, strings.Join(headers, "\t"))
printer(w)
_ = w.Flush()
func viewFromVolumeList(volumeList []volumes.Volume) []volumeView {
retList := make([]volumeView, len(volumeList))
for i, v := range volumeList {
retList[i] = volumeView{
ID: v.ID,
Description: v.Description,
}
}
return retList
}

View file

@ -1,38 +0,0 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package volume
import (
"bytes"
"testing"
"gotest.tools/v3/golden"
"github.com/docker/compose-cli/api/volumes"
)
func TestPrintList(t *testing.T) {
secrets := []volumes.Volume{
{
ID: "volume/123",
Description: "volume 123",
},
}
out := &bytes.Buffer{}
printList(out, secrets)
golden.Assert(t, out.String(), "volumes-out.golden")
}

View file

@ -1,2 +0,0 @@
ID DESCRIPTION
volume/123 volume 123

View file

@ -112,7 +112,10 @@ func IsDefaultContextCommand(dockerCommand string) bool {
}
// ExecSilent executes a command and do redirect output to stdOut, return output
func ExecSilent(ctx context.Context) ([]byte, error) {
cmd := exec.CommandContext(ctx, ComDockerCli, os.Args[1:]...)
func ExecSilent(ctx context.Context, args ...string) ([]byte, error) {
if len(args) == 0 {
args = os.Args[1:]
}
cmd := exec.CommandContext(ctx, ComDockerCli, args...)
return cmd.CombinedOutput()
}