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  }