From 9bf1668b3f83997f6fdecf1410bf0f586c3c11f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Fri, 19 Feb 2021 15:37:11 +0100 Subject: [PATCH 1/9] Fix `auth git-credential` when the token comes from environment When a token such as GH_TOKEN is set through environment variables and `~/.config/gh/hosts.yml` is non-existent, the `auth git-credential get` command used to fail due to missing username. Since GitHub username isn't at all required for token authentication, use the `x-access-token` faux username instead of trying to obtain one from a config file. --- pkg/cmd/auth/gitcredential/helper.go | 16 ++++++++--- pkg/cmd/auth/gitcredential/helper_test.go | 34 +++++++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/auth/gitcredential/helper.go b/pkg/cmd/auth/gitcredential/helper.go index c62cef3a8..4f80afbe7 100644 --- a/pkg/cmd/auth/gitcredential/helper.go +++ b/pkg/cmd/auth/gitcredential/helper.go @@ -11,8 +11,10 @@ import ( "github.com/spf13/cobra" ) +const tokenUser = "x-access-token" + type config interface { - Get(string, string) (string, error) + GetWithSource(string, string) (string, string, error) } type CredentialOptions struct { @@ -98,13 +100,19 @@ func helperRun(opts *CredentialOptions) error { return err } - gotUser, _ := cfg.Get(wants["host"], "user") - gotToken, _ := cfg.Get(wants["host"], "oauth_token") + var gotUser string + gotToken, source, _ := cfg.GetWithSource(wants["host"], "oauth_token") + if strings.HasSuffix(source, "_TOKEN") { + gotUser = tokenUser + } else { + gotUser, _, _ = cfg.GetWithSource(wants["host"], "user") + } + if gotUser == "" || gotToken == "" { return cmdutil.SilentError } - if wants["username"] != "" && !strings.EqualFold(wants["username"], gotUser) { + if wants["username"] != "" && gotUser != tokenUser && !strings.EqualFold(wants["username"], gotUser) { return cmdutil.SilentError } diff --git a/pkg/cmd/auth/gitcredential/helper_test.go b/pkg/cmd/auth/gitcredential/helper_test.go index 336d4ef34..c8f449526 100644 --- a/pkg/cmd/auth/gitcredential/helper_test.go +++ b/pkg/cmd/auth/gitcredential/helper_test.go @@ -10,8 +10,8 @@ import ( type tinyConfig map[string]string -func (c tinyConfig) Get(host, key string) (string, error) { - return c[fmt.Sprintf("%s:%s", host, key)], nil +func (c tinyConfig) GetWithSource(host, key string) (string, string, error) { + return c[fmt.Sprintf("%s:%s", host, key)], c["_source"], nil } func Test_helperRun(t *testing.T) { @@ -29,6 +29,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -53,6 +54,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -78,6 +80,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -101,6 +104,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", }, nil }, @@ -119,6 +123,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -133,6 +138,31 @@ func Test_helperRun(t *testing.T) { wantStdout: "", wantStderr: "", }, + { + name: "token from env", + opts: CredentialOptions{ + Operation: "get", + Config: func() (config, error) { + return tinyConfig{ + "_source": "GITHUB_ENTERPRISE_TOKEN", + "example.com:oauth_token": "OTOKEN", + }, nil + }, + }, + input: heredoc.Doc(` + protocol=https + host=example.com + username=hubot + `), + wantErr: false, + wantStdout: heredoc.Doc(` + protocol=https + host=example.com + username=x-access-token + password=OTOKEN + `), + wantStderr: "", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From f807795491e90954e26873e39d2f90ec1f07bf33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 23 Feb 2021 10:19:11 +0100 Subject: [PATCH 2/9] Fix pasting Personal Access Token to `auth login` for GHE --- pkg/cmd/auth/shared/oauth_scopes.go | 2 +- pkg/cmd/auth/shared/oauth_scopes_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/auth/shared/oauth_scopes.go b/pkg/cmd/auth/shared/oauth_scopes.go index c99b5543d..20dbf9a83 100644 --- a/pkg/cmd/auth/shared/oauth_scopes.go +++ b/pkg/cmd/auth/shared/oauth_scopes.go @@ -40,7 +40,7 @@ func HasMinimumScopes(httpClient httpClient, hostname, authToken string) error { return err } - req.Header.Set("Autorization", "token "+authToken) + req.Header.Set("Authorization", "token "+authToken) res, err := httpClient.Do(req) if err != nil { diff --git a/pkg/cmd/auth/shared/oauth_scopes_test.go b/pkg/cmd/auth/shared/oauth_scopes_test.go index 3b9766a95..0f6bd9f32 100644 --- a/pkg/cmd/auth/shared/oauth_scopes_test.go +++ b/pkg/cmd/auth/shared/oauth_scopes_test.go @@ -52,7 +52,9 @@ func Test_HasMinimumScopes(t *testing.T) { fakehttp := &httpmock.Registry{} defer fakehttp.Verify(t) + var gotAuthorization string fakehttp.Register(httpmock.REST("GET", ""), func(req *http.Request) (*http.Response, error) { + gotAuthorization = req.Header.Get("authorization") return &http.Response{ Request: req, StatusCode: 200, @@ -70,6 +72,7 @@ func Test_HasMinimumScopes(t *testing.T) { } else { assert.NoError(t, err) } + assert.Equal(t, gotAuthorization, "token ATOKEN") }) } From cfddda8829cd205b88a1e854b6fca76d6acc34b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 23 Feb 2021 10:52:29 +0100 Subject: [PATCH 3/9] Indicate `workflow` scope is GHE 3.0+ only during `auth login` --- pkg/cmd/auth/shared/login_flow.go | 10 +++-- pkg/cmd/auth/shared/login_flow_test.go | 52 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/auth/shared/login_flow.go b/pkg/cmd/auth/shared/login_flow.go index fbff9882e..6f75a784f 100644 --- a/pkg/cmd/auth/shared/login_flow.go +++ b/pkg/cmd/auth/shared/login_flow.go @@ -9,6 +9,7 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/api" "github.com/cli/cli/internal/authflow" + "github.com/cli/cli/internal/ghinstance" "github.com/cli/cli/pkg/iostreams" "github.com/cli/cli/pkg/prompt" ) @@ -125,7 +126,7 @@ func Login(opts *LoginOptions) error { fmt.Fprint(opts.IO.ErrOut, heredoc.Docf(` Tip: you can generate a Personal Access Token here https://%s/settings/tokens The minimum required scopes are %s. - `, hostname, scopesSentence(minimumScopes))) + `, hostname, scopesSentence(minimumScopes, ghinstance.IsEnterprise(hostname)))) err := prompt.SurveyAskOne(&survey.Password{ Message: "Paste your authentication token:", @@ -193,11 +194,14 @@ func Login(opts *LoginOptions) error { return nil } -func scopesSentence(scopes []string) string { +func scopesSentence(scopes []string, isEnterprise bool) string { quoted := make([]string, len(scopes)) for i, s := range scopes { quoted[i] = fmt.Sprintf("'%s'", s) + if s == "workflow" && isEnterprise { + // remove when GHE 2.x reaches EOL + quoted[i] += " (GHE 3.0+)" + } } - // TODO: insert an "and" before the last element return strings.Join(quoted, ", ") } diff --git a/pkg/cmd/auth/shared/login_flow_test.go b/pkg/cmd/auth/shared/login_flow_test.go index c37d89b46..521616dfa 100644 --- a/pkg/cmd/auth/shared/login_flow_test.go +++ b/pkg/cmd/auth/shared/login_flow_test.go @@ -101,3 +101,55 @@ func TestLogin_ssh(t *testing.T) { assert.Equal(t, "ATOKEN", cfg["example.com:oauth_token"]) assert.Equal(t, "ssh", cfg["example.com:git_protocol"]) } + +func Test_scopesSentence(t *testing.T) { + type args struct { + scopes []string + isEnterprise bool + } + tests := []struct { + name string + args args + want string + }{ + { + name: "basic scopes", + args: args{ + scopes: []string{"repo", "read:org"}, + isEnterprise: false, + }, + want: "'repo', 'read:org'", + }, + { + name: "empty", + args: args{ + scopes: []string(nil), + isEnterprise: false, + }, + want: "", + }, + { + name: "workflow scope for dotcom", + args: args{ + scopes: []string{"repo", "workflow"}, + isEnterprise: false, + }, + want: "'repo', 'workflow'", + }, + { + name: "workflow scope for GHE", + args: args{ + scopes: []string{"repo", "workflow"}, + isEnterprise: true, + }, + want: "'repo', 'workflow' (GHE 3.0+)", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := scopesSentence(tt.args.scopes, tt.args.isEnterprise); got != tt.want { + t.Errorf("scopesSentence() = %q, want %q", got, tt.want) + } + }) + } +} From 27aea42d8a43951b880145fcbbd42b262ed6af08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 23 Feb 2021 12:10:56 +0100 Subject: [PATCH 4/9] Avoid upgrade notice for recent release if gh is under Homebrew prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, when gh detected there was a new release in the `cli/cli` repo, it would show this notice: A new release of gh is available: {V1} → {V2} Additionally, when the release was more than 24h old, we would show this to Homebrew users: To upgrade, run: brew update && brew upgrade gh Ref. feb4acc2c00ce42d5ed67252ae1ec66addeb786d This change makes it so that the original notice "A new release of gh is available" is NOT shown to Homebrew users unless the release is older than 24h. We effectively hide the fact that any release happened until we're sure that the version bump has made it to `homebrew-core`. --- cmd/gh/main.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/gh/main.go b/cmd/gh/main.go index a0eba09a5..e20452808 100644 --- a/cmd/gh/main.go +++ b/cmd/gh/main.go @@ -163,12 +163,19 @@ func main() { newRelease := <-updateMessageChan if newRelease != nil { - ghExe, _ := os.Executable() + isHomebrew := false + if ghExe, err := os.Executable(); err == nil { + isHomebrew = isUnderHomebrew(ghExe) + } + if isHomebrew && isRecentRelease(newRelease.PublishedAt) { + // do not notify Homebrew users before the version bump had a chance to get merged into homebrew-core + return + } fmt.Fprintf(stderr, "\n\n%s %s → %s\n", ansi.Color("A new release of gh is available:", "yellow"), ansi.Color(buildVersion, "cyan"), ansi.Color(newRelease.Version, "cyan")) - if suggestBrewUpgrade(newRelease, ghExe) { + if isHomebrew { fmt.Fprintf(stderr, "To upgrade, run: %s\n", "brew update && brew upgrade gh") } fmt.Fprintf(stderr, "%s\n\n", @@ -265,13 +272,12 @@ func apiVerboseLog() api.ClientOption { return api.VerboseLog(colorable.NewColorable(os.Stderr), logTraffic, colorize) } -// Suggest to `brew upgrade gh` only if gh was found under homebrew prefix and when the release was -// published over 24h ago, allowing homebrew-core ample time to merge the formula bump. -func suggestBrewUpgrade(rel *update.ReleaseInfo, ghBinary string) bool { - if rel.PublishedAt.IsZero() || time.Since(rel.PublishedAt) < time.Duration(time.Hour*24) { - return false - } +func isRecentRelease(publishedAt time.Time) bool { + return !publishedAt.IsZero() && time.Since(publishedAt) < time.Hour*24 +} +// Check whether the gh binary was found under the Homebrew prefix +func isUnderHomebrew(ghBinary string) bool { brewExe, err := safeexec.LookPath("brew") if err != nil { return false From cbf8a0d9641869de104ad1c94493e07addcd45c9 Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Tue, 23 Feb 2021 20:12:26 +0530 Subject: [PATCH 5/9] Accept only one argument when deleting a gist --- pkg/cmd/gist/delete/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/gist/delete/delete.go b/pkg/cmd/gist/delete/delete.go index 54f745030..add7e3335 100644 --- a/pkg/cmd/gist/delete/delete.go +++ b/pkg/cmd/gist/delete/delete.go @@ -29,7 +29,7 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete a gist", - Args: cmdutil.MinimumArgs(1, "cannot delete: gist argument required"), + Args: cobra.ExactArgs(1), RunE: func(c *cobra.Command, args []string) error { opts.Selector = args[0] if runF != nil { From 732e919a835882700262b0a448c1150faa24d1bf Mon Sep 17 00:00:00 2001 From: boonhong Date: Tue, 23 Feb 2021 22:51:10 +0800 Subject: [PATCH 6/9] Add `pr edit --base` to change the base branch of a PR --- pkg/cmd/pr/edit/edit.go | 8 ++++++++ pkg/cmd/pr/edit/edit_test.go | 22 ++++++++++++++++++++++ pkg/cmd/pr/shared/editable.go | 2 ++ 3 files changed, 32 insertions(+) diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index 6c1592b4c..3fc1c8f10 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -70,6 +70,9 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman if flags.Changed("body") { opts.Editable.Body.Edited = true } + if flags.Changed("base") { + opts.Editable.Base.Edited = true + } if flags.Changed("add-reviewer") || flags.Changed("remove-reviewer") { opts.Editable.Reviewers.Edited = true } @@ -104,6 +107,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman cmd.Flags().StringVarP(&opts.Editable.Title.Value, "title", "t", "", "Set the new title.") cmd.Flags().StringVarP(&opts.Editable.Body.Value, "body", "b", "", "Set the new body.") + cmd.Flags().StringVarP(&opts.Editable.Base.Value, "base", "B", "", "Change the base `branch` for this pull request") cmd.Flags().StringSliceVar(&opts.Editable.Reviewers.Add, "add-reviewer", nil, "Add reviewers by their `login`.") cmd.Flags().StringSliceVar(&opts.Editable.Reviewers.Remove, "remove-reviewer", nil, "Remove reviewers by their `login`.") cmd.Flags().StringSliceVar(&opts.Editable.Assignees.Add, "add-assignee", nil, "Add assigned users by their `login`. Use \"@me\" to assign yourself.") @@ -133,6 +137,7 @@ func editRun(opts *EditOptions) error { editable.Reviewers.Allowed = true editable.Title.Default = pr.Title editable.Body.Default = pr.Body + editable.Base.Default = pr.BaseRefName editable.Reviewers.Default = pr.ReviewRequests.Logins() editable.Assignees.Default = pr.Assignees.Logins() editable.Labels.Default = pr.Labels.Names() @@ -203,6 +208,9 @@ func updatePullRequest(client *api.Client, repo ghrepo.Interface, id string, edi return err } params.MilestoneID = ghId(milestoneId) + if editable.Base.Edited { + params.BaseRefName = ghString(&editable.Base.Value) + } err = api.UpdatePullRequest(client, repo, params) if err != nil { return err diff --git a/pkg/cmd/pr/edit/edit_test.go b/pkg/cmd/pr/edit/edit_test.go index 35d8278dc..da328ba5b 100644 --- a/pkg/cmd/pr/edit/edit_test.go +++ b/pkg/cmd/pr/edit/edit_test.go @@ -65,6 +65,20 @@ func TestNewCmdEdit(t *testing.T) { }, wantsErr: false, }, + { + name: "base flag", + input: "23 --base base-branch-name", + output: EditOptions{ + SelectorArg: "23", + Editable: shared.Editable{ + Base: shared.EditableString{ + Value: "base-branch-name", + Edited: true, + }, + }, + }, + wantsErr: false, + }, { name: "add-reviewer flag", input: "23 --add-reviewer monalisa,owner/core", @@ -254,6 +268,10 @@ func Test_editRun(t *testing.T) { Value: "new body", Edited: true, }, + Base: shared.EditableString{ + Value: "base-branch-name", + Edited: true, + }, Reviewers: shared.EditableSlice{ Add: []string{"OWNER/core", "OWNER/external", "monalisa", "hubot"}, Remove: []string{"dependabot"}, @@ -303,6 +321,10 @@ func Test_editRun(t *testing.T) { Value: "new body", Edited: true, }, + Base: shared.EditableString{ + Value: "base-branch-name", + Edited: true, + }, Assignees: shared.EditableSlice{ Add: []string{"monalisa", "hubot"}, Remove: []string{"octocat"}, diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index 16faca4de..abcfc9b43 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -14,6 +14,7 @@ import ( type Editable struct { Title EditableString Body EditableString + Base EditableString Reviewers EditableSlice Assignees EditableSlice Labels EditableSlice @@ -42,6 +43,7 @@ type EditableSlice struct { func (e Editable) Dirty() bool { return e.Title.Edited || e.Body.Edited || + e.Base.Edited || e.Reviewers.Edited || e.Assignees.Edited || e.Labels.Edited || From 56ead91702e61575622233713ccf247af4644bcb Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Wed, 24 Feb 2021 15:49:40 +0530 Subject: [PATCH 7/9] Add helper function to validate exact args in cmdutil --- pkg/cmd/gist/edit/edit.go | 2 +- pkg/cmd/gist/view/view.go | 2 +- pkg/cmd/pr/checkout/checkout.go | 2 +- pkg/cmdutil/args.go | 18 ++++++++++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index 7cba14800..a8fa4d683 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -49,7 +49,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman cmd := &cobra.Command{ Use: "edit { | }", Short: "Edit one of your gists", - Args: cmdutil.MinimumArgs(1, "cannot edit: gist argument required"), + Args: cmdutil.ExactArgs(1, "cannot edit: gist argument required"), RunE: func(c *cobra.Command, args []string) error { opts.Selector = args[0] diff --git a/pkg/cmd/gist/view/view.go b/pkg/cmd/gist/view/view.go index 70bb0a238..e1e9408cf 100644 --- a/pkg/cmd/gist/view/view.go +++ b/pkg/cmd/gist/view/view.go @@ -35,7 +35,7 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman cmd := &cobra.Command{ Use: "view { | }", Short: "View a gist", - Args: cmdutil.MinimumArgs(1, "cannot view: gist argument required"), + Args: cmdutil.ExactArgs(1, "cannot view: gist argument required"), RunE: func(cmd *cobra.Command, args []string) error { opts.Selector = args[0] diff --git a/pkg/cmd/pr/checkout/checkout.go b/pkg/cmd/pr/checkout/checkout.go index d2cd84304..f7f73bb28 100644 --- a/pkg/cmd/pr/checkout/checkout.go +++ b/pkg/cmd/pr/checkout/checkout.go @@ -46,7 +46,7 @@ func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobr cmd := &cobra.Command{ Use: "checkout { | | }", Short: "Check out a pull request in git", - Args: cmdutil.MinimumArgs(1, "argument required"), + Args: cmdutil.ExactArgs(1, "argument required"), RunE: func(cmd *cobra.Command, args []string) error { // support `-R, --repo` override opts.BaseRepo = f.BaseRepo diff --git a/pkg/cmdutil/args.go b/pkg/cmdutil/args.go index 65f3ade51..d58757c20 100644 --- a/pkg/cmdutil/args.go +++ b/pkg/cmdutil/args.go @@ -21,6 +21,24 @@ func MinimumArgs(n int, msg string) cobra.PositionalArgs { } } +func ExactArgs(n int, msg string) cobra.PositionalArgs { + if msg == "" { + return cobra.MinimumNArgs(1) + } + + return func(cmd *cobra.Command, args []string) error { + if len(args) > n { + return &FlagError{Err: errors.New("too many arguments")} + } + + if len(args) < n { + return &FlagError{Err: errors.New("not enough arguments")} + } + + return nil + } +} + func NoArgsQuoteReminder(cmd *cobra.Command, args []string) error { if len(args) < 1 { return nil From 61eb7eeeab3f346ff7a4c61a79d5b0341cc71cff Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Wed, 24 Feb 2021 15:53:07 +0530 Subject: [PATCH 8/9] Add msg in gist delete --- pkg/cmd/gist/delete/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cmd/gist/delete/delete.go b/pkg/cmd/gist/delete/delete.go index add7e3335..674c33ad6 100644 --- a/pkg/cmd/gist/delete/delete.go +++ b/pkg/cmd/gist/delete/delete.go @@ -29,7 +29,7 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete a gist", - Args: cobra.ExactArgs(1), + Args: cmdutil.ExactArgs(1, "cannot delete: gist argument required"), RunE: func(c *cobra.Command, args []string) error { opts.Selector = args[0] if runF != nil { From 66d4307bce0d0189c1cb4650b432852cde39f328 Mon Sep 17 00:00:00 2001 From: Gowtham Munukutla Date: Wed, 24 Feb 2021 18:05:11 +0530 Subject: [PATCH 9/9] return msg instead of too many arguments --- pkg/cmdutil/args.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/cmdutil/args.go b/pkg/cmdutil/args.go index d58757c20..ee9c5e350 100644 --- a/pkg/cmdutil/args.go +++ b/pkg/cmdutil/args.go @@ -22,9 +22,6 @@ func MinimumArgs(n int, msg string) cobra.PositionalArgs { } func ExactArgs(n int, msg string) cobra.PositionalArgs { - if msg == "" { - return cobra.MinimumNArgs(1) - } return func(cmd *cobra.Command, args []string) error { if len(args) > n { @@ -32,7 +29,7 @@ func ExactArgs(n int, msg string) cobra.PositionalArgs { } if len(args) < n { - return &FlagError{Err: errors.New("not enough arguments")} + return &FlagError{Err: errors.New(msg)} } return nil