github.com/abdfnx/gh-api@v0.0.0-20210414084727-f5432eec23b8/pkg/cmd/factory/remote_resolver.go (about)

     1  package factory
     2  
     3  import (
     4  	"errors"
     5  	"net/url"
     6  	"sort"
     7  
     8  	"github.com/abdfnx/gh-api/context"
     9  	"github.com/abdfnx/gh-api/git"
    10  	"github.com/abdfnx/gh-api/internal/config"
    11  	"github.com/abdfnx/gh-api/internal/ghinstance"
    12  	"github.com/abdfnx/gh-api/pkg/set"
    13  )
    14  
    15  const GH_HOST = "GH_HOST"
    16  
    17  type remoteResolver struct {
    18  	readRemotes   func() (git.RemoteSet, error)
    19  	getConfig     func() (config.Config, error)
    20  	urlTranslator func(*url.URL) *url.URL
    21  }
    22  
    23  func (rr *remoteResolver) Resolver() func() (context.Remotes, error) {
    24  	var cachedRemotes context.Remotes
    25  	var remotesError error
    26  
    27  	return func() (context.Remotes, error) {
    28  		if cachedRemotes != nil || remotesError != nil {
    29  			return cachedRemotes, remotesError
    30  		}
    31  
    32  		gitRemotes, err := rr.readRemotes()
    33  		if err != nil {
    34  			remotesError = err
    35  			return nil, err
    36  		}
    37  		if len(gitRemotes) == 0 {
    38  			remotesError = errors.New("no git remotes found")
    39  			return nil, remotesError
    40  		}
    41  
    42  		sshTranslate := rr.urlTranslator
    43  		if sshTranslate == nil {
    44  			sshTranslate = git.ParseSSHConfig().Translator()
    45  		}
    46  		resolvedRemotes := context.TranslateRemotes(gitRemotes, sshTranslate)
    47  
    48  		cfg, err := rr.getConfig()
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  
    53  		authedHosts, err := cfg.Hosts()
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  		defaultHost, src, err := cfg.DefaultHostWithSource()
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		// Use set to dedupe list of hosts
    62  		hostsSet := set.NewStringSet()
    63  		hostsSet.AddValues(authedHosts)
    64  		hostsSet.AddValues([]string{defaultHost, ghinstance.Default()})
    65  		hosts := hostsSet.ToSlice()
    66  
    67  		// Sort remotes
    68  		sort.Sort(resolvedRemotes)
    69  
    70  		// Filter remotes by hosts
    71  		cachedRemotes := resolvedRemotes.FilterByHosts(hosts)
    72  
    73  		// Filter again by default host if one is set
    74  		// For config file default host fallback to cachedRemotes if none match
    75  		// For enviornment default host (GH_HOST) do not fallback to cachedRemotes if none match
    76  		if src != "" {
    77  			filteredRemotes := cachedRemotes.FilterByHosts([]string{defaultHost})
    78  			if src == GH_HOST || len(filteredRemotes) > 0 {
    79  				cachedRemotes = filteredRemotes
    80  			}
    81  		}
    82  
    83  		if len(cachedRemotes) == 0 {
    84  			if src == GH_HOST {
    85  				remotesError = errors.New("none of the git remotes configured for this repository correspond to the GH_HOST environment variable. Try adding a matching remote or unsetting the variable.")
    86  			} else {
    87  				remotesError = 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`")
    88  			}
    89  			return nil, remotesError
    90  		}
    91  
    92  		return cachedRemotes, nil
    93  	}
    94  }