Add --all flag to alias delete command (#7900)
This commit is contained in:
parent
bcbf842706
commit
925473eeb1
2 changed files with 182 additions and 60 deletions
|
|
@ -2,6 +2,7 @@ package delete
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
|
|
@ -14,6 +15,7 @@ type DeleteOptions struct {
|
|||
IO *iostreams.IOStreams
|
||||
|
||||
Name string
|
||||
All bool
|
||||
}
|
||||
|
||||
func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command {
|
||||
|
|
@ -23,12 +25,19 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
|
|||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete <alias>",
|
||||
Short: "Delete an alias",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "delete {<alias> | --all}",
|
||||
Short: "Delete set aliases",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.Name = args[0]
|
||||
|
||||
if len(args) == 0 && !opts.All {
|
||||
return cmdutil.FlagErrorf("specify an alias to delete or `--all`")
|
||||
}
|
||||
if len(args) > 0 && opts.All {
|
||||
return cmdutil.FlagErrorf("cannot use `--all` with alias name")
|
||||
}
|
||||
if len(args) > 0 {
|
||||
opts.Name = args[0]
|
||||
}
|
||||
if runF != nil {
|
||||
return runF(opts)
|
||||
}
|
||||
|
|
@ -36,6 +45,8 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&opts.All, "all", false, "Delete all aliases")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
@ -47,25 +58,40 @@ func deleteRun(opts *DeleteOptions) error {
|
|||
|
||||
aliasCfg := cfg.Aliases()
|
||||
|
||||
expansion, err := aliasCfg.Get(opts.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no such alias %s", opts.Name)
|
||||
|
||||
aliases := make(map[string]string)
|
||||
if opts.All {
|
||||
aliases = aliasCfg.All()
|
||||
if len(aliases) == 0 {
|
||||
return cmdutil.NewNoResultsError("no aliases configured")
|
||||
}
|
||||
} else {
|
||||
expansion, err := aliasCfg.Get(opts.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("no such alias %s", opts.Name)
|
||||
}
|
||||
aliases[opts.Name] = expansion
|
||||
}
|
||||
|
||||
err = aliasCfg.Delete(opts.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete alias %s: %w", opts.Name, err)
|
||||
for name := range aliases {
|
||||
if err := aliasCfg.Delete(name); err != nil {
|
||||
return fmt.Errorf("failed to delete alias %s: %w", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = cfg.Write()
|
||||
if err != nil {
|
||||
if err := cfg.Write(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.IO.IsStdoutTTY() {
|
||||
cs := opts.IO.ColorScheme()
|
||||
fmt.Fprintf(opts.IO.ErrOut, "%s Deleted alias %s; was %s\n", cs.SuccessIconWithColor(cs.Red), opts.Name, expansion)
|
||||
keys := make([]string, 0, len(aliases))
|
||||
for k := range aliases {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
fmt.Fprintf(opts.IO.ErrOut, "%s Deleted alias %s; was %s\n", cs.SuccessIconWithColor(cs.Red), k, aliases[k])
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -11,78 +11,174 @@ import (
|
|||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAliasDelete(t *testing.T) {
|
||||
_ = config.StubWriteConfig(t)
|
||||
|
||||
func TestNewCmdDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
cli string
|
||||
isTTY bool
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
wantErr string
|
||||
name string
|
||||
input string
|
||||
output DeleteOptions
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "no aliases",
|
||||
config: "",
|
||||
cli: "co",
|
||||
isTTY: true,
|
||||
wantStdout: "",
|
||||
wantStderr: "",
|
||||
wantErr: "no such alias co",
|
||||
name: "no arguments",
|
||||
input: "",
|
||||
wantErr: true,
|
||||
errMsg: "specify an alias to delete or `--all`",
|
||||
},
|
||||
{
|
||||
name: "delete one",
|
||||
name: "specified alias",
|
||||
input: "co",
|
||||
output: DeleteOptions{
|
||||
Name: "co",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all flag",
|
||||
input: "--all",
|
||||
output: DeleteOptions{
|
||||
All: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "specified alias and all flag",
|
||||
input: "co --all",
|
||||
wantErr: true,
|
||||
errMsg: "cannot use `--all` with alias name",
|
||||
},
|
||||
{
|
||||
name: "too many arguments",
|
||||
input: "il co",
|
||||
wantErr: true,
|
||||
errMsg: "accepts at most 1 arg(s), received 2",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ios, _, _, _ := iostreams.Test()
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: ios,
|
||||
}
|
||||
argv, err := shlex.Split(tt.input)
|
||||
assert.NoError(t, err)
|
||||
var gotOpts *DeleteOptions
|
||||
cmd := NewCmdDelete(f, func(opts *DeleteOptions) error {
|
||||
gotOpts = opts
|
||||
return nil
|
||||
})
|
||||
cmd.SetArgs(argv)
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
_, err = cmd.ExecuteC()
|
||||
if tt.wantErr {
|
||||
assert.EqualError(t, err, tt.errMsg)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.output.Name, gotOpts.Name)
|
||||
assert.Equal(t, tt.output.All, gotOpts.All)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config string
|
||||
isTTY bool
|
||||
opts *DeleteOptions
|
||||
wantAliases map[string]string
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
wantErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "delete alias",
|
||||
config: heredoc.Doc(`
|
||||
aliases:
|
||||
il: issue list
|
||||
co: pr checkout
|
||||
`),
|
||||
cli: "co",
|
||||
isTTY: true,
|
||||
wantStdout: "",
|
||||
isTTY: true,
|
||||
opts: &DeleteOptions{
|
||||
Name: "co",
|
||||
All: false,
|
||||
},
|
||||
wantAliases: map[string]string{
|
||||
"il": "issue list",
|
||||
},
|
||||
wantStderr: "✓ Deleted alias co; was pr checkout\n",
|
||||
},
|
||||
{
|
||||
name: "delete all aliases",
|
||||
config: heredoc.Doc(`
|
||||
aliases:
|
||||
il: issue list
|
||||
co: pr checkout
|
||||
`),
|
||||
isTTY: true,
|
||||
opts: &DeleteOptions{
|
||||
All: true,
|
||||
},
|
||||
wantAliases: map[string]string{},
|
||||
wantStderr: "✓ Deleted alias co; was pr checkout\n✓ Deleted alias il; was issue list\n",
|
||||
},
|
||||
{
|
||||
name: "delete alias that does not exist",
|
||||
config: heredoc.Doc(`
|
||||
aliases:
|
||||
il: issue list
|
||||
co: pr checkout
|
||||
`),
|
||||
isTTY: true,
|
||||
opts: &DeleteOptions{
|
||||
Name: "unknown",
|
||||
},
|
||||
wantAliases: map[string]string{
|
||||
"il": "issue list",
|
||||
"co": "pr checkout",
|
||||
},
|
||||
wantErrMsg: "no such alias unknown",
|
||||
},
|
||||
{
|
||||
name: "delete all aliases when none exist",
|
||||
isTTY: true,
|
||||
opts: &DeleteOptions{
|
||||
All: true,
|
||||
},
|
||||
wantAliases: map[string]string{},
|
||||
wantErrMsg: "no aliases configured",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := config.NewFromString(tt.config)
|
||||
|
||||
ios, _, stdout, stderr := iostreams.Test()
|
||||
ios.SetStdoutTTY(tt.isTTY)
|
||||
ios.SetStdinTTY(tt.isTTY)
|
||||
ios.SetStdoutTTY(tt.isTTY)
|
||||
ios.SetStderrTTY(tt.isTTY)
|
||||
tt.opts.IO = ios
|
||||
|
||||
factory := &cmdutil.Factory{
|
||||
IOStreams: ios,
|
||||
Config: func() (config.Config, error) {
|
||||
return cfg, nil
|
||||
},
|
||||
cfg := config.NewFromString(tt.config)
|
||||
tt.opts.Config = func() (config.Config, error) {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
cmd := NewCmdDelete(factory, nil)
|
||||
|
||||
argv, err := shlex.Split(tt.cli)
|
||||
require.NoError(t, err)
|
||||
cmd.SetArgs(argv)
|
||||
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(io.Discard)
|
||||
cmd.SetErr(io.Discard)
|
||||
|
||||
_, err = cmd.ExecuteC()
|
||||
if tt.wantErr != "" {
|
||||
assert.EqualError(t, err, tt.wantErr)
|
||||
return
|
||||
err := deleteRun(tt.opts)
|
||||
if tt.wantErrMsg != "" {
|
||||
assert.EqualError(t, err, tt.wantErrMsg)
|
||||
writeCalls := cfg.WriteCalls()
|
||||
assert.Equal(t, 0, len(writeCalls))
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
writeCalls := cfg.WriteCalls()
|
||||
assert.Equal(t, 1, len(writeCalls))
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.wantStdout, stdout.String())
|
||||
assert.Equal(t, tt.wantStderr, stderr.String())
|
||||
assert.Equal(t, tt.wantAliases, cfg.Aliases().All())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue