Add --all flag to alias delete command (#7900)

This commit is contained in:
Jun Nishimura 2023-09-07 19:56:44 +09:00 committed by GitHub
parent bcbf842706
commit 925473eeb1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 182 additions and 60 deletions

View file

@ -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

View file

@ -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())
})
}
}