diff --git a/pkg/cmd/config/config.go b/pkg/cmd/config/config.go index c011ddcf0..2168516d3 100644 --- a/pkg/cmd/config/config.go +++ b/pkg/cmd/config/config.go @@ -6,6 +6,7 @@ import ( "github.com/cli/cli/v2/internal/config" cmdGet "github.com/cli/cli/v2/pkg/cmd/config/get" + cmdList "github.com/cli/cli/v2/pkg/cmd/config/list" cmdSet "github.com/cli/cli/v2/pkg/cmd/config/set" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/spf13/cobra" @@ -33,6 +34,7 @@ func NewCmdConfig(f *cmdutil.Factory) *cobra.Command { cmd.AddCommand(cmdGet.NewCmdConfigGet(f, nil)) cmd.AddCommand(cmdSet.NewCmdConfigSet(f, nil)) + cmd.AddCommand(cmdList.NewCmdConfigList(f, nil)) return cmd } diff --git a/pkg/cmd/config/list/list.go b/pkg/cmd/config/list/list.go new file mode 100644 index 000000000..8b1157b1f --- /dev/null +++ b/pkg/cmd/config/list/list.go @@ -0,0 +1,70 @@ +package list + +import ( + "fmt" + + "github.com/cli/cli/v2/internal/config" + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/iostreams" + "github.com/spf13/cobra" +) + +type ListOptions struct { + IO *iostreams.IOStreams + Config func() (config.Config, error) + + Hostname string +} + +func NewCmdConfigList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command { + opts := &ListOptions{ + IO: f.IOStreams, + Config: f.Config, + } + + cmd := &cobra.Command{ + Use: "list", + Short: "Print a list of configuration keys and values", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + if runF != nil { + return runF(opts) + } + + return listRun(opts) + }, + } + + cmd.Flags().StringVarP(&opts.Hostname, "host", "h", "", "Get per-host configuration") + + return cmd +} + +func listRun(opts *ListOptions) error { + cfg, err := opts.Config() + if err != nil { + return err + } + + var host string + if opts.Hostname != "" { + host = opts.Hostname + } else { + host, err = cfg.DefaultHost() + if err != nil { + return err + } + } + + configOptions := config.ConfigOptions() + + for _, key := range configOptions { + val, err := cfg.Get(host, key.Key) + if err != nil { + return err + } + fmt.Fprintf(opts.IO.Out, "%s=%s\n", key.Key, val) + } + + return nil +} diff --git a/pkg/cmd/config/list/list_test.go b/pkg/cmd/config/list/list_test.go new file mode 100644 index 000000000..14f9aba4b --- /dev/null +++ b/pkg/cmd/config/list/list_test.go @@ -0,0 +1,113 @@ +package list + +import ( + "bytes" + "testing" + + "github.com/cli/cli/v2/internal/config" + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/iostreams" + "github.com/google/shlex" + "github.com/stretchr/testify/assert" +) + +func TestNewCmdConfigList(t *testing.T) { + tests := []struct { + name string + input string + output ListOptions + wantsErr bool + }{ + { + name: "no arguments", + input: "", + output: ListOptions{}, + wantsErr: false, + }, + { + name: "list with host", + input: "--host HOST.com", + output: ListOptions{Hostname: "HOST.com"}, + wantsErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := &cmdutil.Factory{ + Config: func() (config.Config, error) { + return config.ConfigStub{}, nil + }, + } + + argv, err := shlex.Split(tt.input) + assert.NoError(t, err) + + var gotOpts *ListOptions + cmd := NewCmdConfigList(f, func(opts *ListOptions) error { + gotOpts = opts + return nil + }) + cmd.Flags().BoolP("help", "x", false, "") + + cmd.SetArgs(argv) + cmd.SetIn(&bytes.Buffer{}) + cmd.SetOut(&bytes.Buffer{}) + cmd.SetErr(&bytes.Buffer{}) + + _, err = cmd.ExecuteC() + if tt.wantsErr { + assert.Error(t, err) + return + } + + assert.NoError(t, err) + assert.Equal(t, tt.output.Hostname, gotOpts.Hostname) + }) + } +} + +func Test_listRun(t *testing.T) { + tests := []struct { + name string + input *ListOptions + config config.ConfigStub + stdout string + wantErr bool + }{ + { + name: "list", + config: config.ConfigStub{ + "HOST:git_protocol": "ssh", + "HOST:editor": "/usr/bin/vim", + "HOST:prompt": "disabled", + "HOST:pager": "less", + "HOST:http_unix_socket": "", + "HOST:browser": "brave", + }, + input: &ListOptions{Hostname: "HOST"}, // ConfigStub gives empty DefaultHost + stdout: `git_protocol=ssh +editor=/usr/bin/vim +prompt=disabled +pager=less +http_unix_socket= +browser=brave +`, + }, + } + + for _, tt := range tests { + io, _, stdout, _ := iostreams.Test() + tt.input.IO = io + tt.input.Config = func() (config.Config, error) { + return tt.config, nil + } + + t.Run(tt.name, func(t *testing.T) { + err := listRun(tt.input) + assert.NoError(t, err) + assert.Equal(t, tt.stdout, stdout.String()) + //assert.Equal(t, tt.stderr, stderr.String()) + }) + } +}