diff --git a/git/remote.go b/git/remote.go index 676027b3b..df3a37201 100644 --- a/git/remote.go +++ b/git/remote.go @@ -168,7 +168,7 @@ func SetRemoteResolution(name, resolution string) error { return run.PrepareCmd(addCmd).Run() } -func RemoveRemoteResolution(name string) error { +func UnsetRemoteResolution(name string) error { addCmd, err := GitCommand("config", "--unset-all", fmt.Sprintf("remote.%s.gh-resolved", name)) if err != nil { return err diff --git a/pkg/cmd/config/config.go b/pkg/cmd/config/config.go index 03b8700ee..2168516d3 100644 --- a/pkg/cmd/config/config.go +++ b/pkg/cmd/config/config.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/cli/cli/v2/internal/config" - cmdBase "github.com/cli/cli/v2/pkg/cmd/config/base" 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" @@ -33,7 +32,6 @@ func NewCmdConfig(f *cmdutil.Factory) *cobra.Command { cmdutil.DisableAuthCheck(cmd) - cmd.AddCommand(cmdBase.NewCmdConfigBase(f, nil)) cmd.AddCommand(cmdGet.NewCmdConfigGet(f, nil)) cmd.AddCommand(cmdSet.NewCmdConfigSet(f, nil)) cmd.AddCommand(cmdList.NewCmdConfigList(f, nil)) diff --git a/pkg/cmd/config/base/base.go b/pkg/cmd/repo/default/default.go similarity index 60% rename from pkg/cmd/config/base/base.go rename to pkg/cmd/repo/default/default.go index c0e9e8b46..0481c39eb 100644 --- a/pkg/cmd/config/base/base.go +++ b/pkg/cmd/repo/default/default.go @@ -1,117 +1,129 @@ -package base - -import ( - "fmt" - "net/http" - - "github.com/MakeNowJust/heredoc" - "github.com/cli/cli/v2/api" - "github.com/cli/cli/v2/context" - "github.com/cli/cli/v2/git" - "github.com/cli/cli/v2/internal/ghrepo" - "github.com/cli/cli/v2/pkg/cmdutil" - "github.com/cli/cli/v2/pkg/iostreams" - "github.com/spf13/cobra" -) - -type BaseOptions struct { - IO *iostreams.IOStreams - Remotes func() (context.Remotes, error) - BaseRepo func() (ghrepo.Interface, error) - HttpClient func() (*http.Client, error) - - RemoteName string - ViewFlag bool -} - -func NewCmdConfigBase(f *cmdutil.Factory, runF func(*BaseOptions) error) *cobra.Command { - opts := &BaseOptions{ - IO: f.IOStreams, - HttpClient: f.HttpClient, - BaseRepo: f.BaseRepo, - Remotes: f.Remotes, - } - - cmd := &cobra.Command{ - Use: "base ", - Short: "Configure the base repository used for various commands", - Long: heredoc.Doc(` - The base repository is used to determine which repository gh - should automatically query for the commands: - issue, pr, browse, run, repo rename, secret, workflow - `), - Example: heredoc.Doc(` - $ gh base upstream - `), - Args: cobra.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) > 0 { - opts.RemoteName = args[0] - } - if err := cmdutil.MutuallyExclusive( - "args cannot be passed in with --view", - opts.RemoteName != "", - opts.ViewFlag, - ); err != nil { - return err - } - - if runF != nil { - return runF(opts) - } - return baseRun(opts) - }, - } - - cmd.Flags().BoolVarP(&opts.ViewFlag, "view", "v", false, "View the current configured default repository") - return cmd -} - -func baseRun(opts *BaseOptions) error { - remotes, err := opts.Remotes() - if err != nil { - return err - } - - if opts.ViewFlag { - for _, remote := range remotes { - if remote.Resolved == "base" { - fmt.Println(remote.Remote.Name) - return nil - } - } - return fmt.Errorf("base repo has not been specified yet") - } - - if opts.RemoteName != "" { - for _, remote := range remotes { - if opts.RemoteName == remote.Remote.Name { - removeBaseRepo(remotes) - git.SetRemoteResolution(remote.Name, "base") - return nil - } - } - return fmt.Errorf("could not find local remote name %s", opts.RemoteName) - } - removeBaseRepo(remotes) - httpClient, err := opts.HttpClient() - if err != nil { - return err - } - apiClient := api.NewClientFromHTTP(httpClient) - repoContext, err := context.ResolveRemotesToRepos(remotes, apiClient, "") - if err != nil { - return err - } - _, err = repoContext.BaseRepo(opts.IO) - return err -} - -func removeBaseRepo(remotes context.Remotes) { - for _, remote := range remotes { - if remote.Resolved == "base" { - remote.Resolved = "" - git.RemoveRemoteResolution(remote.Remote.Name) - } - } -} +package base + +import ( + "fmt" + "net/http" + "strings" + + "github.com/MakeNowJust/heredoc" + "github.com/cli/cli/v2/api" + "github.com/cli/cli/v2/context" + "github.com/cli/cli/v2/git" + "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/pkg/cmdutil" + "github.com/cli/cli/v2/pkg/iostreams" + "github.com/spf13/cobra" +) + +type DefaultOptions struct { + IO *iostreams.IOStreams + Remotes func() (context.Remotes, error) + BaseRepo func() (ghrepo.Interface, error) + HttpClient func() (*http.Client, error) + + RemoteName string + ListFlag bool +} + +func NewCmdDefault(f *cmdutil.Factory, runF func(*DefaultOptions) error) *cobra.Command { + opts := &DefaultOptions{ + IO: f.IOStreams, + HttpClient: f.HttpClient, + BaseRepo: f.BaseRepo, + Remotes: f.Remotes, + } + + cmd := &cobra.Command{ + Use: "default ", + Short: "Configure the default repository used for various commands", + Long: heredoc.Doc(` + The default repository is used to determine which repository gh + should automatically query for the commands: + issue, pr, browse, run, repo rename, secret, workflow + `), + Example: heredoc.Doc(` + $ gh repo default upstream + `), + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) > 0 { + opts.RemoteName = args[0] + } + if !opts.IO.CanPrompt() && !opts.ListFlag && opts.RemoteName == "" { + return cmdutil.FlagErrorf("remote name is required when not running interactively, use `--list` to see available remotes") + } + if err := cmdutil.MutuallyExclusive( + "args cannot be passed in with --list", + opts.RemoteName != "", + opts.ListFlag, + ); err != nil { + return err + } + + if runF != nil { + return runF(opts) + } + return defaultRun(opts) + }, + } + + cmd.Flags().BoolVarP(&opts.ListFlag, "list", "l", false, "list the current and available repositories") + return cmd +} + +func defaultRun(opts *DefaultOptions) error { + remotes, err := opts.Remotes() + if err != nil { + return err + } + + if opts.ListFlag { + found := false + list := &strings.Builder{} + for _, remote := range remotes { + if remote.Resolved == "base" { + list.WriteString(fmt.Sprintf("* %s\n", remote.Remote.Name)) + found = true + } else { + list.WriteString(fmt.Sprintf(" %s\n", remote.Remote.Name)) + } + } + if !found { + fmt.Fprint(opts.IO.Out, "the default repo has not been set\n") + } + fmt.Fprint(opts.IO.Out, list.String()) + return nil + } + + if opts.RemoteName != "" { + for _, remote := range remotes { + if opts.RemoteName == remote.Remote.Name { + removeBaseRepo(remotes) + git.SetRemoteResolution(remote.Name, "base") + return nil + } + } + return fmt.Errorf("could not find local remote name %s", opts.RemoteName) + } + removeBaseRepo(remotes) + httpClient, err := opts.HttpClient() + if err != nil { + return err + } + apiClient := api.NewClientFromHTTP(httpClient) + repoContext, err := context.ResolveRemotesToRepos(remotes, apiClient, "") + if err != nil { + return err + } + _, err = repoContext.BaseRepo(opts.IO) + return err +} + +func removeBaseRepo(remotes context.Remotes) { + for _, remote := range remotes { + if remote.Resolved == "base" { + remote.Resolved = "" + git.UnsetRemoteResolution(remote.Remote.Name) + } + } +} diff --git a/pkg/cmd/config/base/base_test.go b/pkg/cmd/repo/default/default_test.go similarity index 92% rename from pkg/cmd/config/base/base_test.go rename to pkg/cmd/repo/default/default_test.go index 22f111144..66fa1b529 100644 --- a/pkg/cmd/config/base/base_test.go +++ b/pkg/cmd/repo/default/default_test.go @@ -1 +1 @@ -package base +package base diff --git a/pkg/cmd/repo/repo.go b/pkg/cmd/repo/repo.go index e8696d7d9..d3dce190d 100644 --- a/pkg/cmd/repo/repo.go +++ b/pkg/cmd/repo/repo.go @@ -6,6 +6,7 @@ import ( repoCloneCmd "github.com/cli/cli/v2/pkg/cmd/repo/clone" repoCreateCmd "github.com/cli/cli/v2/pkg/cmd/repo/create" creditsCmd "github.com/cli/cli/v2/pkg/cmd/repo/credits" + repoDefaultCmd "github.com/cli/cli/v2/pkg/cmd/repo/default" repoDeleteCmd "github.com/cli/cli/v2/pkg/cmd/repo/delete" deployKeyCmd "github.com/cli/cli/v2/pkg/cmd/repo/deploy-key" repoEditCmd "github.com/cli/cli/v2/pkg/cmd/repo/edit" @@ -52,6 +53,7 @@ func NewCmdRepo(f *cmdutil.Factory) *cobra.Command { cmd.AddCommand(repoRenameCmd.NewCmdRename(f, nil)) cmd.AddCommand(repoDeleteCmd.NewCmdDelete(f, nil)) cmd.AddCommand(repoArchiveCmd.NewCmdArchive(f, nil)) + cmd.AddCommand(repoDefaultCmd.NewCmdDefault(f, nil)) return cmd }