diff --git a/context/context.go b/context/context.go index dc6407a67..7030a557f 100644 --- a/context/context.go +++ b/context/context.go @@ -11,9 +11,9 @@ import ( "github.com/cli/cli/v2/pkg/iostreams" ) -// cap the number of git remotes looked up, since the user might have an -// unusually large number of git remotes -const maxRemotesForLookup = 5 +// Cap the number of git remotes to look up, since the user might have an +// unusually large number of git remotes. +const defaultRemotesForLookup = 5 func ResolveRemotesToRepos(remotes Remotes, client *api.Client, base string) (*ResolvedRemotes, error) { sort.Stable(remotes) @@ -36,11 +36,11 @@ func ResolveRemotesToRepos(remotes Remotes, client *api.Client, base string) (*R return result, nil } -func resolveNetwork(result *ResolvedRemotes) error { +func resolveNetwork(result *ResolvedRemotes, remotesForLookup int) error { var repos []ghrepo.Interface for _, r := range result.remotes { repos = append(repos, r) - if len(repos) == maxRemotesForLookup { + if len(repos) == remotesForLookup { break } } @@ -84,7 +84,7 @@ func (r *ResolvedRemotes) BaseRepo(io *iostreams.IOStreams) (ghrepo.Interface, e return r.remotes[0], nil } - repos, err := r.NetworkRepos() + repos, err := r.NetworkRepos(defaultRemotesForLookup) if err != nil { return nil, err } @@ -109,7 +109,7 @@ func (r *ResolvedRemotes) BaseRepo(io *iostreams.IOStreams) (ghrepo.Interface, e func (r *ResolvedRemotes) HeadRepos() ([]*api.Repository, error) { if r.network == nil { - err := resolveNetwork(r) + err := resolveNetwork(r, defaultRemotesForLookup) if err != nil { return nil, err } @@ -124,9 +124,11 @@ func (r *ResolvedRemotes) HeadRepos() ([]*api.Repository, error) { return results, nil } -func (r *ResolvedRemotes) NetworkRepos() ([]*api.Repository, error) { +// NetworkRepos fetches info about remotes for the network of repos. +// Pass a value of 0 to fetch info on all remotes. +func (r *ResolvedRemotes) NetworkRepos(remotesForLookup int) ([]*api.Repository, error) { if r.network == nil { - err := resolveNetwork(r) + err := resolveNetwork(r, remotesForLookup) if err != nil { return nil, err } diff --git a/pkg/cmd/repo/setdefault/setdefault.go b/pkg/cmd/repo/setdefault/setdefault.go index 98ad3498d..2cf8b19b9 100644 --- a/pkg/cmd/repo/setdefault/setdefault.go +++ b/pkg/cmd/repo/setdefault/setdefault.go @@ -160,7 +160,7 @@ func setDefaultRun(opts *SetDefaultOptions) error { return err } - knownRepos, err := resolvedRemotes.NetworkRepos() + knownRepos, err := resolvedRemotes.NetworkRepos(0) if err != nil { return err } diff --git a/pkg/cmd/repo/setdefault/setdefault_test.go b/pkg/cmd/repo/setdefault/setdefault_test.go index 26b6dff5f..a1c1f44ac 100644 --- a/pkg/cmd/repo/setdefault/setdefault_test.go +++ b/pkg/cmd/repo/setdefault/setdefault_test.go @@ -122,6 +122,9 @@ func TestDefaultRun(t *testing.T) { repo1, _ := ghrepo.FromFullName("OWNER/REPO") repo2, _ := ghrepo.FromFullName("OWNER2/REPO2") repo3, _ := ghrepo.FromFullName("OWNER3/REPO3") + repo4, _ := ghrepo.FromFullName("OWNER4/REPO4") + repo5, _ := ghrepo.FromFullName("OWNER5/REPO5") + repo6, _ := ghrepo.FromFullName("OWNER6/REPO6") tests := []struct { name string @@ -392,6 +395,55 @@ func TestDefaultRun(t *testing.T) { }, wantStdout: "Found only one known remote repo, OWNER2/REPO2 on github.com.\n✓ Set OWNER2/REPO2 as the default repository for the current directory\n", }, + { + name: "interactive mode more than five remotes", + tty: true, + opts: SetDefaultOptions{}, + remotes: []*context.Remote{ + {Remote: &git.Remote{Name: "origin"}, Repo: repo1}, + {Remote: &git.Remote{Name: "upstream"}, Repo: repo2}, + {Remote: &git.Remote{Name: "other1"}, Repo: repo3}, + {Remote: &git.Remote{Name: "other2"}, Repo: repo4}, + {Remote: &git.Remote{Name: "other3"}, Repo: repo5}, + {Remote: &git.Remote{Name: "other4"}, Repo: repo6}, + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.GraphQL(`query RepositoryNetwork\b`), + httpmock.GraphQLQuery(`{"data":{ + "repo_000":{"name":"REPO","owner":{"login":"OWNER"}}, + "repo_001":{"name":"REPO2","owner":{"login":"OWNER2"}}, + "repo_002":{"name":"REPO3","owner":{"login":"OWNER3"}}, + "repo_003":{"name":"REPO4","owner":{"login":"OWNER4"}}, + "repo_004":{"name":"REPO5","owner":{"login":"OWNER5"}}, + "repo_005":{"name":"REPO6","owner":{"login":"OWNER6"}} + }}`, + func(query string, inputs map[string]interface{}) { + assert.Contains(t, query, "repo_000") + assert.Contains(t, query, "repo_001") + assert.Contains(t, query, "repo_002") + assert.Contains(t, query, "repo_003") + assert.Contains(t, query, "repo_004") + assert.Contains(t, query, "repo_005") + }), + ) + }, + gitStubs: func(cs *run.CommandStubber) { + cs.Register(`git config --add remote.upstream.gh-resolved base`, 0, "") + }, + prompterStubs: func(pm *prompter.PrompterMock) { + pm.SelectFunc = func(p, d string, opts []string) (int, error) { + switch p { + case "Which repository should be the default?": + prompter.AssertOptions(t, []string{"OWNER/REPO", "OWNER2/REPO2", "OWNER3/REPO3", "OWNER4/REPO4", "OWNER5/REPO5", "OWNER6/REPO6"}, opts) + return prompter.IndexFor(opts, "OWNER2/REPO2") + default: + return -1, prompter.NoSuchPromptErr(p) + } + } + }, + wantStdout: "This command sets the default remote repository to use when querying the\nGitHub API for the locally cloned repository.\n\ngh uses the default repository for things like:\n\n - viewing and creating pull requests\n - viewing and creating issues\n - viewing and creating releases\n - working with Actions\n - adding repository and environment secrets\n\n✓ Set OWNER2/REPO2 as the default repository for the current directory\n", + }, } for _, tt := range tests {