github.com/ungtb10d/cli/v2@v2.0.0-20221110210412-98537dd9d6a1/pkg/cmd/factory/remote_resolver.go (about) 1 package factory 2 3 import ( 4 "errors" 5 "fmt" 6 "sort" 7 8 "github.com/ungtb10d/cli/v2/context" 9 "github.com/ungtb10d/cli/v2/git" 10 "github.com/ungtb10d/cli/v2/internal/config" 11 "github.com/ungtb10d/cli/v2/internal/ghinstance" 12 "github.com/ungtb10d/cli/v2/pkg/set" 13 "github.com/cli/go-gh/pkg/ssh" 14 ) 15 16 const ( 17 GH_HOST = "GH_HOST" 18 ) 19 20 type remoteResolver struct { 21 readRemotes func() (git.RemoteSet, error) 22 getConfig func() (config.Config, error) 23 urlTranslator context.Translator 24 } 25 26 func (rr *remoteResolver) Resolver() func() (context.Remotes, error) { 27 var cachedRemotes context.Remotes 28 var remotesError error 29 30 return func() (context.Remotes, error) { 31 if cachedRemotes != nil || remotesError != nil { 32 return cachedRemotes, remotesError 33 } 34 35 gitRemotes, err := rr.readRemotes() 36 if err != nil { 37 remotesError = err 38 return nil, err 39 } 40 if len(gitRemotes) == 0 { 41 remotesError = errors.New("no git remotes found") 42 return nil, remotesError 43 } 44 45 sshTranslate := rr.urlTranslator 46 if sshTranslate == nil { 47 sshTranslate = ssh.NewTranslator() 48 } 49 resolvedRemotes := context.TranslateRemotes(gitRemotes, sshTranslate) 50 51 cfg, err := rr.getConfig() 52 if err != nil { 53 return nil, err 54 } 55 56 authedHosts := cfg.Hosts() 57 if len(authedHosts) == 0 { 58 return nil, errors.New("could not find any host configurations") 59 } 60 defaultHost, src := cfg.DefaultHost() 61 62 // Use set to dedupe list of hosts 63 hostsSet := set.NewStringSet() 64 hostsSet.AddValues(authedHosts) 65 hostsSet.AddValues([]string{defaultHost, ghinstance.Default()}) 66 hosts := hostsSet.ToSlice() 67 68 // Sort remotes 69 sort.Sort(resolvedRemotes) 70 71 // Filter remotes by hosts 72 cachedRemotes := resolvedRemotes.FilterByHosts(hosts) 73 74 // Filter again by default host if one is set 75 // For config file default host fallback to cachedRemotes if none match 76 // For environment default host (GH_HOST) do not fallback to cachedRemotes if none match 77 if src != "default" { 78 filteredRemotes := cachedRemotes.FilterByHosts([]string{defaultHost}) 79 if isHostEnv(src) || len(filteredRemotes) > 0 { 80 cachedRemotes = filteredRemotes 81 } 82 } 83 84 if len(cachedRemotes) == 0 { 85 // Any non-github.com hostname is fine here 86 dummyHostname := "example.com" 87 if isHostEnv(src) { 88 return nil, fmt.Errorf("none of the git remotes configured for this repository correspond to the %s environment variable. Try adding a matching remote or unsetting the variable.", src) 89 } else if v, _ := cfg.AuthToken(dummyHostname); v != "" { 90 return nil, errors.New("set the GH_HOST environment variable to specify which GitHub host to use") 91 } 92 return nil, errors.New("none of the git remotes configured for this repository point to a known GitHub host. To tell gh about a new GitHub host, please use `gh auth login`") 93 } 94 95 return cachedRemotes, nil 96 } 97 } 98 99 func isHostEnv(src string) bool { 100 return src == GH_HOST 101 }